Implementing: Rules System

This is a design and development forum for EQ2Emulator's extensive Rules System.

Moderator: Team Members

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Implementing: Rules System

Post by John Adams » Thu Jul 02, 2009 1:06 pm

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.
John Adams
EQ2Emulator - Project Ghost
"Everything should work now, except the stuff that doesn't" ~Xinux

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Sun Jul 03, 2011 11:42 am

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.
John Adams
EQ2Emulator - Project Ghost
"Everything should work now, except the stuff that doesn't" ~Xinux

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Sun Jul 03, 2011 11:48 am

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.

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Re: Implementing: Rules System

Post by Scatman » Sun Jul 03, 2011 10:23 pm

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.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Mon Jul 04, 2011 8:10 am

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 :)

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Re: Implementing: Rules System

Post by Scatman » Mon Jul 04, 2011 9:24 pm

Sure. So we'll need another table for those coordinates?

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Tue Jul 05, 2011 8:02 am

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`.

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Re: Implementing: Rules System

Post by Scatman » Tue Jul 05, 2011 5:49 pm

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.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Wed Jul 06, 2011 7:24 am

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.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Wed Jul 06, 2011 7:34 am

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)

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Re: Implementing: Rules System

Post by Scatman » Wed Jul 06, 2011 2:04 pm

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.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Wed Jul 06, 2011 2:31 pm

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 :)

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Re: Implementing: Rules System

Post by Scatman » Thu Jul 07, 2011 12:18 am

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?

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Implementing: Rules System

Post by John Adams » Thu Jul 07, 2011 9:05 am

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).

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Re: Implementing: Rules System

Post by Scatman » Thu Jul 07, 2011 3:15 pm

That sounds good to me.

Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests