Page 1 of 3

Implementing: Rules System

Posted: Thu Jul 02, 2009 1:06 pm
by John Adams
Updated original post for current design concepts - 2011.07.03

I know I mentioned this somewhere else, but wanted to make an official Request out of it. Maybe this is something Image, Scatman or PaulGH could expand on and implement, if we agree it's a good idea.

EQEmulator has replaced most of their "variables" table need with a nice, but complex, "Rules System". I believe their rules can be applied world-wide, or to a specific zone, or even loaded dynamically (like for a GM event to change the rules of a zone). Before we get too much further into designing Combat, XP, Stats, and all that, I thought I would present an idea to implement a similar system.

In the Database, the system is just 2 tables:
  • rulesets: The parent (one) table that holds only the rule set ID and it's name (for loading, saving, etc)

    ruleset_details: The child (many) table that holds the individual rules for a given set
    • Ie., ID, CATEGORY:RULE, VALUE
In the code, there's RulesTypes.h file that define the default values (in case there is no data in the tables):
  • RULE_CATEGORY( Character )
    RULE_INT ( Character, MaxLevel, 65 )
    .
    .
    .
    RULE_CATEGORY( Guild )
    RULE_INT ( Guild, MaxMembers, 2048 )
    .
    .
    .
    RULE_CATEGORY( World )
    RULE_INT ( World, MaxClientsPerIP, -1 ) //Lieka Edit: Maximum number of clients allowed to connect per IP address if account status is < AddMaxClientsStatus. Default value: -1 (feature disabled)
    .
    .
    .
    RULE_CATEGORY( Zone )
    RULE_INT ( Zone, AutoShutdownDelay, 5000 ) //How long a dynamic zone stays loaded while empty
...to show a few examples. I'd rather not continue filling up the `variables` table when this kind of system makes a lot more sense in the long run.

Anyway, the code is in EQEmulator for us to learn from, embellish on, gank, steal or otherwise kindly borrow (with due credit heh), so what do you think?

LE, this is a definite nice-to-have, and not critical or important in any way... I do not expect YOU to implement it unless you agree it's a good time to do so before we get too much further. If no one else wants to do it, it'll have to wait as I totally lack the knowledge needed to do so.

Post your thoughts, hash out the details, and let's see what we come up with. I'd really like to see something like this implemented, as the dynamics of this concept make for a very interesting server configuration ;)

...in my opinion.

Re: Implementing: Rules System

Posted: Sun Jul 03, 2011 11:42 am
by John Adams
Additional thoughts from IRC w/Scat --

Purpose:
"Rules" are how we will allow extreme customization of the World and the player experience. Example would be to set your combat multipliers via the rule system on a global (world) level, or local (zone) level. Players in those areas will experience different outcomes to combat (or any other EQ2Emu system) based on the current active ruleset.


Defaults Requirement:
In this, every rule must have a default hard-coded in code, in case that rule does not exist in the Database, the World still needs to know how to handle it. Otherwise, calculations will certainly fail.


Usage:
As stated above, a Rule Set can be loaded for the entire World (ie., timers, triggers, level caps, etc), or to a specific Zone... and the two shall not conflict with one another. The World's ruleset will be stored (by ID or name) in the existing `variables` table. A Zone's ruleset, stored in a new 'rule_set' column in our Zones table.


Commands:
There will be in-game commands:
  • /reloadrules - reloads all rules from the DB
    /unloadrules
    /reloadworldrules
    /reloadzonerules {zone_id}
Commands for manipulating ruleset configurations from in-game:
  • /rules - the command
    /rules list - List available rule sets
    /rules current - Show name of rule set currently applied to zone
    /rules reload - Reload the selected ruleset in this zone
    /rules switch {ruleset name} Change the selected ruleset and load it
    /rules load {ruleset name} Load a ruleset in the current zone without applying
    /rules store {ruleset name} Store the running ruleset as the specified name
Commands for manipulating running rulesets:
  • /rules reset - Reset all rules to their default values
    /rules get [rule] - Get the specified rule's local value
    /rules set (rule) (value) - Set the specified fule to the specified value locally only
    /rules setdb (rule) (value) - Set the specified fule to the specified value locally and in the Database
    /rules list (catname) - List all rules in the specified category (or all catagories if omitted)
    /rules values (catname) - List the values of all rules in a specified category
These commands are directly from EQEmu's command list, and should be modified to suit our own needs. But reviewing how their rules work, it would appear there are some "non-destructive" commands (load, set, etc) that we should consider keeping.

