Programming Languages
Reply #81 – 2006-02-06 06:21:40
Gameworld(DB) /|\ | | +-->Objectmanager(must explicitely state object-type) | | /|\ | | | | | (obj_lookup) | \|/ | +---Object-Instance(Script-API) | /|\ | +--------(obj_manipulation)-----Script Pseudo-Scriptcode: 1) myobject = objmanager.find(objecttype: "Foo", searchpattern: "Bar") 2) myobject.action.kick.attach 3) otherobject = objmanager.find(objecttype: "Bleh", searchpattern: "Blah") 4) myobject.action.kick.use(target: otherobject) Explanation: 1) script sends lookup command to objectmanger. Objectmanager searches the gameworld-DB, finds the desired object, creates an object-instance of it(which serves as script-API to this individual object) and returns this instance to the script. Script creates a "myobject"-alias for the returned instance. 2) script attaches the action "kick" to myobject. Changes are immediatelly sent to the gameworld-DB. 3) Like "2)" for for "otherobject". It is a different type of object, therefore its available script-API(methods) will differ. But we dont care about this in this example(more on this later). 4) script makes myobject kick otherobject ;) There are two kinds of errors which may happen here: 1. the script executes API-commands(methods) which dont exist for this particular object-type (reason may be typo, or the scripter's memory was wrong when he tried to remember which commands are availabe for this object). Since type-declaration only happens in the lookup, i can only see two solutions to this: A: built error-handling into the script-API (disadvantage: constant performance-cost). B: code a preprocessor which checks all scripts during server-initialization (disadvantage: not easy to code, makes management of API-changes more complex(every change needs to be done in the API and the preprocessor)). 2. the script may lookup a nonexisting object. Obviously, the scripter should create error-handling for that, but what if he didn't? Then, the safest way to handle the situation would be to stop the script, throw an exception, and propagate the exception up to the event which called the script. This leads to the next issue. 3. If a script aborts in the middle of its code because of an exception, then it may already have done some manipulations to the world, thus having done incomplete work. Two solutions which i could think of: A: create a journal of all actions done by the script and do a rollback if it errors. B: make it so that all script-commands are first written to a temporary buffer - if the script finishes without error, write the temp-buffer to the real world, if it errors then drop the buffer completely. Problem of solution B of course is how to make the buffer "transparent" to the script, so that for the script it looks as if the buffer doesn't exist. In any case, this all means quite complex error-handling mechanisms - not so much in the scripts, but in the components which execute scripts and the script-API. Compile-time error-checking obviously can only help with type-errors here. But its helpless in most other cases, because the compiler cannot know beforehand which objects do exist in the gameworld. - Lyx edit: to me, the most promising approach appears to be the "temp-buffer"-approach: since scripts do NOT run concurrently, one could make it so that the DB-accessors allow oneself to set the db-writer to "buffer-mode" - this buffer-mode could be activated when a script is executed. Then, whenever an error in the script happens, just throw an exception, let the script-executer catch it and drop the buffer. When scripts read from the DB, the temp-buffer would be taken into account. The rest of the system would only read from the permanent-DB. Thus, to scripts their commands would seem "instant", while to the rest of the system, events(groups of executed scripts) would be atomic. If a script fails, the entire event never takes place. The only issue would be how to make it so that during script-DB-reading, the DB-accessors should first look in the buffer, and then in the permanent DB - without too high performance penalties. Need to check SQL-syntax for that - maybe its possible to simply use a join-method for that... would be cheap if the buffer is memory-only. If i can get this to work, then i would get a nice freebie: i dont need to write code to "collect" write commands to bundle them in db-transactions - instead, when the script finishes, i can just bundle everything in the temp-buffer, into a write-transaction to the permanent DB.