logo logo

 Back to main page

The NWNX Community Forum

 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
 
Problem Storing some objects, not others.

 
Post new topic   Reply to topic    nwnx.org Forum Index -> Technical support
View previous topic :: View next topic  
Author Message
lothoir



Joined: 13 Dec 2010
Posts: 3

PostPosted: Mon Dec 13, 2010 12:15    Post subject: Problem Storing some objects, not others. Reply with quote

I have two separate scripts, tables and objects to store. The persistent chest storage script works perfectly, however for my death system I can not store the corpse placeable. I have absolutely no idea what I am doing wrong, here are the two scripts along with the xp_mysql log file:


OnDisturb event for the chest:
Code:

#include "nwnx_sql"

int GetNumItems()
{
   int nItems = 1;
   object oItem = GetFirstItemInInventory();
   
   while(GetIsObjectValid(oItem))
         {
         nItems = nItems+1;
         oItem = GetNextItemInInventory();
         }
   return nItems;   
}

void SaveData(object oPC)
{
   
   int nNum = 1;
   object oItem = GetFirstItemInInventory();
   
   while(GetIsObjectValid(oItem))
      {
      SetPersistentObject(oPC,"Slot"+IntToString(nNum),oItem,0,"playerChest");
      nNum = nNum+1;
      oItem = GetNextItemInInventory();
      }
}

void DeleteData(object oPC)

{
   int nCounter;
   for(nCounter = GetNumItems(); nCounter > 0; nCounter --)
      {
      DeletePersistentVariable(oPC,"Slot"+IntToString(nCounter),"playerChest");
      }
}


void main()
{
   
   object oPC = GetLastDisturbed();
   DeleteData(oPC);
   SaveData(oPC);



onDeath script
Code:

#include "nwnx_sql"

void createCorpse(object oPC,location lBody)
{
   string sPlayer =  SQLEncodeSpecialChars(GetPCPlayerName(oPC));
   string sCharacter =  SQLEncodeSpecialChars(GetName(oPC));
   string sLocation =  SQLLocationToString(lBody);
   int iRacialType = GetRacialType(oPC);
   object oCorpse;
   //Create proper corpse
   if(iRacialType == IP_CONST_RACIALTYPE_HALFORC||iRacialType == IP_CONST_RACIALTYPE_HUMANOID_ORC)
   {
      oCorpse = CreateObject(OBJECT_TYPE_PLACEABLE,"sn_pl_orc",lBody);
   } else if(GetGender(oPC) == GENDER_MALE)
   {
      oCorpse = CreateObject(OBJECT_TYPE_PLACEABLE,"sn_pl_corpse_m",lBody);
   } else if(GetGender(oPC) == GENDER_FEMALE)
   {
      oCorpse = CreateObject(OBJECT_TYPE_PLACEABLE,"sn_pl_corpse_f",lBody);
   }
   
   string sCorpseName = GetFirstName(oPC)+" "+GetLastName(oPC);
   SetFirstName(oCorpse,sCorpseName);
   
//Add corpse object to pcCorpseObj table
   SetPersistentObject(oPC,"corpse",oCorpse,0,"pcCorpseObj");
}

void createLootBag(object oPC,location lLootBag)
{
   object oLootBag = CreateObject(OBJECT_TYPE_PLACEABLE,"sn_pl_remains",lLootBag);
   AssignCommand(oLootBag,TakeGoldFromCreature(GetGold(oPC),oPC,FALSE));

   int xCount;
   for (xCount = 1; xCount < 15; xCount++)
     {
      object xItem;
       switch (xCount)
       {
            case 1: xItem = GetItemInSlot(INVENTORY_SLOT_ARMS,oPC); break;
            case 2: xItem = GetItemInSlot(INVENTORY_SLOT_ARROWS,oPC); break;
            case 3: xItem = GetItemInSlot(INVENTORY_SLOT_BELT,oPC); break;
            case 4: xItem = GetItemInSlot(INVENTORY_SLOT_BOLTS,oPC); break;
            case 5: xItem = GetItemInSlot(INVENTORY_SLOT_BOOTS,oPC); break;
            case 6: xItem = GetItemInSlot(INVENTORY_SLOT_BULLETS,oPC); break;
            case 7: xItem = GetItemInSlot(INVENTORY_SLOT_CHEST,oPC); break;
            case 8: xItem = GetItemInSlot(INVENTORY_SLOT_CLOAK,oPC); break;
            case 9: xItem = GetItemInSlot(INVENTORY_SLOT_HEAD,oPC); break;
            case 10: xItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC); break;
            case 11: xItem = GetItemInSlot(INVENTORY_SLOT_LEFTRING,oPC); break;
            case 12: xItem = GetItemInSlot(INVENTORY_SLOT_NECK,oPC); break;
            case 13: xItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC); break;
            case 14: xItem = GetItemInSlot(INVENTORY_SLOT_RIGHTRING,oPC); break;
       }
       if (GetIsObjectValid(xItem))
       {
            AssignCommand(oLootBag,ActionTakeItem(xItem,oPC));
       }
   }
   
   object oItem = GetFirstItemInInventory(oPC);
   while (GetIsObjectValid(oItem))
   {   
      if(GetTag(oItem)=="dmfi_exe_tool"){oItem = GetNextItemInInventory(oPC);}
      else {
      AssignCommand(oLootBag,ActionTakeItem(oItem,oPC));
      oItem = GetNextItemInInventory(oPC);
      }
   }
   SetPersistentObject(oPC,"remains",oLootBag,0,"pcCorpseObj");
}

