Feature Specification: Persistent PC Status

Scripted ALFA systems & related tech discussions (ACR)

Moderators: ALFA Administrators, Staff - Technical

Locked
User avatar
ç i p h é r
Retired
Posts: 2904
Joined: Fri Oct 21, 2005 4:12 pm
Location: US Central (GMT - 6)

Feature Specification: Persistent PC Status

Post by ç i p h é r »

Persistent PC Status
The requirements for persistent PC status are detailed below.

For a short explanation of the feature specification format, visit:
http://www.alandfaraway.org/phpbbforum/ ... hp?t=27229

Functional Requirements
Player status is information that needs to travel with the player and as such, must be saved on the PC (skin/hide), which is stored in the central vault, to achieve persistency across sessions and servers. Player status consists of hit points, spell uses, current location, and current condition (diseased, poisoned, fatigued, ability drained, level drained, etc). Player status will be saved on request (save widget), on a successful rest, on logout, on portal activation, and autosaved every 10 minutes.

NWN Object Dependencies
PC Skin/Hide, Save Widget

Logging and Debugging (global LOG & DEBUG (on/off) constants)
TBD

Persistence Requirements
Hit Points, Spell Uses, Current Condition

Event Dependencies
OnPlayerRest, OnClientEnter, OnActivateItem (save widget), OnEnter (portal)
Last edited by ç i p h é r on Sun Aug 20, 2006 11:05 pm, edited 1 time in total.
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Post by Ronan »

Cipher sent me a PM in chat about how he worried that spell usage scripts could take up too much memory on the bic, and increase general CPU usage (local variable access being greatly dependant on the number of local variables).

So, my thought was to do spell usage the same way it is currently done, with a single local string of spell Id numbers seperated by underscores (though in its current implementation this data is stored on the emote ball). Random access of the spell usage information isn't needed, and its only read when the PC logs in. Appending additional uses to the end of the string should be a quick process, and it only takes up one local variable. When the PC rests successfully, this local string is deleted.

Edit: We'd need two I guess, one to track spell uses and the other feat uses. Not sure if there is an easy way to track item / day uses, though maybe OE will give us a break on all this and store a bit more state information on the bics.
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Post by Ronan »

ie, some list like this:

Code: Select all

////////////////////////////////////////////////////////////////////////////////
//
//  System Name : ALFA Core Rules
//     Filename : acr_stringlist_i.nss
//      Version : 0.1
//         Date : 7/23/06
//       Author : Ronan
//
//  Local Variable Prefix =
//
//
//  Dependencies external of nwscript:
//
//  Description
//  An API which stores multiple strings inside of one string, using a delimiter
//  to seperate the values. Any string can be added to this value, save strings
//  which contain the delimiter character.
//
//  Revision History
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Includes ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Constants ///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

const string _DELIMITER = "_";

////////////////////////////////////////////////////////////////////////////////
// Structures //////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct StringListResult {
    string sResult;
    string sString;
};

////////////////////////////////////////////////////////////////////////////////
// Global Variables ////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function Prototypes /////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// Gets the first element in this string list, and returns it as sResult in the
// struct StringListResult. The Remaining string list (minus the first element)
// is returned as sString in the same struct.
struct StringListResult PopStringList(string sString);

// Pushes the value sValue onto the front of string list sString and returns it.
// Any length or value of sValue is valid, with the exception of any string
// containing the delimiter character, an underscore.
string PushStringListFront(string sString, string sValue);

// Pushes the value sValue onto the end of string list sString and returns it.
// Any length or value of sValue is valid, with the exception of any string
// containing the delimiter character, an underscore.
string PushStringListEnd(string sString, string sValue);

////////////////////////////////////////////////////////////////////////////////
// Function Definitions ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

string PushStringListFront(string sString, string sValue) {
    return sValue + _DELIMITER + sString;
}

string PushStringListEnd(string sString, string sValue) {
    return sString + _DELIMITER + sValue;
}

struct StringListResult PopStringList(string sString) {
    struct StringListResult strResult;
    int nIndex;

