Transfering data between servers

Forum for scripters of NWN material and third party applications.
Post Reply
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Transfering data between servers

Post by Orleron »

I made a system to transfer data between servers using PC hides. If we adopted it, it would be useful in sharing data across servers, such as crafting skill data and scripted quest data.

1) All PC's get a hide if they don't already have one.
2) When portalling, portal code writes important variables to the hide (using functions I wrote below).
3) Upon arrival, the script on that server (onenter, or onarea enter) takes the variables off the hide, writes them to where they need to go, and deletes them off the hide.


I made some functions below to do this. Let me know if you see anything blaringly wrong with them. They do compile.

Code: Select all

//data_trans_inc.nss
//By Josh Simon
//June 21st, 2004
//File governs data transfer between CoPaP servers by taking data
//from PC hide and loading to or from module


#include "ars_include"

// int constants
const int NULL = 0;

// Gets a local integer from a PC's hide.  Returns NULL if PC has no hide.
int GetLocalHideInt(object oPC, string sVarName);

//Sets a local integer with sVarName on the PC's hide.  If PC has no hide,
//it creates one and then calls itself again.
void SetLocalHideInt(object oPC, string sVarName, int iValue);

//Deletes the local integer with name sVarName on the PC's hide
void DeleteLocalHideInt(object oPC, string sVarName);

//Takes an int variable from the PC's hide, and writes it into pwdata table
//of the database.  Deletes the variable off the hide when done.
void TransferHideIntToDB(object oPC, string sVarName);

//Takes all of the player's crafting skills (names and xp values) from the
//database and writes them onto the hide with local variable name being
//the skill, and the value being the amount of xp in that skill
void TransferCraftingSkillsToHide(object oPC);

//Takes ONE crafting skill variable off the hide and writes it into the
//crafting skill table in the database.  Deletes the variable off the hide
//when finished.
void TransferCraftingSkillToDB(object oPC, string sSkill);



//////////////////////////////////////////////////
//GetLocalHideInt(object oPC, string sVarName)
//////////////////////////////////////////////////

int GetLocalHideInt(object oPC, string sVarName)
{
    object oHide = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);
    int iNumber;

    if (GetIsObjectValid(oHide)){

       iNumber = GetLocalInt(oHide, sVarName);

       return  iNumber;
       }

    else

        WriteTimestampedLogEntry("HIDE VARIABLE ERROR: "+GetName(oPC)+" does not have a hide.");

        return NULL;
}


//////////////////////////////////////////////////
//void SetLocalHideInt(object oPC, string sVarName, int iValue)
//////////////////////////////////////////////////

void SetLocalHideInt(object oPC, string sVarName, int iValue)
{

    object oHide = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC); 

    if (GetIsObjectValid(oHide)) 

        SetLocalInt(oHide, sVarName, iValue); 

    else{ 

         oHide = CreateItemOnObject("no_pc_hide", oPC); 

         DelayCommand(0.1,AssignCommand(oPC,ActionEquipItem(oHide,INVENTORY_SLOT_CARMOUR))); 

         SetLocalHideInt(oPC, sVarName, iValue); 

         WriteTimestampedLogEntry("HIDE VARIABLE ERROR: "+GetName(oPC)+" does not have a hide."); 
        } 
}


//////////////////////////////////////////////////
//void DeleteLocalHideInt(object oPC, string sVarName)
//////////////////////////////////////////////////

void DeleteLocalHideInt(object oPC, string sVarName)
{
    object oHide = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);

    if (GetIsObjectValid(oHide))

        DeleteLocalInt(oHide, sVarName);

    else

        WriteTimestampedLogEntry("HIDE VARIABLE ERROR: "+GetName(oPC)+" does not have a hide.");
}


//////////////////////////////////////////////////
//void TransferHideIntToDB(object oPC, string sVarName)
//////////////////////////////////////////////////

void TransferHideIntToDB(object oPC, string sVarName)
{
    int iHideInt = GetLocalHideInt(oPC, sVarName);

    SetPersistentInt(oPC, sVarName, iHideInt);

    DeleteLocalHideInt(oPC, sVarName);
}


//////////////////////////////////////////////////
//void TransferCraftingSkillsToHide(object oPC)
//////////////////////////////////////////////////

void TransferCraftingSkillsToHide(object oPC)
{
    int iSkillCount = ARS_GetSkillCount();
    int i;
    int iXP;

    string sKey;

    ARS_FetchPlayerSkills(oPC);

    for (i=0; i<iSkillCount ; i++)
    {
        sKey = ARS_GetSkillName(i);

        iXP = ARS_GetPlayerXP(oPC, sKey);

        SetLocalHideInt(oPC, sKey, iXP);
    }
}