void main()
{
   object oPC = GetLastPlayerDied();
   location lBody = GetLocation(oPC);
   
   FloatingTextStringOnCreature(GetName(oPC) + " is now dead.",oPC,FALSE);
   
   createCorpse(oPC,lBody);
   location lLootBag = CalcSafeLocation(oPC,lBody,5.0,TRUE,TRUE);
   createLootBag(oPC,lLootBag);
   
   ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), oPC);
   ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectHeal(GetMaxHitPoints(oPC)),oPC);
   AssignCommand(oPC,ActionJumpToObject(GetObjectByTag("sn_fugue")));   
}


xp_mysql log file:
Code:


NWNX MySQL Plugin V.0.0.9
(c) 2007 by Ingmar Stieger (Papillon)
(c) 2008 by virusman
visit us at http://www.nwnx.org
(built using mysql-5.0.27 source)

* Log level set to 2 (everything)
o SCO located at 78f440.
o RCO located at 78f090.
* Hooking successful
* Connecting to server 192.168.1.105
* Plugin initialized.
* Registering under function class SQL
* Executing: SHOW DATABASES
* Executing: SELECT count(*) FROM pwdata
* Returning: 0 (column 0)
* Executing: SELECT count(*) FROM pwobjdata
* Returning: 0 (column 0)
* Executing: SELECT count(*) FROM playerChest
* Returning: 9 (column 0)
* Executing: SELECT count(*) FROM pcList
* Returning: 8 (column 0)
* Executing: SELECT count(*) FROM pcCorpseLoc
* Returning: 0 (column 0)
* Executing: SELECT count(*) FROM pcCorpseObj
* Returning: 0 (column 0)
* Executing: SELECT player FROM pcList WHERE player='Lothoir' AND playerchar ='Ilgrosh'
* Executing: UPDATE pcList SET location='#AREA#sn_loadroom#POSITION_X#      13.548150063#POSITION_Y#      14.089159966#POSITION_Z#      -0.000000000#ORIENTATION#     270.000000000#END#',health=12 WHERE player='Lothoir' AND playerchar='Ilgrosh'
* RCO query: SELECT val FROM playerChest WHERE player='Lothoir' AND tag='Ilgrosh' AND name='Slot1'
* RCO query: SELECT val FROM playerChest WHERE player='Lothoir' AND tag='Ilgrosh' AND name='Slot2'
* Empty RCO resultset
* Executing: DELETE FROM playerChest WHERE player='Lothoir' AND tag='Ilgrosh' AND name='Slot3'
* Executing: DELETE FROM playerChest WHERE player='Lothoir' AND tag='Ilgrosh' AND name='Slot2'
* Executing: DELETE FROM playerChest WHERE player='Lothoir' AND tag='Ilgrosh' AND name='Slot1'
* Executing: SELECT player FROM playerChest WHERE player='Lothoir' AND tag='Ilgrosh' AND name='Slot1'
* SCO query: INSERT INTO playerChest (player,tag,name,val,expire) VALUES('Lothoir','Ilgrosh','Slot1',%s,0)
* Executing: SELECT player FROM playerChest WHERE player='Lothoir' AND tag='Ilgrosh' AND name='Slot2'
* SCO query: INSERT INTO playerChest (player,tag,name,val,expire) VALUES('Lothoir','Ilgrosh','Slot2',%s,0)
* Executing: SELECT player FROM pcCorpseObj WHERE player='Lothoir' AND tag='Ilgrosh' AND name='corpse'
* Executing: SELECT player FROM pcCorpseObj WHERE player='Lothoir' AND tag='Ilgrosh' AND name='remains'