Eg., /rules load [ruleset name] loads the set into memory but does not apply it. This gives the admin/GM a chance to review the settings (/rules list {catname}, /rules values {catname}) before applying them destructively to the current zone (/rules switch [ruleset name]). Does that make sense?


Data Tables:
Preliminary Table layout (not committed til we get started)

`rulesets`

Code: Select all

CREATE TABLE `rulesets` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `ruleset_id` int(10) unsigned NOT NULL default '0',
  `ruleset_name` varchar(64) collate latin1_general_ci NOT NULL default 'default_ruleset',
  `ruleset_active` tinyint(1) unsigned NOT NULL default '1',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `RuleNameIDX` (`ruleset_name`),
  KEY `RulesIDX` (`ruleset_id`)
) ENGINE=InnoDB;

`ruleset_details`

Code: Select all

CREATE TABLE `ruleset_details` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `ruleset_id` int(10) unsigned NOT NULL default '0',
  `rule_category` varchar(64) collate latin1_general_ci NOT NULL default '',
  `rule_type` varchar(64) collate latin1_general_ci NOT NULL default '',
  `rule_value` varchar(64) collate latin1_general_ci NOT NULL default '',
  `description` text collate latin1_general_ci,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `RuleCatTypeIDX` (`ruleset_id`,`rule_category`,`rule_type`),
  CONSTRAINT `FK_ruleset_details` FOREIGN KEY (`ruleset_id`) REFERENCES `rulesets` (`ruleset_id`) ON UPDATE CASCADE
) ENGINE=InnoDB;

Conclusion:
The primary goal is to implement at least the basic Rules System, and these in-game data modification commands are secondary but important to the completion of the system.

I think that's enough to consider for now. Scat, any questions? Soon as you get a framework in place, I will begin expanding it so you don't have to worry about doing everything yourself :) Thanks for the kick-off.

Re: Implementing: Rules System

Posted: Sun Jul 03, 2011 11:48 am
by John Adams
One final thought:

What do you think about a Ruleset on a specific "area"? Is it even possible to define a location area in a zone, and apply different rules specifically to that area? That might be kinda cool ;) not sure how practical it is though.

Re: Implementing: Rules System

Posted: Sun Jul 03, 2011 10:23 pm
by Scatman
It sounds good. Pretty much exactly what I expected. However for area, it's certainly possible (it's a computer, anything is possible). How should it be implemented though? An x,y,z with a radius? 3+ points that are drawn? Just trying to figure out exactly what you want.

Re: Implementing: Rules System

Posted: Mon Jul 04, 2011 8:10 am
by John Adams
Scat, if it is feasible, I thought maybe we could utilize the parameters in the "location" functionality, you know the one that draws the polygon of "you are here"? Does that make sense? If you are within these bounds, then these rules apply...

"Area" can be secondary to the base system implementation, but I figured I'd feed your enormous brain with as much data as possible :)

Re: Implementing: Rules System

Posted: Mon Jul 04, 2011 9:24 pm
by Scatman
Sure. So we'll need another table for those coordinates?

Re: Implementing: Rules System

Posted: Tue Jul 05, 2011 8:02 am
by John Adams
Well, let's focus on getting the main system implemented first (World/Zone), and later we can add functionality for Area, if we figure out the best way to do it.

I was hoping to simply reference in locations table, a ruleset_name, and it would use that rule. No extra tables/coordinates, that are not already identified in `locations`.

Re: Implementing: Rules System

Posted: Tue Jul 05, 2011 5:49 pm
by Scatman
For category and types, these are predefined right?
Aka:

Categories: Character, Guild, Zone, etc...
Types: XP Gain, Loot Coin Bonus, etc...

Then you can mix and match? Character:XP Gain, Guild:XP Gain, Zone:Loot Coin Bonus, etc?

If so, can we change these types in the database from VARCHAR to ENUM? Enum is more efficient and way more readable so we can see the predefined values.

Re: Implementing: Rules System

Posted: Wed Jul 06, 2011 7:24 am
by John Adams
Yes, ENUM should be fine. The DB values are merely "overrides" to what is CONSTANT in the code. Meaning, there will never be a DB "rule" that invents itself. If the rule does not exist in code as a pre-defined rule, then any invalid overrides are ignored.

Valid override:

Code: Select all

Code: CHARACTER:MaxLevel = 80
Invalid override:

Code: Select all

