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 
 
Weird nwnx_hashset crash, need help here @_@

 
Post new topic   Reply to topic    nwnx.org Forum Index -> Windows technical support
View previous topic :: View next topic  
Author Message
pethrowilo



Joined: 21 Dec 2014
Posts: 7
Location: China

PostPosted: Tue Mar 15, 2016 21:47    Post subject: Weird nwnx_hashset crash, need help here @_@ Reply with quote

Code:
#include "nwnx_hashset"

const string HSHASH = "HS_OV_HASHSET_TESTHASHSET";

int NOP = 33;
int NED = 100;

void TestInvalidValue(int NTARG);

void main()
{
    object oPC = GetPlaceableLastClickedBy();
    AssignCommand(oPC, ClearAllActions());
    int n;
    for (n = NOP; n <= NED; n++)
    {
        WriteTimestampedLogEntry("TESTING " + IntToString(n));
        TestInvalidValue(n);
    }
}

void TestInvalidValue(int NTARG)
{
    object oS = OBJECT_SELF;
    HashSetCreate(oS, HSHASH);
    int n;
    for (n = 1; n <= NTARG; n++)
    {
        HashSetSetLocalString(oS, HSHASH, IntToString(n), IntToString(d12()));
    }

    string sKey;
    n = 1;
    for (sKey = HashSetGetFirstKey(oS, HSHASH); "" != sKey; sKey = HashSetGetNextKey(oS, HSHASH))
    {
        if (NTARG == n)//if (2 == n)
        {
            //WriteTimestampedLogEntry("CATCH!");
            //SetLocalInt(oS, "TESTVALUE", Random(32767));
            HashSetDeleteVariable(oS, HSHASH, sKey);
            // break;
        }
        else
        {
            //WriteTimestampedLogEntry("PASS!");
        }
        n++;
    }

    HashSetDestroy(oS, HSHASH);
}


Plugin Version: http://www.nwnx.org/index.php?id=nwnx2
Running on win10 64bit build 10240
Compatibility of both nwnx2 and nwserver have been set to xp sp2, with admin rights granted

Crashes on deleting the last element and tries another HashSetGetNextKey when hashset size reaches exactly 4, 8, 16, 32, 64. So as a rule of thumb, I guess the 'bad values' are 2^n(n>1)?
HashSetHasNext also crashes, hope this helps to solve the problem.
Back to top
View user's profile Send private message
highv priest



Joined: 01 Mar 2013
Posts: 111

PostPosted: Wed Apr 06, 2016 23:35    Post subject: Reply with quote

I've never had this problem and I run nwn on windows 10 with zero compatibility enabled whatsoever.

This function is also pretty heavily extensively used. So far the only outward error I've found is to NOT put hashset stored on a player or in fact anything that can be removed from the server(so either areas or module or perm objects is best).

I think your major problem is not using HashSetKeyExists or HashSetHasNext for that matter lol. Hashset doesn't work like a normal array would where it just automatically bottoms out when you reach the end. You need to make it check each iteration if THERE IS another one after and if not then cancel out.

Examples of code which works and is heavily used:

Code:
//Works just like google and retrieves all entries related to the keywords typed.
//nCache searches the cache for the entry as opposed to the hard drive.
void GenEntries(object oPC, string sGuild, string sSearch, int nEntire=FALSE, int nCache=TRUE);

void GenEntries(object oPC, string sGuild, string sSearch, int nEntire=FALSE, int nCache=TRUE)
{
if(sSearch == "/")
{
return;
}
object oMod = GetModule();
string sTitle;
string sDB;
string sWrite;
string sFix = sSearch;
if(sSearch == "")
{
sFix = "Fixed_Search";
}
int nAmount = GetNumJournalEntries(oPC);
int nCount = 1;
int nCustom = 167+(nAmount*2);
int nHash = HashSetValid(oMod, sFix);
float fCount = 0.0;
if(!nHash && nCache == TRUE)
{
HashSetCreate(oMod, sFix, 34);
}
else if(nHash && nCache == TRUE)
{
sDB = HashSetGetFirstKey(oMod, sFix);
while(sDB != "")
{
fCount = IntToFloat(nAmount);
nCount = StringToInt(GetStringRight(sDB, GetStringLength(sDB)-10));
sWrite = GetCampaignString(GetDBByCount(nCount), sDB);
sTitle = HashSetGetLocalString(oMod, sFix, sDB);
DelayCommand(0.10*fCount, SetCustomToken(nCustom, sTitle));
DelayCommand(0.10*fCount, SetCustomToken(nCustom+1, sWrite));
nAmount++;
DelayCommand(0.20*fCount, AddJournalQuestEntry("<CUSTOM"+IntToString(nCustom)+">", 1, oPC, FALSE));
nCustom+= 2;
if(HashSetHasNext(oMod, sFix) == TRUE)
{
sDB = HashSetGetNextKey(oMod, sFix);
}
else
{
sDB = "";
}
}
return;
}
sDB = RetrieveFromDB("Wiki"+sGuild+IntToString(nCount), "varname", "libraryindex", "title");
while(sDB != "" && nAmount <= 33)
{
if(sDB != "DELETED")
{
if(TestStringAgainstPattern("**"+sSearch+"**", sDB) == TRUE)
{
HashSetSetLocalString(oMod, sFix, "Wiki"+sGuild+IntToString(nCount), sDB);
fCount = IntToFloat(nAmount);
sWrite = GetCampaignString(GetDBByCount(nCount), "Wiki"+sGuild+IntToString(nCount));
DelayCommand(0.10*fCount, SetCustomToken(nCustom, sDB));
DelayCommand(0.10*fCount, SetCustomToken(nCustom+1, sWrite));
nAmount++;
DelayCommand(0.20*fCount, AddJournalQuestEntry("<CUSTOM"+IntToString(nCustom)+">", 1, oPC, FALSE));
nCustom+= 2;
}
}
nCount++;
sDB = RetrieveFromDB("Wiki"+sGuild+IntToString(nCount), "varname", "libraryindex", "title");
}
}


