With this segment we will see parts of "theSystem's" land environment take shape, we are also laying the 2nd half of the
foundation for logging and debugging. We will be looking at one table metadata.debuglogging, and one stored
procedure land.landBuilder. We will also take a detail look into the system data that populates tables we covered
in the last segment; land.landType, land.mapType, land.landTypeExistanceMod.
We have two new objects: one a table in the metadata schema called "debuglogging". The second is a stored procedure in the land schema called "landBuilder". The table debuglogging is the partner table to the metadata.debug table introduced in the
last article. This table gives "theSystem" processes a place to log information for debugging purposes. If debug is turned on for a particular procedure call or for a schema this table will begin to fill up with what will hopefully be useful information for debugging errors.
This table contains 4 columns:
- object_name which represents the object that is doing the logging
- Event_date will store the date for this particular log record.
- user_name which is system user name that is running the process being logged
- the debug_message itself that is being written to this row in the table
Hopefully I won't have to use this table often, but as the process becomes more and more complex and I get a procedure calling a procedure, calling a trigger calling another trigger, it will be nice to research where an errored line
of code exists. The debuglogging table does not exist to pick up hard system errors but rather soft process errors or bugs that cause the system to behave in unintended ways. This logging table will allow me to step through a complex set of code using an audit trail. The ability to turn logging on and off not only by passing a parameter but by having a value in a table set the logging level will great help in finding bugs in a online production system.
Now that I have this structure in place all of my stored procedures will have a @debug parameter that is defaulted to 0. All of the stored procedures will also check the value of the metadata.logging table to see if the schema they exist in is set in debug mode. The @debug parameter will take precedence over a value in the metadata.logging table unless it is 0 in which case the metadata.logging value will be determined. Any value greater than one will indicate that some level of logging is necessary, and the @debug parameter will always be of type bit, tinyint, or smallint.
The second object, land.landBuilder, is a procedure that builds upon land.spaceBuilder. The land.landBuilder procedure
retrieves the maximum and minimum x and y coordinates of the land.map table and builds a series of spaces in a straight line
from the highest value of x with the lowest value of y to the highest value of x to the highest value of y.
It then builds from the highest value of y lowest value of x to the highest value of y to the highest value of x,
ignoring any spaces that already have values. In this way it builds two straight lines around two edges of a block as shown here:
----| XXXX| XXXX| XXXX| XXXX| KEY:| and - represent new map spaces.
Currently this map building logic could result in non continuous space on the map. I will have to re-work the way land.landBuilder chooses its starting positions in the future but for now I'm not worried about it. Also this manner of adding spaces to the map means that as the map gets bigger the number of spaces added increases by two with each call. Once again this is something to keep in mind if the map ever gets to be millions of spaces square. I will also need to write a procedure to check for non continuous space in the future.
That's it for new objects let's get to the system data that makes them tick. I will put these three items on my to do list and come back to them shortly in a few segment.
Things to revisit later
- land.landBuilder could build non continuos spaces
- land.landBuilder adds two new spaces to the build process with each run (3,5,7,....10,001,10,003 etc.)
- possibly may need to build a check for non conations spaces if the first item is not resolved
Here we have the code for these two system objects.
use theSystem
go
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[metadata].[DebugLogging]') AND type in (N'U'))
DROP TABLE [metadata].[DebugLogging]
GO
create table metadata.debugLogging
(
object_name sysname not null
,event_date datetime not null
,user_name sysname not null
,debug_message varchar(2500) null
)
go
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[land].[landBuilder]') AND type in (N'P', N'PC'))
DROP PROCEDURE [land].[landBuilder]
go
create procedure land.landBuilder
@debug bit = 0
------------------------------------------------------------------
--Created by:Steve Fibich
--Created on: 2007.11.28
--Version:1.0
--Notes: this procedure will add one row and one column worth of map values
--to the land.map table. Currently this proc does not take into consideration
--any land creation modifiers
--
------------------------------------------------------------------
as
begin
set nocount on
------------------------------
--Check global debug status --
------------------------------
if @debug=0
BEGIN
select @debug=debug from metadata.logging where schema_name='land'
END
--------------
-- Vars --
--------------
declare @map_type int
declare @counter int
declare @z_axis int
declare @max_x_axis int
declare @max_y_axis int
declare @min_x_axis int
declare @min_y_axis int
declare @x_axis int
declare @y_axis int
------------
--defaults--
------------
set @map_type =1
select
@max_x_axis=coalesce(max(x_axis),1)
,@max_y_axis=coalesce(max(y_axis),1)
,@min_x_axis=coalesce(min(x_axis),1)
,@min_y_axis=coalesce(min(y_axis),1)
,@z_axis=0
from
land.map
if @debug=1
BEGIN
insert into metadata.debuglogging(object_name,event_date,user_name,debug_message)
values('land.landBuilder',getdate(),suser_name(),'@max_x_axis:' +cast(@max_x_axis as varchar(11))
+' @max_y_axis:'+cast(@max_y_axis as varchar(11))+' @min_x_axis:'+cast(@min_x_axis as varchar(11))
+' @min_y_axis:'+cast(@min_y_axis as varchar(11))+' @z_axis:'+cast(@z_axis as varchar(11)))
END
--------
--Code--
--------
set @counter=@min_y_axis
set @x_axis=@max_x_axis+1
while @counter <= @max_y_axis+1
begin
if (select map_ident from land.map where x_axis=@x_axis and y_axis=@counter) is null
BEGIN
executeland.spaceBuilder @x_axis,@counter,@debug,@map_type
END
---------
--debug--
---------
if @debug=1
BEGIN
insert into metadata.debuglogging(object_name,event_date,user_name,debug_message)
values('land.landBuilder',getdate(),suser_name(),'@x_axis:' +cast(@x_axis as varchar(11))+
'@y_axis:' +cast(@counter as varchar(11)))
END
set @counter=@counter+1
end
set @counter=@min_x_axis
set @y_axis=@max_y_axis+1
while @counter <= @max_x_axis
begin
if (select map_ident from land.map where x_axis=@counter and y_axis=@y_axis) is null
BEGIN
executeland.spaceBuilder @counter,@y_axis,@debug,@map_type
END
---------
--debug--
---------
if @debug=1
BEGIN
insert into metadata.debuglogging(object_name,event_date,user_name,debug_message)
values('land.landBuilder',getdate(),suser_name(),'@x_axis:' +cast(@counter as varchar(11))+
'@y_axis:' +cast(@y_axis as varchar(11)))
END
set @counter=@counter+1
end
end
go
declare @mapCount int
set @mapCount=1
delete land.map
--initialize the land.map table...this first value can make a difference
insert into land.map
(land_ident,x_axis,y_axis,z_axis,map_type)
values(7,1,1,1,1)
while @mapCount < 100
BEGIN
execute land.landBuilder @debug=0
set @mapCount=@mapCount+1
END
execute land.showmap
select * from land.map
where land_ident=16
Now we have a number of tables and a number of procedures but the database doesn't really have any life of its own as of yet. This system needs its system data to allow any of the stored procedures we have built to truly function. The first system data we are going to look into is the land.MapType values. This is going to be pretty straight forward as we only have one value currently which is "map". We will be expanding this in the future for maps of different types most likely "town", "cavern", "city", etc. This system data doesn't do a whole lot any procedure at this point and is more of a stub for future development. The code for this initial value is below.
USE [theSystem]
go
------------------------
--land.mapType Inserts--
------------------------
insert into land.mapType
(map_type_desc)
values('map')
go
The second core system data we look into is the land.landType data. This data represents top level map land types. Currently I have no way to distinguish between top level map types and secondary level map types, but this doesn't present a huge problem, as I only have a single map type which happens to be the top level map type. Later on the structure of this table will change to allow multiple map type landtype data to be stored.
With this current iteration we have 15 landType values. Each of these values represents a textual description land, such as swamp, hills, mountains and so forth. Each landType has a value for base_incounter_percentage, base_special_incounter_percentage, and base_existence. The first two represents values for future use and will be utilized to determine the chance for a player to encounter some sort of random chance action in the game. The third value base_existence_percentage is initial value we use to calculate the chance of this particular land type to exist on any given map title (row) in the land.map table.
I have been working with these values and the land.landTypeExistanceMode values to get the land.spaceBuilder procedure produce map tiles that have a natural feel to them. In other words I don't want a bunch of ocean tiles next to desert next to the tundra map tiles. I would like it to progress from plains to hills to mountains...with a little bit of a random feel every once in a while. The code for adding these values is below
USE [theSystem]
go
--------------------------
--land.landTypes Inserts--
--------------------------
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('light forest',.00005,.00001,.02)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('forest',.00005,.00005,.05)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('heavy forest',.0005,.00005,.02)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('aired plains',.00005,.00005,.02)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('plains',.00005,.00005,.05)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('hills',.0005,.00005,.01)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('mountains',.00005,.00005,.01)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('high mountains',.000005,.00005,.001)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('swamp',.0005,.00005,.001)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('lake',.0000005,.00005,.001)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('river',.0000005,.00005,.001)
--insert into land.landTypes
--(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
--values('stream',.00005,.00005,.001)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('volcano',.0000005,.1,.000001)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('tundra',.0000005,.05,.001)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('glacier',.0000005,.05,.0001)
insert into land.landTypes
(land_desc,base_incounter_percentage,base_special_incounter_percentage,base_existance_percentage)
values('sea',.0000005,.001,.1)
go
Now we come to the value for the land.landTypeExistanceMod table. These are some of the more difficult data elements to set correctly in "theSystem." These values help to determine the relationship between different land.landType data. Each land.landType value can have a modifier for each and every other land.landType value. The purpose of these modifies as mentioned earlier is to ensure that the land.spaceBuilder procedure builds the map in a logical layout and not just a random setting of land.landType tiles.
I have set these values through trial and error to produce a map that lends itself to building certain land types next to one another and pretty much avoiding the sea land type. Once a sea landType tile is inserted into the land.map table the odds of a sea mapType existing next to it increase greatly. This affinity for sea values to reside next to other sea values and everything else to reside next to itself or a similar land type somewhat mirrors we see in our own planet. The code for adding this is below.
USE [theSystem]
go
-------------------------------------
--land.landTypeExistanceMod Inserts--
-------------------------------------
delete land.landTypeExistanceMod
go
------------------------------------------------
--Standard Percentages--
--20% - same land types (rare)
--10% - same land types (or similar land types (rare))
--5% - same land types (or similar land types (rare))
--1% - similar land types
--.5% - distant land types
--.1% - unlikely land types
--Negative Values -- Very unlikely land types
------------------------------------------------
--Light Forest--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,1,.05)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,2,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,3,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,4,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,5,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,6,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,7,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,8,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,9,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,10,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,11,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,13,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,14,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,15,.001)
--Forest--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,1,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,2,.05)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,3,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,4,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,5,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,6,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,7,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,8,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,9,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,10,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,11,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,13,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,14,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,15,.001)
--Heavy Forest--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,1,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,2,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,3,.05)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,4,.005)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,5,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,6,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,7,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,8,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,9,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,10,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,11,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,13,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,14,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,15,.001)
--mountains--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(7,7,.05)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(7,8,.01)
--high mountains--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(8,7,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(8,8,.10)
--tundra--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(14,7,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(14,8,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(14,14,.2)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(14,15,.05)
--glacier--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(15,7,.01)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(15,8,.05)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(15,14,.05)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(15,15,.2)
--Everything vs. Sea--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(1,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(2,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(3,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(4,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(5,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(6,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(7,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(8,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(9,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(10,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(11,16,-.099)
--insert into land.landTypeExistanceMod
--(land_ident,new_land_ident,modification_existance_percentage)
--values(12,16,-.015)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(13,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(14,16,-.099)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(15,16,-.099)
--Sea--
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,1,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,2,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,3,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,4,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,5,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,6,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,7,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,8,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,9,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,10,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,11,-.1)
--insert into land.landTypeExistanceMod
--(land_ident,new_land_ident,modification_existance_percentage)
--values(16,12,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,13,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,14,-.1)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,15,.001)
insert into land.landTypeExistanceMod
(land_ident,new_land_ident,modification_existance_percentage)
values(16,16,.8)
go
Well I tried to keep this article easily digestible, as always please let me know if you have questions or comments on the project so far. I hope you have created your own "theSystem" database and can play with these objects on your own.
If you have any enhancements to the design let me know and I'll see about working them in. The next installment will bring
a new schema, a movement procedure, and updates to existing objects to bring them inline with our new debugging objects.