DB: COMBAT:MaxLevel = 80
I can see someone opening the ruleset_details table and changing an ENUM (even accidentally) and rendering the override invalid. We simply need to ignore any Category+Type that does not have a hard-coded reference. Make sense?


Ie., the only concern I have is that (in the DB) someone might mistakenly assign a catagory to a rule that is not supported.

Re: Implementing: Rules System

Posted: Wed Jul 06, 2011 7:34 am
by John Adams
Btw, "ruleset_type", if you'd rather this field (and define name) be something else more clear, feel free to change it. No DB tables have been committed for this yet.

`rule_category`
`rule_name`

Or even just
`category`
`name`

(tho I think those may be MySQL reserve words, and I am trying to steer our DB away from using reserves)

Re: Implementing: Rules System

Posted: Wed Jul 06, 2011 2:04 pm
by Scatman
If the category and type combination are invalid, like you said, they'll simply be ignored. And those column names are fine. Just need to be changed to ENUM from VARCHAR and I'll be a happy hobbit.

Re: Implementing: Rules System

Posted: Wed Jul 06, 2011 2:31 pm
by John Adams
Ok, right now I do not know all the ENUM values that we will use, but we can probably make a value for each "system" we already know about (like with LogWrite). Use the same ones to start. Unless you'd rather only start with the ones we know, and add as we go?

Up to you on that one. The latter is fine with me. Hell, just for developing this, make 1 enum for 'character' and test the max_level rule :)


In case I didn't mention it, my goal to start is to "ruleify" everything we can from the `variables` table, anything that defines the world. Then, under the World and Zone enums, all the timers that are currently hard-coded.

Ie:

Code: Select all

World::World() : save_time_timer(300000), time_tick_timer(3000), vitality_timer(3600000), player_stats_timer(60000), server_stats_timer(60000), remove_grouped_player(30000), guilds_timer(60000), lotto_players_timer(500) {
those :)

Re: Implementing: Rules System

Posted: Thu Jul 07, 2011 12:18 am
by Scatman
So I'm about 3/4's done (minus the commands). The only part I'm not done is actually applying a Rule Set to a specific zone. But that's just a database change and a Database loading call (so maybe I'm more like 7/8th's done). I'm posting this so you can look it over before we set it in stone. I won't be around tomorrow (Thursday) and I never know what my weekends are like. It's a little different from LogTypes because I wanted to get rid of the preprocessor hackjobs. So here's a quick rundown:

4 new classes (all defined in Rules.h/cpp):
- Rule - Defines an actually rule (from ruleset_details).
- RuleSet - Defines the set of rules (from ruleset). When loading a ruleset, the database will first load all possible rules into the rule set with their default values. Then it'll hit the database and look for overrides and overwrite their values. If a combination of ruleset_details.category and ruleset_details.type is not a valid combination, you'll see an error message and it'll be ignored.
- RuleSets - The list of all the rule sets.
- DefaultRules - Simply a list of all the possible rules and what their default values are.

When the database loads a zone, it'll find the ruleset_id from the database. If it's greater than 0, it'll load the rule set from the global RuleSets list and the Zone will carry a reference to that ruleset. Once loaded, a rule will be accessed be zone->GetRuleSet()->GetRule(category, type)->Get([type]);

Example: zone->GetRuleSet()->GetRule(CHARACTER, MAX_LEVEL)->GetInt32();

PS: We need to figure out how to apply the active bit. Should the rule set not even be loaded? Or should it be loaded but return all null values for ruleset->GetRule()? Should it be loaded into memory but not apply to any zone?

Re: Implementing: Rules System

Posted: Thu Jul 07, 2011 9:05 am
by John Adams
Dude, this is awesome. Thank you for doing this so quickly :) I was prepared to write it myself, but yours sounds 100x better than my ideas were haha. Love it. Also, I think that's the largest post you have ever made. Bravo! ~tear~
Scatman wrote:PS: We need to figure out how to apply the active bit. Should the rule set not even be loaded? Or should it be loaded but return all null values for ruleset->GetRule()? Should it be loaded into memory but not apply to any zone?
If rulesets.active == 0, do not even load it. Ignore it entirely. That's the reason I put that bool in there. So your ruleset load query will just say "...WHERE active = 1". This is meant so you can set up rulesets and swap them out as needed, without adding additional overhead by loading rulesets that are unused.

If you can think of a better way to handle this, let me know. Note that rulesets could eventually be up in the 100's of values (int, bool, float, maybe even char values).

Re: Implementing: Rules System

Posted: Thu Jul 07, 2011 3:15 pm
by Scatman
That sounds good to me.