Code:

void DeleteHash(object oSelf, string Var, string Key)
{
HashSetDeleteVariable(oSelf, Var, Key);
}

void IncrementMemorizedSpell(object oToIncrement, string sIndex, string sLvl, string sID, string sMeta="", string sDomain="")
{
    int nSlot = 0;
    int nIndex = StringToInt(sIndex);
    int nLvl = StringToInt(sLvl);
    int bStop = FALSE;
    int nLength = GetStringLength(sID);
    string sExec = NWNX_Magic_GetMemorizedSpell(oToIncrement, nIndex, nLvl, nSlot);
    while(GetStringLeft(sExec, 2) != "-1")
    {
    if(GetStringLeft(sExec, nLength) != sID)
    {
    DelayCommand(0.2, AddSpell(oToIncrement, sIndex, sLvl, sExec));
    }
    else
    {
    if(GetStringRight(GetStringLeft(sExec, nLength+2), 1) == "0" && bStop == FALSE)
    {
    bStop = TRUE;
    DelayCommand(0.2, AddSpell(oToIncrement, sIndex, sLvl, sID+" 1 "+sMeta+" "+sDomain));
    }
    else
    {
    DelayCommand(0.2, AddSpell(oToIncrement, sIndex, sLvl, sExec));
    }
    }
    nSlot++;
    sExec = NWNX_Magic_GetMemorizedSpell(oToIncrement, nIndex, nLvl, nSlot);
    }
    NWNX_Magic_EmptySpellLevel(oToIncrement, nIndex, nLvl, 0);
}

