Storage Object framework

Scripted ALFA systems & related tech discussions (ACR)

Moderators: ALFA Administrators, Staff - Technical

Locked
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Storage Object framework

Post by Ronan »

This was one of the first systems I wrote, and I've not really mentioned it here. I use it quite often. Basically what it does is dynamically spawn a "storage object" placeable when CreateStorageObject() is called. When used with our "private" variable naming conventions, an object private to a single system can be created. This can do the following,
  • Provides an object to store local variables on. The execution time of GetLocal* or SetLocal* functions increases linearly with the number of local variables on an object. By providing each system with its own storage object, we reduce the execution time of those functions when using that object. The "private" nature of many of these objects means that there is no chance of other systems creating conflicting local variable names, so shorter names can be used, increasing speed and decreasing memory use.
  • Provides a source for applying effects. In nwscript, the only way to differentiate two identical effects is to compare their creators with GetEffectCReator(). So if you want to tell the difference between a EFFECT_TYPE_CONCEALMENT from a darkness spell or the weather system, you need to call GetEffectCreator(). Local variables attached to the storage object can describe the source of the effect (see the persistant effects system), so that intelligent choices on removal can be made. I'm not sure what the best way to configure this system would be, so I've left it as a simple boolean removable/unremovable flag for now.
  • The storage object can store items as well, as they have inventories.

Code: Select all

////////////////////////////////////////////////////////////////////////////////
//
//  System Name : ALFA Core Rules
//     Filename : acr_storage_obj_i
//      Version : 0.1
//         Date : 5/4/06
//       Author : Ronan
//
//  Local Variable Prefix = ACR_STO
//
//  Dependencies external of nwscript:
//  Requires a placable blueprint resref to exist, as defined by the
//  _ACR_STO_OBJECT_RESREF constant. Also requires a waypoint containing the tag
//  of the _ACR_STO_WAYPOINT_TAG constant to exist.
//
//  Description
//  NWN stores variables by placing them on objects. For this reason, a system
//  to organize the objects they store these variables on is needed. In NWN1,
//  local variable mean access time increases linearly with the number of
//  variables stored on an object (as dumb as that is).
//  Also, this system can be used as a way to track effects on a creature,
//  by use of GetEffectCreator().
//
//  Revision History
////////////////////////////////////////////////////////////////////////////////

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

#include "acr_debug_i"

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

// Blueprint resref for the storage object.
const string _ACR_STO_OBJECT_RESREF = "acr_sto_obj";

// Waypoint tag for the location the objects are created at.
const string _ACR_STO_WAYPOINT_TAG = "acr_sto_wp";

// Signifies that effects applied by this object should be removable through
// normal means.
const int STORAGE_ITEM_EFFECTS_REMOVABLE = 1;

// Signifies that effects applied by this object should not be removable through
// normal means.
const int STORAGE_ITEM_EFFECTS_UNREMOVALBE = 2;

// The local int for the above constants.
const string _EFFECTS_REMOVABLE_LI = "ACR_STO_EFFRMV";

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

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

int _storageDebugSystem;

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

// Initializes the storage object system. Usually called from OnModuleLoad.
void InitializeStorageObjects();

// Creates and returns a storage object, a medium for storing local variables.
// bEffectsRemovable should be defined as,
// STORAGE_ITEM_EFFECTS_REMOVABLE
// Signifies that effects applied by this object should be removable through
// normal means. Or,
// STORAGE_ITEM_EFFECTS_UNREMOVALBE
// Signifies that effects applied by this object should not be removable through
// normal means.
object CreateStorageObject(string sName = "", int bEffectsRemovable = STORAGE_ITEM_EFFECTS_REMOVABLE);

// Returns 1 if effects applied from oObject are removable, 0 otherwise.
int CanRemoveEffectsFrom(object oObject);

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

void InitializeStorageObjects() {
    _storageDebugSystem = CreateDebugSystem("Storage object: ", DEBUG_TARGET_NONE, DEBUG_TARGET_LOG, DEBUG_TARGET_LOG);
}

object CreateStorageObject(string sName = "", int bEffectsRemovable = STORAGE_ITEM_EFFECTS_REMOVABLE) {

    PrintDebugMessage("Creating storage object named: " + sName, _storageDebugSystem, DEBUG_LEVEL_INFO);