If anyone could help point me toward an answer I would be extremely grateful!
Back to top
View user's profile Send private message
Dethia



Joined: 01 Oct 2009
Posts: 23

PostPosted: Tue Dec 21, 2010 6:06    Post subject: Reply with quote

well I am able to save corpse objects, will take a look at your code but just wanted to say it's doable.

Ok I took a look at your code and I don't know why you are doing all that crazy stuff. You are able to simply copy the pc's corpse and treat the copy as an object, here is the code I use:

Code:
void DEATH_SpawnPCCorpse(object oPC, location lLoc)
{
   object   oCorpse   = CopyObject(oPC, lLoc);   //Copy the player object
   string   sCharID   = GetTag(oPC);   //Get the character's ID

   EmptyInventory(oCorpse, TRUE, TRUE);   //Destroys all items in copy's inventory
   //Kill the copy to leave a corpse behind, this way the corpse looks just like the PC
   ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(0, 0, 1), oCorpse);
   //Prevent the corpse from decaying until PC is ressurected or the corpse is taken
   AssignCommand(oCorpse, SetIsDestroyable(FALSE, FALSE, FALSE));
   //Set the dead pc as a local object on the corpse for recovery as well as the char's ID
   SetLocalObject(oCorpse, "dead_pc", oPC);
   SetLocalString(oCorpse, "dead_pc_id", sCharID);

   //Before we save the corpse to the DB check if there is already an entry for one
   SQLExecDirect("select character_id from pc_corpses where character_id = " + sCharID);
   if(SQLFetch())   //If there is an existing entry simply update its location
   {
      SQLExecDirect("update pc_corpses set corpse_location = '"   +
               SQLLocationToString(lLoc) + "' where character_id = " + sCharID + ";");
   }
   else   //If no previous record exists add one
   {//Save the corpse in the database after 6 seconds (to prevent save of equipment)
      DelayCommand(6.0f, SQLSCORCOExec("insert into pc_corpses (character_id, "   +
         "first_name, last_name, corpse_location, corpse_object) values ("      +
         sCharID + ", "                                       +
         "'" + SQLEncodeSpecialChars(GetFirstName(oPC)) + "', "         +
         "'" + SQLEncodeSpecialChars(GetLastName(oPC)) + "', "         +
         "'" + SQLLocationToString(lLoc) + "', %s)"                  ));
      DelayCommand(6.5f, SQLStoreObject(oCorpse));   //Store the actual object   
   }
   //Create an invisible placeable on top of the corpse for living pc's to interact with
   object   oCorpsePlc   = CreateObject(64, DEATH_CORPSE_PLAC, GetLocation(oCorpse));
   //Set the placeable's name to PC's name
   SetFirstName(oCorpsePlc, GetName(oPC) + " (P)");
   //Set the corpse as a local object on the placeable
   SetLocalObject(oCorpsePlc, "corpse", oCorpse);
}


