View previous topic :: View next topic |
Author |
Message |
pethrowilo
Joined: 21 Dec 2014 Posts: 7 Location: China
|
Posted: Tue Mar 15, 2016 21:47 Post subject: Weird nwnx_hashset crash, need help here @_@ |
|
|
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 |
|
|
highv priest
Joined: 01 Mar 2013 Posts: 111
|
Posted: Wed Apr 06, 2016 23:35 Post subject: |
|
|
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 |
|
|
pethrowilo
Joined: 21 Dec 2014 Posts: 7 Location: China
|
Posted: Tue Apr 19, 2016 9:33 Post subject: |
|
|
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?
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 |
|
|
highv priest
Joined: 01 Mar 2013 Posts: 111
|
Posted: Thu Apr 28, 2016 10:11 Post subject: |
|
|
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 |
|
|
|
|
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
|