    nIndex = FindSubString(sString, _DELIMITER);

    strResult.sResult = GetStringLeft(sString, nIndex);
    strResult.sString = GetStringRight(sString, GetStringLength(sString) - nIndex);
    return strResult;
}
User avatar
Gelcur
Dire Badger
Posts: 141
Joined: Wed Jan 14, 2004 5:37 pm

Post by Gelcur »

I have to agree with this, we should minimize usage anywhere it is possible. Since this system is usually invisible to the DMs and players there is no reason for it to be easily readable by anyone it just needs to work and be efficient. Just my two cents I'm ussually for readablity over opitmization but I think this is one place we can optimize and it won't matter much.
Image
User avatar
Fionn
Ancient Red Dragon
Posts: 2942
Joined: Sun Jan 04, 2004 7:07 am
Location: Seattle, WA

Post by Fionn »

It should be possible to store it locallyon the mod, AND on the BIC. I don't know what the footprint is for an empty INT on a bic vs full, but if needed we can simply destroy the object they're attached to. When a PC activates the portal script, all local data specific to the PC is read to the bic. When a PC enters the mod, if they have such an object, it is read to the local module and destroyed. Normal login/logout wouldn't be affected by this data.
PC: Bot (WD)

Code: Select all

     -----          -----          -----          -----
    /     \        /     \        /     \        /     \
   /  RIP  \      /  RIP  \      /  RIP  \      /  RIP  \      /
   |       |      |       |      |       |      |       |      |
  *| *  *  |*    *| *  *  |*    *| *  *  |*    *| *  *  |*    *|
_)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_(
User avatar
ç i p h é r
Retired
Posts: 2904
Joined: Fri Oct 21, 2005 4:12 pm
Location: US Central (GMT - 6)

Post by ç i p h é r »

Yeah, we could use the existing method, though I don't know what's worse: one really long string you'd have to parse or lots of dedicated integers. The former is decidedly disk friendly but the latter is decidedly CPU friendly. Presumably, RAM usage would also favor strings if they are dynamically allocated.

It's simple enough to compare save times using both methods and comparing mem usage to see if that's notable would be interesting too. I'll see what I can drum up. This could be a non-issue entirely, at least with regard to the method we use, but I'll opt for optimization of memory given the tight limits we'll be under, at least initially.

The dark horse in all this is what Obsidian ends up doing, of course.
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Post by Ronan »

ç i p h é r wrote:Yeah, we could use the existing method, though I don't know what's worse: one really long string you'd have to parse or lots of dedicated integers. The former is decidedly disk friendly but the latter is decidedly CPU friendly. Presumably, RAM usage would also favor strings if they are dynamically allocated.
Its a pretty rare occurance that this string is read, really only on log-in. So in terms of CPU usage, I think both would work fine. I don't think either implementation is likely to cause a spike in CPU usage which could lag anything.
User avatar
ç i p h é r
Retired
Posts: 2904
Joined: Fri Oct 21, 2005 4:12 pm
Location: US Central (GMT - 6)

Post by ç i p h é r »

Unfortunately, that's not true. Not with needing to pray or study for spells. As a result, spell uses have to be either removed completely (what the system does now) or restored to pre-rest values after any successful rest in order to facilitate this requirement.

Sorcerers & Bards: Just rest.
Wizards: Rest and study.
Clerics, Druids, Rangers, and Paladins: Rest and pray.

We could circumvent the built in REST system, but I haven't really thought that all through. Maybe that introduces more script level coding and local data management. As it stands, the two aspects of a REST that need to be rolled back are Spell Use and Ability Damage recovery. Unless Obsidian changes things.
User avatar
ç i p h é r
Retired
Posts: 2904
Joined: Fri Oct 21, 2005 4:12 pm
Location: US Central (GMT - 6)

Post by ç i p h é r »

Ok, I committed an initial rev of this script to the repository. I've kept the spell use management in the rest system since part of the requirements there include "simulated" resting from login/outs...managing spell uses goes with the territory. I also left out any management of condition as we haven't quite worked out how to adequately record effects so they can be recreated on login. I expect to revisit this if a simple solution isn't provided with NWN2.

Feel free to have a look. Ronan, let me know if you want me to revise anything.

P.S. The data on the bic, worst case, added about 1-2k to the file size. With compression supposedly coming in NWN2, it seems a moot issue. I didn't notice an appreciable, sustained memory difference either so I'm holding off making optimizations until NWN2 rolls around and we know what we've actually got to work with.

P.P.S. I've adopted the ALFA_ prefix on all global functions as convention. We didn't stipulate one to my knowledge but it seemed apropos to do so.
User avatar
Fionn
Ancient Red Dragon
Posts: 2942
Joined: Sun Jan 04, 2004 7:07 am
Location: Seattle, WA

Post by Fionn »

ALFA_***** for stuff that travels
SERVER_****** for stuf that doesn't

Makes sense to me.

I agree, 1-2K is inconsequential. We've currently got bics in the 100-200KB range. NWN2 has promissed to have a single size for inventory icons, so likely PCs will be able to carry more crap than they do now. There will also be more skills, feats, etc - expect 100KB to be the minimum size for a bic.
PC: Bot (WD)

Code: Select all

     -----          -----          -----          -----
    /     \        /     \        /     \        /     \
   /  RIP  \      /  RIP  \      /  RIP  \      /  RIP  \      /
   |       |      |       |      |       |      |       |      |
  *| *  *  |*    *| *  *  |*    *| *  *  |*    *| *  *  |*    *|
_)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_(
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Post by Ronan »

I noticed you had the PC status scripts saving a PC's last position and moving him to his last location. I think this stuff really needs to be handled somewhere else, as there are quite a few reasons a PC would log in and be invalid to play on a server (such as logging in to a server he didn't port into).