You must empty the copied object's inventory prior to killing it, you must also delete all of its equipped items and gold (otherwise it will drop them). If you need additional help or have questions send me a PM.
Back to top
View user's profile Send private message
lothoir



Joined: 13 Dec 2010
Posts: 3

PostPosted: Tue Dec 21, 2010 11:24    Post subject: Reply with quote

I'm sorry, I should have explained what I'm doing: When a player dies I want to strip all of their gold and items and put it in a loot container that will appear next to their corpse, which will be a placeable without an inventory. Clicking on the corpse would destroy the placeable corpse and put a heavy object into their inventory, which can then be hauled back to town for some kind cleric to cast Raise Dead or Resurrection.

I want both the corpse and the loot container (including all of the loot within!) to be persistent between server resets. The module OnLoad script would read from the database and spawn the appropriate corpses and loot containers around the server where necessary.

I plan to eventually implement 'decay' where the corpses would turn to bone, and then eventually dust, as well allow 'burials' for rogues and assassins to hide their targets when all is done.
Back to top
View user's profile Send private message
Dethia



Joined: 01 Oct 2009
Posts: 23

PostPosted: Tue Dec 21, 2010 13:18    Post subject: Reply with quote

well what you describe is still doable and it's doable both your way and my way.

If you look at my example I copy the pc, strip their items and spawn an invisible placeable for ppl to interact with. People can click on the placeable at which point they get a conversation to either pick up the corpse or leave it alone.

The main thing is that I do spawn 2 objects one a placeable and one the corpse.

Now you don't want to just strip items from the pc but add them to the inventory of some placeable which is fine.

What you need to be sure to do right though is the following. As far as I know you can't just save a container and all of it's contents with it (I may be wrong but I never tried). You would need to save the container and each individual item inside it. This is all doable and not too difficult either. But that's not all, if you want to avoid duping items, you need change the tag of every item you store in the database (this mostly pertains to stackable items), generally appending the tag with the item's id is fine. When the item is removed from the chest just return the tag name to normal.

Now looking at your script you are using a SetPersistentObject function which I am not familiar with sadly, I use the SCO/RCO functions.

My advice is for the corpse object since you have pre-made placeables you do not need to store the corpse but only it's resref. Just store the resref for the corpse and use the createobject function. You would simply need to make an OnModuleStart script that would load all the corpses when the module starts.

Lastly take a look at my thread:
http://www.nwnx.org/phpBB2/viewtopic.php?t=1515
Maybe it will help you in some way. If you have more specific questions don't hesitate to ask.

EDIT: I also think you shouldn't bother saving the container. Just have a set placeable, chest or whatnot that you will spawn near the corpse with the items being populated from the database. Give each unique corpse a unique ID and link the items to that ID. So all in all you only need to store the items and the resref of a specific corpse for a particular character.
Back to top
View user's profile Send private message
lothoir



Joined: 13 Dec 2010
Posts: 3

PostPosted: Tue Dec 21, 2010 16:51    Post subject: Reply with quote

I used an nwnx_sql include file I found on these forums somewhere; here are the relevant functions:
Code:
void SetPersistentObject(object oOwner, string sVarName, object oObject, int iExpiration =
                         0, string sTable = "pwobjdata")
{
    string sPlayer;
    string sTag;

    if (GetIsPC(oOwner))
    {
        sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oOwner));
        sTag = SQLEncodeSpecialChars(GetName(oOwner));
    }
    else
    {
        sPlayer = "~";
        sTag = GetTag(oOwner);
    }
    sVarName = SQLEncodeSpecialChars(sVarName);

    string sSQL = "SELECT player FROM " + sTable + " WHERE player='" + sPlayer +
        "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
    SQLExecDirect(sSQL);

    if (SQLFetch() == SQL_SUCCESS)
    {
        // row exists
        sSQL = "UPDATE " + sTable + " SET val=%s,expire=" + IntToString(iExpiration) +
            " WHERE player='" + sPlayer + "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
        SQLSCORCOExec(sSQL);
        SQLStoreObject (oObject);
    }
    else
    {
        // row doesn't exist
        sSQL = "INSERT INTO " + sTable + " (player,tag,name,val,expire) VALUES" +
            "('" + sPlayer + "','" + sTag + "','" + sVarName + "',%s," + IntToString(iExpiration) + ")";
        SQLSCORCOExec(sSQL);
        SQLStoreObject (oObject);
    }
}

