View previous topic :: View next topic |
Author |
Message |
Red
Joined: 14 Feb 2009 Posts: 21
|
Posted: Wed Dec 30, 2009 1:07 Post subject: Local VS Persistent |
|
|
When I was using the NWN DB, I had a habit of hitting the DB as little as possible and setting variables/strings that I would be checking regularly as local where applicable.
Is this still a good practice when using NWNX or would that be a waste of time?
one example would be a persistent location. When the client enters I was in the habit of checking for that campaign location and setting a local location for that toon (to be honest I even started using item properties on an item to determine what the location was, fearing the NWN DB calls). If that location changed I would set it as local, saving to the DB during rest/client exit events. Very common practice from what I have read.
Still a good practice with NWNX? |
|
Back to top |
|
|
axs
Joined: 11 Feb 2005 Posts: 76
|
Posted: Wed Dec 30, 2009 1:42 Post subject: |
|
|
Using Local's is always good practice.
My server save player location every HB on local, every 60 seconds is maintance time, for each player in delay of few seconds server exports character and saves lots of data to mysql db and also other module data.
Player data are saved also in OnLeave.
I haven't got any overloads, everything is smooth and not laggy.
Also good practice is if you using some systems (like CNR) that create dozens of vars, to reserve locals that need quick access. And never delete them.
For example, when module load (on module object), when player join (on player).
Access to those variables will be quicker. |
|
Back to top |
|
|
Red
Joined: 14 Feb 2009 Posts: 21
|
Posted: Wed Dec 30, 2009 1:51 Post subject: |
|
|
Thanks for the reply.
I am going to stick with that philosophy. |
|
Back to top |
|
|
Fireboar
Joined: 17 Feb 2008 Posts: 323
|
Posted: Wed Dec 30, 2009 2:04 Post subject: |
|
|
Just a point there, why bother saving location data as locals at all? Wouldn't it make more sense to only create the data required at the time when you want to save it to the database? Seems a little wasteful to do SetLocalLocation on a PC when GetLocation could get exactly the same data as GetLocalLocation whenever it's called. Since location data is only ever needed for persistence or server-portalling.
I suppose there is merit in doing it this way if you have to store the precise location of the PC OnClientLeave, but apart from that just using GetLocation should be fine, no?
Apart from that, I'd agree with what axs said. |
|
Back to top |
|
|
axs
Joined: 11 Feb 2005 Posts: 76
|
Posted: Wed Dec 30, 2009 2:18 Post subject: |
|
|
The reason why I'm saving location so often is because GetLocation used in OnLeave doesn't give valid location anymore.
Players complained that they are not starting where they recently left.
It's little waste, but not such big. |
|
Back to top |
|
|
the.gray.fox
Joined: 11 Dec 2009 Posts: 21
|
Posted: Wed Dec 30, 2009 3:37 Post subject: |
|
|
axs wrote: | Using Local's is always good practice.
My server save player location every HB on local |
Hello.
When a player transitions to another area, he quits the area he was last in, but he is not yet in the area he is going to.
Check for validity the area the player is in before you do sensible stuff that involves areas, locations, vectors, spawning things, dropping objects on ground, et cetera.
-fox |
|
Back to top |
|
|
axs
Joined: 11 Feb 2005 Posts: 76
|
Posted: Wed Dec 30, 2009 3:50 Post subject: |
|
|
Hi. I'm using GetIsObjectValid(GetAreaFromLocation(lLoc)) in most cases is sufficient. |
|
Back to top |
|
|
Red
Joined: 14 Feb 2009 Posts: 21
|
Posted: Wed Dec 30, 2009 7:16 Post subject: |
|
|
Thanks for all the responses. Good info above. |
|
Back to top |
|
|
Asparius
Joined: 18 Sep 2007 Posts: 52
|
Posted: Tue Jan 05, 2010 10:09 Post subject: |
|
|
About local variables performance - I did a little research about 1,5 year ago, maybe you'll find it useful:
http://nwn.bioware.com/forums/viewtopic.html?topic=647653&forum=47&sp=0
For CNR - and all systems that use lots of localvars, it would be a good option to use a waypoint for this system variables, instead of module object. |
|
Back to top |
|
|
Red
Joined: 14 Feb 2009 Posts: 21
|
Posted: Tue Jan 05, 2010 19:25 Post subject: |
|
|
Very useful, thank you.
Quite a lot of research done there. I was setting quite a lot on the module as an object with my spawn system as well. In the end I created a GetModuleObject() function as suggested and split my storage of variables, rather than stack them all together. |
|
Back to top |
|
|
maddogfargo
Joined: 03 Nov 2009 Posts: 49
|
Posted: Tue Jan 05, 2010 23:23 Post subject: Locals |
|
|
All location data in the Base Mod I experimented with / released is saved as locals on a non-transferrable player map tool. It is very fast and no database access is ever required.
Players can manually save locations where permitted. (* As well as customize their category names and add a description for each saved location). But for persistent location data there are only 2 events that fire this:
On-enter for all areas
On-rest
Character is exported at the same time location is saved.
Combining location save and export on these events seemed to make sense and works well for me. _________________ * illegible scribble * |
|
Back to top |
|
|
Baaleos
Joined: 02 Sep 2007 Posts: 830
|
Posted: Wed Jan 06, 2010 12:39 Post subject: Pooling your database updates |
|
|
On my own server, I work on the basis that things which are going to be stored rapidly, would be best stored locally on an object, and then at predetermined times, based on heartbeats, those values are transfered persistently to the database.
Eg -
Player is killing monsters - each kill gives 'blood points'.
These need to be stored persistently, but I didnt want to do database updates on each kill, because I have no idea what would happen if someone did a hellball, and killed 100 monsters at once - would it over load the odbc? I have no idea.
So, to be safe, I had the onDeath event, store the BloodPoints on the player object.
Then, on the heartbeat of the server, when 6 heartbeats had passed, it would loop through all players, read their locally stored variable, and then add it to their database entry. Incrementing the already stored value, while deleting their locally stored value.
Using this method, it reduces odbc overhead/processing requirements, while allowing persistency.
I'd recommend attempting to keep all of your necessary database updates and database queries, conceise and possibly pool the frequent ones to reduce the amount of necessary queries.
Eg - Instead of doing 100 +10 Blood Points per kill - instead store the values temporarily on the player, then transfer them, at a convenient time to the database.
This turns 100 queries which add 10 each, to the database, into 1 query which adds 1000 to the database.
6 of 1, half a dozen of the other. |
|
Back to top |
|
|
the.gray.fox
Joined: 11 Dec 2009 Posts: 21
|
Posted: Fri Jan 08, 2010 13:26 Post subject: |
|
|
When I first thought to mirror a large amount of 2da data into LocalVariables I wondered if it would have been really better to pack it in compact form, storing subvalues like I could in a biffield (at least for integers).
In some case this cuts the amount of total vars considerably -- of course.
But it so happen that there is then a small overhead to pay every time one of the sub values from a specific var are needed.
As no script can come even close to the speed of compiled code, I wondered if the benefit of the reduced amount of vars stored would not be defeated by the cost to extract the subdata.
And it so happens that I have experience with parsers, virtual machines and bytecode.
Even the fastest atomic operator in the end translates to many assembly instructions on the metal.
Interpreted and Executed are worlds apart always -- no matter how speed-optimized the VM is.
Having modified lot of original bioware scripts, I have seen that their scripters are no professionals. Often they have no idea of the basic optmizations.
But does it matter? There is little room for smart code anyway.
You think of some hashing algorithm to eliminate branching and take advantage of boolean logic... and you know it would run lightning fast on compiled code... but you port that in nwscript, and it becomes slow to the point it is defeated by any direct call to the built-in "branching and jumping" compiled functions.
From my experience with nwn and nwscript, I have learned that trying any fast trick does backfire on you in almost all cases.
Packing of LocalVariables is rewarding if you store them in big amounts, and only if you read them back very often *and* in a short time frame.
What instead has shown to pay really well, is the use of ExecuteScript() to simulate the dynamic linking of functions (at least for the big functions reused by many scripts).
This positively impacts on the code size of a script, reducing it and cutting the "load" times required to bring that script into cache and prepare for its execution.
And having smaller scripts collaterally makes more of them stay actively in cache for longer, de facto zeroing the load times much more frequently.
-fox |
|
Back to top |
|
|
Baaleos
Joined: 02 Sep 2007 Posts: 830
|
Posted: Fri Jan 08, 2010 22:48 Post subject: streamline |
|
|
Quote: |
What instead has shown to pay really well, is the use of ExecuteScript() to simulate the dynamic linking of functions (at least for the big functions reused by many scripts).
|
I call this Streamlining.
If you use too many includes etc, you can get a
"IDENTIFIER LIST FULL" Error.
This is when you have created a script, and all available memory is used for the included functions, and no more can be added.
Using Execute Script, allows you to get around this.
Its useful, when you absolutly NEED to have includes in use, but alas, you are getting that script error. You just split the script into 2 separate scripts, and put one include in one, and then have it call the second script, and the second includes and uses the other include.
I got this error many times for scripts such as my onClientEnter - which needs to run FunkySwerves Simtools onEnter, as well as Shayans Subrace on enter methods.
So, What I did, was have the onEnter script call Stream_onEnter1, and then it calls Stream_onEnter2 etc. |
|
Back to top |
|
|
|