//////////////////////////////////////////////////
//void TransferCraftingSkillToDB(object oPC, string sSkill)
//////////////////////////////////////////////////

void TransferCraftingSkillToDB(object oPC, string sSkill)
{
    int iXP = GetLocalHideInt(oPC, sSkill);

    string sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oPC));
    string sCharName = SQLEncodeSpecialChars(GetName(oPC));

    if (iXP > ARS_GetPlayerXP(oPC, sSkill)){

        SQLExecDirect("SELECT skill FROM tradeskills WHERE player='" + sPlayer +
             "' AND charname='" + sCharName + "' AND skill='" + sSkill + "'");

        if (SQLFetch() == SQL_SUCCESS)
        {
            SQLExecDirect("UPDATE tradeskills SET xp=" + IntToString(iXP) +
                      " WHERE player='" + sPlayer + "' AND charname='" +
                      sCharName + "' AND skill='" + sSkill + "'");
        }
        else
        {
            SQLExecDirect("INSERT INTO tradeskills (player,charname,skill,xp,expire) " +
                      "VALUES ('" + sPlayer + "','" + sCharName + "','" +
                      sSkill + "'," + IntToString(iXP) + ",365)");
        }

    }
    else
        WriteTimestampedLogEntry("ERROR: Skill in database is greater than skill on hide.");

    DeleteLocalHideInt(oPC, sSkill);
}



Last edited by Orleron on Mon Jun 21, 2004 1:43 pm, edited 2 times in total.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Jeff
World Leader: Ea
Posts: 130
Joined: Wed Nov 19, 2003 8:36 pm
Location: EA
Contact:

Post by Jeff »

Orleron,
You code looks very good, I am impressed at your coding skill.
It's funny you decided to go ahead and do this. In my work with Sylvan to get the ARS working in EA we talked about doing something like this to Alpha test the theory.

I think one thing is missing in your functions though. I would recommend a check of the players existing skill levels before setting the new values. This check would ensure that only the high values are kept. This would be very important in the event a PC was to somehow enter a world with lower skill settings saved on the hide than what was already in the database.
As I told Sylvan, I am happy to help with the testing of this system.

Well done.

What are your thoughts on a

GetLocalHideHash
SetLocalHideHash
DeleteLocalHideHash

set of functions?
Come by and see us at:
http://hanus.is-a-geek.net/
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

I think one thing is missing in your functions though. I would recommend a check of the players existing skill levels before setting the new values.
Ah, good point. I put in the DeleteLocalVariable statements at the end of those functions to ensure that the variable is gone in case something tries to read it again to use it to overwrite a better value.

But, yeah, I will put in a comparison of the DB value and the hide value and take whichever is greater. That will make it doubly safe.

I can throw in all the hashet stuff too, and maybe even some string and floats as well for the final version.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Ok, I changed the code at the top to check if the crafting skill in the database is greater than the one on the hide. If it is, the skill on the hide will not overwrite the database value.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Jeff
World Leader: Ea
Posts: 130
Joined: Wed Nov 19, 2003 8:36 pm
Location: EA
Contact:

Post by Jeff »

I like it.
Nice touch putting the error in the log too.
Come by and see us at:
http://hanus.is-a-geek.net/
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Ok, new version is ready to test. It's in the Avlis Systems directory: IntrSrvrDataTrans.erf.

It has float and string support. Also, I took all of Sylvan's hash set functions and made variations of them that will look at the hash set on the hides if the function is used on a PC. Not a big deal from a coding perspective... I just rerouted where the function goes to. But it's convenient if you use hash sets.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Jeff
World Leader: Ea
Posts: 130
Joined: Wed Nov 19, 2003 8:36 pm
Location: EA
Contact:

Post by Jeff »

If I could be so bold.

Code snipit for the Module on enter:

Code: Select all

 object oPc = GetEnteringObject();
 int rc;
 string sSkill;
//look up all the skills that are in the database
  SQLExecDirect("SELECT skill FROM ars_skills");
//loop over each skill and update player record
         rc = SQLFetch();
       while(rc == SQL_SUCCESS)
       {
       sSkill = SQLGetData(1);
       TransferCraftingSkillToDB(oPc, sSkill);
       rc = SQLNextRow();
       }
Come by and see us at:
http://hanus.is-a-geek.net/
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Yep, that's one way to do it.

The long way would be:

Code: Select all