string SQLEncodeSpecialChars(string sString)
{
    return NWNXGetString("SQL", "GET ESCAPE STRING", sString, 0);
}

void SQLSCORCOExec(string sSQL)
{
    NWNXSetString("SQL", "SETSCORCOSQL", sSQL, 0, "");
}

void SQLStoreObject(object oObject)
{
    StoreCampaignObject("NWNX", "-", oObject);
}

object SQLRetrieveObject(location lLocation, object oOwner = OBJECT_INVALID, string sMode="-")
{
    return RetrieveCampaignObject("NWNX", sMode, lLocation, oOwner);
}


The big thing I want to point out though is that the SetPersistentObject() function is working. The chest script I posted works absolutely perfectly, which is why I'm so confused as to why the corpse object will not be stored. The corpse is clickable, but has no inventory, so that's not the problem.

The reason I want to store the corpse object to the database is because I set the corpse's name to the character's and will eventually be adding onto the script to change the description of the corpse placeable so that people passing by with be able to examine the corpse for race and gender. I'd also like to later add in the ability for deceased characters to set a general description of their corpse from the Fugue. It will require DM policing to prevent abuse, but it would be worth it, I think.

When I've figures out the problem with storing the corpse in the database I'll move onto the loot containers that appear beside the corpse, which is also rather important because it will allow bandits to attack and rob people, which gives the law enforcement and paladiny types to do their thing.

How does changing the tags of items as they are stored in the database help prevent duping, though?
Back to top
View user's profile Send private message
eeriegeek



Joined: 07 Jan 2008
Posts: 59

PostPosted: Tue Dec 21, 2010 21:00    Post subject: Reply with quote

Virusman has just recently implemented placeable object storage http://nwnx.org/phpBB2/viewtopic.php?t=1083 for Linux. Is there a possibility the version of NWNX you are using doesn't support placeable storage (i.e. only supports item and creature storage)?
Back to top
View user's profile Send private message
Dethia



Joined: 01 Oct 2009
Posts: 23

PostPosted: Sat Dec 25, 2010 17:31    Post subject: Reply with quote

well I have never tried to save placeables but we have been using persistent placeables on the server for years. Using resrefs imo is much better than storing a placeable object.

Again about the corpse you know you can store things like the player's name and the players description in the sql database as well it's just 2 text fields. Objects are big blob fields that often take up more memory. I will post the script we use to store persistent placeables as an example I hope it will at least help you with your issue.



Code:

void main()
{
    object      oPC         = GetItemActivator();
    object      oItem      = GetItemActivated();
    object      oTarget      = GetItemActivatedTarget();
    location   lTarget      = GetItemActivatedTargetLocation();
   
   //Below we check that the player is in his/her own house
   object      oArea      = GetArea(oPC);
   string      sAreaTag   = GetTag(oArea);
   
   //CREATE DB TABLE IF IT DOES NOT EXIST
   SQLExecDirect("select count(*) from pc_placeables");
   if(!SQLFetch())   //If it fails the database table does not exist, so we'll create one
   {
      SQLExecDirect(
      "CREATE TABLE `nwnx_test`.`pc_placeables`"                  +
      "("                                                +
        "`player` VARCHAR(64) NOT NULL, "                        +
      "`public_cd_key` VARCHAR(64) NOT NULL, "                  +
      "`plac_owner` TEXT NOT NULL, "                           +
      "`plac_name` TEXT NOT NULL, "                           +
      "`plac_tag` TEXT NOT NULL, "                           +
      "`plac_location` VARCHAR(300) NOT NULL, "                  +
      "`plac_resref` TEXT NOT NULL, "                           +
      "`plac_id` INTEGER(6) UNSIGNED NOT NULL AUTO_INCREMENT, "      +
      "PRIMARY KEY (`plac_id`) "                              +
      ")"                                                +
      "ENGINE = InnoDB;"   );
   }   
   //End of - CREATE DB TABLE

   if(GetIsLocationValid(lTarget))
   {
      //CREATE THE PLACEABLE IN-GAME
      string      sPlacTag   = GetLocalString(oItem, "sTag");
      string      sPlacResRef = GetLocalString(oItem, "sResRef");
      //The above lines get the tag and resref of the placeable the player put down.
   
      //Now that all the necessary properties are defined, create the object      
      object      oPlaceable   = CreateObject(OBJECT_TYPE_PLACEABLE, sPlacResRef, lTarget,
                           FALSE, sPlacTag);
      //End of - CREATE THE PLACEABLE IN-GAME

      //SAVE PLACEABLE IN DB
      SQLExecDirect("insert into pc_placeables (player, public_cd_key, "
      +"plac_owner, plac_name, plac_tag, plac_location, plac_resref) values"
      +" ('" + SQLEncodeSpecialChars(GetPCPlayerName(oPC)) + "',"
      +"'" + SQLEncodeSpecialChars(GetPCPublicCDKey(oPC)) + "',"
      +"'" + SQLEncodeSpecialChars(GetName(oPC)) + "',"
      +"'" + SQLEncodeSpecialChars(GetName(oPlaceable)) + "', "
      +"'" + SQLEncodeSpecialChars(GetTag(oPlaceable)) + "',"
      +"'" + SQLLocationToString(lTarget) + "',"
      +"'" + SQLEncodeSpecialChars(GetResRef(oPlaceable)) + "')"   );
      //End of - SAVE PLACEABLE IN DB

      //ASSIGN OWNERSHIP VARIABLES TO PLACEABLE
      SQLExecDirect("select last_insert_id() from pc_placeables");   //Get latest entry
      SQLFetch();
      int iPlac_ID = StringToInt(SQLGetData(1));
      SetLocalInt(oPlaceable, "iPlac_ID", iPlac_ID);
      SetLocalInt(oPlaceable, "iPC_Owned", TRUE);
      SetLocalString(oPlaceable, "sPlayer", GetPCPlayerName(oPC));
      //End of - ASSIGN OWNERSHIP VARIABLES TO PLACEABLE

      //And finally destroy the item that was used to set-up the placeable
      DestroyObject(oItem);
   }
}


The placeables in this example are placed by in-game items hence oPC is the item activator, in your case this would fire from when the PC hit's the respawn button (or when they die) so it'd just be GetLastPlayerDied() or something appropriate.

Secondly for the location it'd just be the location of the PC (before they are ported to the fugue plane).

string sPlacTag = GetLocalString(oItem, "sTag");
string sPlacResRef = GetLocalString(oItem, "sResRef");
These two lines are just something we need, in your case you would probably have different placeables for different corpses, we extract the tag/resref from the activated item in your case it would be a few if conditionals depending on the pc's race/gender.