So, I think the act of allowing a PC for live play should be done at the end of his OnSpawn event. I definitely don't think we should have individual systems making their own OnSpawn events with polling scripts. Each system that might call a function that marks him invalid and throws him in Q. If no such function is called, the PC is allowed for active play at the end of his OnSpawn event. Sound good?
User avatar
Fionn
Ancient Red Dragon
Posts: 2942
Joined: Sun Jan 04, 2004 7:07 am
Location: Seattle, WA

Post by Fionn »

I'd whitelist rather than blaklist

Come to think, why not just default mod start to Q with an onAreaEnter to freeze. AreaHB can checj for passport
PC: Bot (WD)

Code: Select all

     -----          -----          -----          -----
    /     \        /     \        /     \        /     \
   /  RIP  \      /  RIP  \      /  RIP  \      /  RIP  \      /
   |       |      |       |      |       |      |       |      |
  *| *  *  |*    *| *  *  |*    *| *  *  |*    *| *  *  |*    *|
_)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_(
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Post by Ronan »

Fionn wrote:I'd whitelist rather than blaklist
Hmm, why? I was thinking blacklisting is nicer, since it doesn't require as much implementation for each system added. All each system needs to do is call QuarantinePC(), or not.
User avatar
Fionn
Ancient Red Dragon
Posts: 2942
Joined: Sun Jan 04, 2004 7:07 am
Location: Seattle, WA

Post by Fionn »

validateResident()
validateTourist()

See edit
PC: Bot (WD)

Code: Select all

     -----          -----          -----          -----
    /     \        /     \        /     \        /     \
   /  RIP  \      /  RIP  \      /  RIP  \      /  RIP  \      /
   |       |      |       |      |       |      |       |      |
  *| *  *  |*    *| *  *  |*    *| *  *  |*    *| *  *  |*    *|
_)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_//(/|_)(__)/\\_(
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Post by Ronan »

We've got a lot more reasons to Q someone than just not having a passport, unfortunately. And calling QuarantinePC() instead of validateResident() means doesn't require the quarantining system has any knowlege of the reasons for Qing the PC. Marking the PC as validated through each step does.
Locked