if (Get Tag(GetArea(oPC) == "Whatever tag of portal area is"){ 

    TransferCraftingSkillToDB(oPC, "Blacksmithing"); 

    TransferCraftingSkillToDB(oPC, "Carpentry"); 

    TransferCraftingSkillToDB(oPC, "Tailoring"); 

    TransferCraftingSkillToDB(oPC, "Weaponcrafting"); 

    TransferCraftingSkillToDB(oPC, "Armorcrafting"); 

    TransferCraftingSkillToDB(oPC, "Alchemy"); 

    TransferCraftingSkillToDB(oPC, "Herbalism"); 

    TransferCraftingSkillToDB(oPC, "Jewelcrafting"); 

    TransferCraftingSkillToDB(oPC, "Mining"); 
    }
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Jeff
World Leader: Ea
Posts: 130
Joined: Wed Nov 19, 2003 8:36 pm
Location: EA
Contact:

Post by Jeff »

Well... we have the code as posted at the very top in our module now.
I can get that erf and update later today. Thanks for adding the other functions.
I guess all we need now is to get Hala to import the code and we can do some real testing Avlis->Hala->EA_lov->Hala->Avlis.

So what say you Drakuul.....?
*wink wink nod nod*
Come by and see us at:
http://hanus.is-a-geek.net/
Drakuul
Groundling
Posts: 120
Joined: Tue Feb 03, 2004 8:18 am

Post by Drakuul »

Yep, we've got some problems with our Cskin.nss script at present - it removes the skin at first login and replaces it if you relog - working on that problem before adding new cskin codes :)
*Your superior intelligence can not defeat my puny weapons*
_LuCkY_
Noobie
Posts: 3
Joined: Mon Jun 21, 2004 9:24 am

Post by _LuCkY_ »

Actually all servers should have that problem. The problem is that cskin_include.nss removes all creature hides it doesn't recognize. Every subrace that has a creature hide created with Autobic, has a hide that doesn't get recognized (ie all hides that start with "l404_sr_"). A simple solution (the one thats used on Hala now) is to change the following function in cskin_include (the code between those enters was added):

Code: Select all

void ApplyRacialSkin(object oPC)
{
    if(CSKIN_DEBUG)SendMessageToPC(oPC,"DEBUG: ApplyRacialSkin running.");
    string sHide = GetHideResRef(oPC);
    object oHide = GetItemInSlot(INVENTORY_SLOT_CARMOUR,oPC);
    if(oHide != OBJECT_INVALID)
    {
        if(CSKIN_DEBUG)SendMessageToPC(oPC,"DEBUG: Hide already present.");
        if(GetResRef(oHide)==sHide)
        {
            if(CSKIN_DEBUG)SendMessageToPC(oPC,"DEBUG: Current hide is appropriate hide, exiting.");
            return;
        }





        else if(GetStringLeft(GetResRef(oHide), 8)=="l404_sr_")
        {
            if(CSKIN_DEBUG)SendMessageToPC(oPC,"DEBUG: Using hide from Autobic system.");
            return;
        }





        else
        {
            if(CSKIN_DEBUG)SendMessageToPC(oPC,"DEBUG: Current hide is incorrect, destroying current hide.");
            SetPlotFlag(oHide,FALSE);
            AssignCommand(oPC,ActionUnequipItem(oHide));
            AssignCommand(oPC,DestroyObject(oHide));
        }
    }
    ApplyHideToPC(oPC,sHide);

}
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Also, you must have your ILR checker turned off. If not, it will remove hides from people upon login, no matter what you do.

We've replaced the ILR checker with a coded one made by Red Golem, which is also available in the Avlis Systems directory.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
hylia
Planewalker
Posts: 40
Joined: Tue Nov 25, 2003 2:55 pm

Post by hylia »

With all the discussion over creature hides lately, I was wondering--has there been any progress on this front--using them to store variables for transfer between servers?
hermyt
World Leader - LoT: Moonsea
Posts: 65
Joined: Fri Nov 21, 2003 9:41 pm
Contact:

Will be on it soon

Post by hermyt »

I'll be probably testing hopefully with rockhome soon. I've just installed the ACS and gone through the avlis zero and exported all the missing resrefs and items for crafting that aren't in the original crafting package but are part of the recipes.

Everything should be working good for the crafting, I just have to do placeables around for pc's to use and start laying resources. Should be hopefully next week will have the hides persistent code imported and hopefully do some testing.

On that front if testing goes well and this code all works well, hopefully the other copap worlds will integrate it for the betterment of pc's in general.

HerMyT
Themicles
Leader: Tairis'nàdur & CoPaP Hak-Master
Posts: 887
Joined: Tue Nov 25, 2003 11:26 am
Location: Michigan
Contact:

Post by Themicles »

If Avlis wants to do any testing, I'll volunteer Tairis'nadur.
Not only do I already have the ACS installed and running, I already have a few characters of my own that have crafting XP on both servers.

-Themicles
"A wise man does not dwell on his past. He learns from it, he grows from it, and then moves ahead into his future." -me
Post Reply