void CheckandIncrementAbilities()
{
object oSelf = GetModule();
object oPC = OBJECT_SELF;
string sPC = GetName(oPC);
string sKey;
int nHash;
int nStart;
int nEnd;
int nCurrent;
int nLvl;
int nIndex;
int nID;
int nDomain;
int bIncremented = FALSE;
string sLvl;
string sIndex;
string sID;
string sClass;
string sMeta;
string sDomain;
if(HashSetValid(oSelf, "SPELLREGENERATION"+sPC) == TRUE)
{
sKey = HashSetGetFirstKey(oSelf, "SPELLREGENERATION"+sPC);
while(HashSetKeyExists(oSelf, "SPELLREGENERATION"+sPC, sKey))
{
nHash = HashSetGetLocalInt(oSelf, "SPELLREGENERATION"+sPC, sKey);
if(nHash > 1)
{
HashSetSetLocalInt(oSelf, "SPELLREGENERATION"+sPC, sKey, nHash-1);
}
else if(TestStringAgainstPattern("**SORC**", sKey) == TRUE && bIncremented == FALSE)
{
bIncremented = TRUE;
nStart = FindSubString(sKey, "+")+1;
nEnd= FindSubString(sKey, "}", nStart);
sLvl = GetSubString(sKey, nStart, nEnd-nStart);
nStart = FindSubString(sKey, "~")+1;
nEnd= FindSubString(sKey, "}", nStart);
sIndex = GetSubString(sKey, nStart, nEnd-nStart);
nLvl = StringToInt(sLvl);
nIndex = StringToInt(sIndex);
DelayCommand(2.0, DeleteHash(oSelf, "SPELLREGENERATION"+sPC, sKey));
nCurrent = NWNX_Magic_ModifySpellsPerDay(oPC, nIndex, nLvl, 1, -1);
NWNX_Magic_ModifySpellsPerDay(oPC, nIndex, nLvl, 1, nCurrent+1);
}
else if(TestStringAgainstPattern("**BARD**", sKey) == TRUE && bIncremented == FALSE)
{
bIncremented = TRUE;
nStart = FindSubString(sKey, "+")+1;
nEnd= FindSubString(sKey, "}", nStart);
sLvl = GetSubString(sKey, nStart, nEnd-nStart);
nStart = FindSubString(sKey, "~")+1;
nEnd= FindSubString(sKey, "}", nStart);
sIndex = GetSubString(sKey, nStart, nEnd-nStart);
nLvl = StringToInt(sLvl);
nIndex = StringToInt(sIndex);
DelayCommand(2.0, DeleteHash(oSelf, "SPELLREGENERATION"+sPC, sKey));
nCurrent = NWNX_Magic_ModifySpellsPerDay(oPC, nIndex, nLvl, 1, -1);
NWNX_Magic_ModifySpellsPerDay(oPC, nIndex, nLvl, 1, nCurrent+1);
}
else if(bIncremented == FALSE)
{
bIncremented = TRUE;
nStart = FindSubString(sKey, "+")+1;
nEnd = FindSubString(sKey, "}", nStart);
sLvl = GetSubString(sKey, nStart, nEnd-nStart);
nStart = FindSubString(sKey, "~")+1;
nEnd = FindSubString(sKey, "}", nStart);
sIndex = GetSubString(sKey, nStart, nEnd-nStart);
nStart = FindSubString(sKey, "%")+1;
nEnd = FindSubString(sKey, "}", nStart);
sClass = GetSubString(sKey, nStart, nEnd-nStart);
nStart = FindSubString(sKey, "#")+1;
nEnd = FindSubString(sKey, "}", nStart);
sID = GetSubString(sKey, nStart, nEnd-nStart);
nStart = FindSubString(sKey, "*")+1;
nEnd = FindSubString(sKey, "}", nStart);
sDomain = GetSubString(sKey, nStart, nEnd-nStart);
nStart = FindSubString(sKey, "-")+1;
nEnd = FindSubString(sKey, "}", nStart);
sMeta = GetSubString(sKey, nStart, nEnd-nStart);
DelayCommand(2.0, DeleteHash(oSelf, "SPELLREGENERATION"+sPC, sKey));
IncrementMemorizedSpell(oPC, sIndex, sLvl, sID, sMeta, sDomain);
}
sKey = HashSetGetNextKey(oSelf, "SPELLREGENERATION"+sPC);
}
}//Spell Regeneration
if(HashSetValid(oSelf, "FEATREGENERATION"+sPC) == TRUE)
{
sKey = HashSetGetFirstKey(oSelf, "FEATREGENERATION"+sPC);
while(HashSetKeyExists(oSelf, "FEATREGENERATION"+sPC, sKey))
{
nHash = HashSetGetLocalInt(oSelf, "FEATREGENERATION"+sPC, sKey);
if(nHash > 1)
{
HashSetSetLocalInt(oSelf, "FEATREGENERATION"+sPC, sKey, nHash-1);
}
else
{
nEnd = FindSubString(sKey, "|");
sID = GetStringLeft(sKey, nEnd);
nID = StringToInt(sID);
DelayCommand(2.0, DeleteHash(oSelf, "FEATREGENERATION"+sPC, sKey));
IncrementRemainingFeatUses(oPC, nID);
}
sKey = HashSetGetNextKey(oSelf, "FEATREGENERATION"+sPC);
}
}//Feat Regeneration
}


In there it adds/deletes/increments/decrements/etc in every way for hashsets and has multiple versions of hashsets active at any one time. Again you just need to make sure you don't try to recall data for a hash that doesn't exist as that is paramount to a memory error and is an auto CTD.
Back to top
View user's profile Send private message
pethrowilo



Joined: 21 Dec 2014
Posts: 7
Location: China

PostPosted: Tue Apr 19, 2016 9:33    Post subject: Reply with quote

Thank you for your reply highv priest
But I think I've mentioned HashSetHasNext would simply crash my server on my environment...

And... Wouldn't a dm login crash a no-compatibility set server? Sad

I've checked your script, of course your script would never crash the server because of that Cycling-With-Deletion action, it's a delayed command, while my deletion occurs just in cycle.

You did not seem to use HashSetHasNext(which would crash my server on execution, as mentioned before) either.

HashSetKeyExists needs a key already known, not an option for me here.
Back to top
View user's profile Send private message
highv priest



Joined: 01 Mar 2013
Posts: 111

PostPosted: Thu Apr 28, 2016 10:11    Post subject: Reply with quote

DM login did not crash the no compatibility server.

I do have the server to run as administrator(lol), but no compatibility was necessary.

I think your problem really is something to do with hashset conflicting with something else you're using. Perhaps you should consider using the sortset version instead of hashset as they have similar uses.

Likewise, you can also use SQL to act as an array simply by specifying it to use the LOCAL(which means memory) instead of database for the calls.

Lastly if that isn't enough for you... Use nwnx_funcs GetFirst/GetNext local variable to simulate arrays as well.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    nwnx.org Forum Index -> Windows 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