Overall when using CopyObject on a PC it will copy their appearance into an npc with all of their items (it would be alive though) thus saving you the trouble of copying them (albeit you would then need to delete the items in the pc's inventory so they aren't duped. Well hope this helps you a bit.
EDIT: THe reason why CopyObject is nice is that the copied NPC object will have exactly the same appearance as the PC (and gender). Thus you don't need to give any description, players can tell what it is just by looking at it. And if they happen to know the PC they'd know it was him or her since it looks the same.

edit#2: For completion, in order for the placeables to appear in the game after a restart they have to be loaded in from the table during the module startup. Generally we add a line in our OnModuleStart script that executes the loading script (ExecuteScript("script_name))

Code:

void main()
{
   SQLExecDirect("select * from pc_placeables");
   while(SQLFetch())
   {   //First retreive the necessary data
      int         iPlac_ID   = StringToInt(SQLGetData(8));
      string      sPlacTag   = SQLGetData(5);
      string      sPlacResRef   = SQLGetData(7);
      location   lLocation   = SQLStringToLocation(SQLGetData(6));
      
      //create the placeable using the retrieved values
      object   oPlaceable = CreateObject(OBJECT_TYPE_PLACEABLE, sPlacResRef, lLocation, FALSE,
                           sPlacTag);
      //assign some variables to the placeable as identifiers for future use
      SetLocalInt(oPlaceable, "iPlac_ID", iPlac_ID);
      SetLocalInt(oPlaceable, "iPC_Owned", TRUE);
      SetLocalString(oPlaceable, "sPlayer", SQLGetData(1));
   }
}
Back to top
View user's profile Send private message
Gryphyn



Joined: 20 Jan 2005
Posts: 431

PostPosted: Sat Jan 01, 2011 1:32    Post subject: Reply with quote

Firstly there is a know issue with Get/SetLocation - the generated string can exceed the length of the buffer allocation.
You need to increase the length of the buffer, or shorten the location string. (eg #POSITION_X# becomes #X# etc - with relevant code changes)

Secondly, the object being stored has a capped data length, while this is fine for most objects, quite a few (a lot) exceed this limit.

-and another plug-
I stopped work on my SQLServer plugin, but it has all the code changes needed to make NWNX database friendly - removing all the 'gotchas' and limitations of the original plugin. It's been so long, and no-one wants the improvements, including a, by far, easier NWScript command set (for the database novice) and functionality that fully supports the ODBC API.
PS. It's fully backwards compatible, so NWScript for MySQL will also work (without change) on SQLServer2005/8 (Express)

Cheers
Gryphyn
Back to top
View user's profile Send private message
MetaPhaze



Joined: 03 Jun 2007
Posts: 30
Location: USA

PostPosted: Sat Jan 01, 2011 5:21    Post subject: Reply with quote

I haven't given much to the NWN community, I gave up on scripting and module building shortly after NWN was released because of the flaws that were in the multi-player system for the game... bioware later fixed a lot of the issues and some friends of mine got me back into NWN.

I spent 3 years developing one of the most advanced servers around using the neverwinter nights extender, and I have used or have plans to use every single plugin that nwnx2 supports.
I've added many things to NWN that many people didn't think possible, or that people thought would create server side lag on a server, or be too complicated to implement.

We have a great persistent world that no one plays much anymore, it will probably be the last nwn server running in the end.
I've written my own functions for my aps_include.nss file to handle the problems I've found with the standard aps functions...
We use these functions on our persistent world and have for the last 4 years. It's tested and there isn't much difference in how it works and how the original functions worked... in fact you won't notice much difference in locations and to the players it will seem exactly as they placed it...
We're dealing with floats and when you get to micro, nano, and pico position data your really not losing much... and it's not noticeable in the game.

These functions simply shorten the length of the floating point number to the right of the decimal point.

Have fun hope this helps you.

MetaPhaze

P.S.

feel free to use these functions however you wish, add to them, change them, distribute them, and please remember me in your code.

// written by MetaPhaze for aps_include.nss based on work by the aps team and nwnx2



string mpVectorToString(vector vVector)
{
return "#POSITION_X#" + FloatToString(vVector.x) + "#POSITION_Y#" + FloatToString(vVector.y) + "#POSITION_Z#" + FloatToString(vVector.z) + "#END#";
}

vector mpStringToVector(string sVector)
{
float fX, fY, fZ;
int iPos, iCount;
int iLen = GetStringLength(sVector);

if (iLen > 0)
{
iPos = FindSubString(sVector, "#POSITION_X#") + 12;
iCount = FindSubString(GetSubString(sVector, iPos, iLen - iPos), "#");
fX = StringToFloat(GetSubString(sVector, iPos, iCount));

iPos = FindSubString(sVector, "#POSITION_Y#") + 12;
iCount = FindSubString(GetSubString(sVector, iPos, iLen - iPos), "#");
fY = StringToFloat(GetSubString(sVector, iPos, iCount));

iPos = FindSubString(sVector, "#POSITION_Z#") + 12;
iCount = FindSubString(GetSubString(sVector, iPos, iLen - iPos), "#");
fZ = StringToFloat(GetSubString(sVector, iPos, iCount));
}

return Vector(fX, fY, fZ);
}

string mpLocationToString(location lLocation)
{
object oArea = GetAreaFromLocation(lLocation);
vector vPosition = GetPositionFromLocation(lLocation);
float fOrientation = GetFacingFromLocation(lLocation);
string sReturnValue = "";

if (GetIsObjectValid(oArea))
sReturnValue = "#AREA#" + GetTag(oArea) + "#POSITION_X#" + FloatToString(vPosition.x) + "#POSITION_Y#" + FloatToString(vPosition.y) + "#POSITION_Z#" + FloatToString(vPosition.z) + "#ORIENTATION#" + IntToString(FloatToInt(fOrientation)) + "#END#";

return sReturnValue;
}

location mpStringToLocation(string sLocation)
{
location lReturnValue;
object oArea;
vector vPosition;
float fOrientation, fX, fY, fZ;

int iPos, iCount;
int iLen = GetStringLength(sLocation);

if (iLen > 0)
{
iPos = FindSubString(sLocation, "#AREA#") + 6;
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
oArea = GetObjectByTag(GetSubString(sLocation, iPos, iCount));

iPos = FindSubString(sLocation, "#POSITION_X#") + 12;
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
fX = StringToFloat(GetSubString(sLocation, iPos, iCount));

iPos = FindSubString(sLocation, "#POSITION_Y#") + 12;
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
fY = StringToFloat(GetSubString(sLocation, iPos, iCount));

iPos = FindSubString(sLocation, "#POSITION_Z#") + 12;
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
fZ = StringToFloat(GetSubString(sLocation, iPos, iCount));

vPosition = Vector(fX, fY, fZ);

iPos = FindSubString(sLocation, "#ORIENTATION#") + 13;
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
fOrientation = StringToFloat(GetSubString(sLocation, iPos, iCount));
int iOrientation = FloatToInt(fOrientation);
fOrientation = IntToFloat(iOrientation);
lReturnValue = Location(oArea, vPosition, fOrientation);
}

return lReturnValue;
}

Here is the implementation:

void SetPersistentLocation(object oObject, string sVarName, location lLocation, int iExpiration=0, string sTable="pwdata")
{
SetPersistentString(oObject, sVarName, mpLocationToString(lLocation), iExpiration, sTable);
}

location GetPersistentLocation(object oObject, string sVarName, string sTable="pwdata")
{
return mpStringToLocation(GetPersistentString(oObject, sVarName, sTable));
}


Last edited by MetaPhaze on Sat Jan 01, 2011 5:27; edited 3 times in total
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address Yahoo Messenger
MetaPhaze



Joined: 03 Jun 2007
Posts: 30
Location: USA

PostPosted: Sat Jan 01, 2011 5:23    Post subject: Reply with quote

sorry for the indentation problem... seems that the forums stripped my tab spacings...
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address Yahoo Messenger
MetaPhaze



Joined: 03 Jun 2007
Posts: 30
Location: USA

PostPosted: Sat Jan 01, 2011 5:23    Post subject: Reply with quote

Oh, and HAPPY NEW YEAR!
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address Yahoo Messenger
Display posts from previous:   
Post new topic   Reply to topic    nwnx.org Forum Index -> Technical support All times are GMT + 2 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group