    object wp = GetObjectByTag(_ACR_STO_WAYPOINT_TAG);
    if(!GetIsObjectValid(wp)) {
        PrintDebugMessage("Error finding creation waypoint. Tag looked for: " + _ACR_STO_WAYPOINT_TAG, _storageDebugSystem, DEBUG_LEVEL_FATAL);
        return OBJECT_INVALID;
    }

    if( !GetIsObjectValid(GetObjectByTag(_ACR_STO_WAYPOINT_TAG, 1)) ) {
        PrintDebugMessage("Multiple storage object waypoints found! There should only be one. Tag looked for: " + _ACR_STO_WAYPOINT_TAG, _storageDebugSystem, DEBUG_LEVEL_WARNING);
    }

    object obj;

    obj = CreateObject(OBJECT_TYPE_PLACEABLE, _ACR_STO_OBJECT_RESREF, GetLocation(wp), FALSE, sName);
    if(sName != "") {
        SetName(obj, sName);
    }

    if(!GetHasInventory(obj)) {
        PrintDebugMessage("Storage object does not have an inventory.", _storageDebugSystem, DEBUG_LEVEL_FATAL);
    }

    if(!GetIsObjectValid(obj)) {
        PrintDebugMessage("Error creating object of resref " + _ACR_STO_OBJECT_RESREF, _storageDebugSystem, DEBUG_LEVEL_FATAL);
        return OBJECT_INVALID;
    }
    SetPlotFlag(obj, 1);
    AssignCommand(obj, SetIsDestroyable(0, 0, 0));
    SetLocalInt(obj, _EFFECTS_REMOVABLE_LI, bEffectsRemovable);
    return obj;
}

int CanRemoveEffectsFrom(object oObject) {
    return GetLocalInt(oObject, _EFFECTS_REMOVABLE_LI);
}
User avatar
Fionn
Ancient Red Dragon
Posts: 2942
Joined: Sun Jan 04, 2004 7:07 am
Location: Seattle, WA

Post by Fionn »

This gets me to thinking. We have a requirement to maintain a lot of data about PCs that can travel with PCs. What if we create such an object for use with our Portal system, pass it to the next server, and read it to the local DB. Outbound scripts will recreate, attach to PC, grant a passport (more for debugging failed inbounds), and boot the PC. Inbound scripts will move the PC to the desired location, then read the object into the local DB and destroy the object.

We would need some way of validating PCs if thier server went down, else maintaining a copy of the peristant object on the bic (thus defeating the above). If we could write a copy of the local DB to a central DB, this would allow a manual retrieve from the central when needed.
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:This gets me to thinking. We have a requirement to maintain a lot of data about PCs that can travel with PCs. What if we create such an object for use with our Portal system, pass it to the next server, and read it to the local DB. Outbound scripts will recreate, attach to PC, grant a passport (more for debugging failed inbounds), and boot the PC. Inbound scripts will move the PC to the desired location, then read the object into the local DB and destroy the object.

We would need some way of validating PCs if thier server went down, else maintaining a copy of the peristant object on the bic (thus defeating the above). If we could write a copy of the local DB to a central DB, this would allow a manual retrieve from the central when needed.
I see where you are going trying to reduce bic size, but I don't know if thats something thats really going to be significant. I'll store the PC's last location on his bic, information about his pets, and his persistant effects. Not much else I can think of at the moment. Portal destination as well I suppose, but thats something that gets deleted as soon as the portal is done. Can you think of other things which will take a significant amount of space? Pets could, but not many PCs would have more than one or maybe two pets.

BTW, here is the struct I use for storing game locations, from acr_game_loc_i.nss,

Code: Select all

struct GameLocation {
    location lLocation;
    string sAreaTag;
    string sAreaResRef;
    int nServerId;
};
This is called a game location because its a persistant location in the game world. With it you should be able to pinpoint a location anywhere in ALFA, and it will persist across module updates (when typical location variables become invalid). If we ever decide on a way to implement world coordinates, I'll make a acr_world_loc_i.nss and a struct WorldLocation.

Ack, this is horribly off topic from my original post. Damn you Fionn :P
Ronan
Dungeon Master
Posts: 4611
Joined: Sun Feb 20, 2005 9:48 am

Post by Ronan »

Hey guys, is there anyone using storage objects to store items, currently? A few of my scripts do, but I can change those easily. I'm thinking about making the default storage object a waypoint, with a different function to create a merchant object (for both item storage and data storage). The waypoints just use a lot less RAM, which would be nice if we create a single storage object per area for the virtual areas.
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 »

Not as yet, no.
Locked