Slash Commands Not Working After a Rename
-
Every time a player uses /renameme or if an admin has to rename someone, slash commands (and admin commands) do not work on that character until the server has been restarted. From what I understand, the player database in memory does not match the hard drive, or something like that. Is there any way to fix this issue without restarting the server?
-
My server is using FLHook. After a /renameme or admin using .rename, it does kick the player out. When they come back, they can’t use slash commands. For /stuck, it says the player is not in space when they are. Its like it is looking for the old character nam
-
Even the 1.6.1 Rename has this bug, but it occurs not every time as it did in 1.6.0. I always replace the rename function with a fixed from 1.5.5 which NEVER killed a character until today (and players rename very often).
-
We don’t have crashes - even as we had about 50 Players online. Maybe it’s also a rare bug. It’s not the version from 1.5.5 it’s a fixed one (I think I included fixes from posts made here on starport, but it’s over a year ago I did that). Anyway, the code is:
HK_ERROR HkRename(wstring wscCharname, wstring wscNewCharname, bool bOnlyDelete) { HK_GET_CLIENTID(iClientID, wscCharname); if((iClientID == -1) && !HkGetAccountByCharname(wscCharname)) return HKE_CHAR_DOES_NOT_EXIST; if(!bOnlyDelete && HkGetAccountByCharname(wscNewCharname)) return HKE_CHARNAME_ALREADY_EXISTS; if(!bOnlyDelete && (wscNewCharname.length() > 23)) return HKE_CHARNAME_TOO_LONG; if(!bOnlyDelete && !wscNewCharname.length()) return HKE_CHARNAME_TOO_SHORT; CAccount *acc; wstring wscOldCharname; if(iClientID != -1) { acc = Players.FindAccountFromClientID(iClientID); wscOldCharname = Players.GetActiveCharacterName(iClientID); } else { wscOldCharname = wscCharname; acc = HkGetAccountByCharname(wscCharname); } wstring wscAccountDirname; HkGetAccountDirName(acc, wscAccountDirname); wstring wscNewFilename; HkGetCharFileName(wscNewCharname, wscNewFilename); wstring wscOldFilename; HkGetCharFileName(wscOldCharname, wscOldFilename); string scNewCharfilePath = scAcctPath + wstos(wscAccountDirname) + "\\" + wstos(wscNewFilename) + ".fl"; string scOldCharfilePath = scAcctPath + wstos(wscAccountDirname) + "\\" + wstos(wscOldFilename) + ".fl"; if(!bOnlyDelete) { if(!flc_decode(scOldCharfilePath.c_str(), scNewCharfilePath.c_str())) { // file wasn't encoded, thus simply rename it DeleteFile(scNewCharfilePath.c_str()); // just to get sure... CopyFile(scOldCharfilePath.c_str(), scNewCharfilePath.c_str(), FALSE); } } // delete old character flstr *str = CreateWString(wscOldCharname.c_str()); HkLockAccountAccess(acc, true); // also kicks player on this account bool bRet = Players.DeleteCharacterFromName(*str); HkUnlockAccountAccess(acc); FreeWString(str); // increment character counter int iNumberOfChars; memcpy(&iNumberOfChars, (char*)acc + 0x2C, 4); iNumberOfChars++; memcpy((char*)acc + 0x2C, &iNumberOfChars, 4); DeleteFile(scOldCharfilePath.c_str()); // doesn't delete when previously renamed, dunno why if(bOnlyDelete) return HKE_OK; // only delete char, thus we're finished wstring wscNewNameString = L""; for(uint i = 0; (i < wscNewCharname.length()); i++) { char cHiByte = wscNewCharname[i] >> 8; char cLoByte = wscNewCharname[i] & 0xFF; wchar_t wszBuf[8]; swprintf(wszBuf, L"%02X%02X", ((uint)cHiByte) & 0xFF, ((uint)cLoByte) & 0xFF); wscNewNameString += wszBuf; } IniWrite(scNewCharfilePath, "Player", "Name", wstos(wscNewNameString)); // we'll also need to add the new character into the flname searchtree in memory(which is usually build when // flserver starts). methods like FindAccountByCharacterName won't work else // insert into flname search tree struct TREENODE { TREENODE *pLeft; TREENODE *pParent; TREENODE *pRight; ulong l1; char *szFLName; uint lLength; ulong l2; // ?? CAccount *acc; }; char *pEBP; pEBP = (char*)&Players + 0x30; char *pEDI; memcpy(&pEDI, pEBP + 4, 4); TREENODE *leaf; memcpy(&leaf, pEBP + 8, 4); // edi+4 is where the root node is TREENODE *node; memcpy(&node, pEDI + 4, 4); bool bLeft = true; TREENODE *lastparent = (TREENODE*)(pEDI + 4); while(node != leaf) { lastparent = node; int iRet = strcmp(node->szFLName, wstos(wscNewFilename + L".fl").c_str()); if(iRet >= 0) { // leftnode? node = node->pLeft; bLeft = true; } else { // rightnode? node = node->pRight; bLeft = false; } } // we need to use fl's new operator, else free might fail later when char gets deleted typedef void* (*_flnew)(unsigned int); _flnew flnew = (_flnew) SRV_ADDR(ADDR_FLNEW); TREENODE *tn = (TREENODE *)flnew(sizeof(TREENODE)); memset(tn, 0, sizeof(TREENODE)); tn->pLeft = leaf; tn->pParent = lastparent; tn->pRight = leaf; tn->szFLName = new char[32]; strcpy(tn->szFLName, wstos(wscNewFilename + L".fl").c_str()); tn->lLength = (uint)strlen(tn->szFLName); tn->l2 = 0x1F; // seems to be always 0x1F tn->acc = acc; if(bLeft) lastparent->pLeft = tn; else lastparent->pRight = tn; // finally we need to add the new char to the CAccount character list // else it will not be shown in the accounts list in the flserver window struct LISTNODE { LISTNODE *next; LISTNODE *prev; u_long l1; wchar_t *wszCharname; ulong lArray[32]; }; LISTNODE *lnHead; memcpy(&lnHead, (char*)acc + 0x28, 4); LISTNODE *lnCur = lnHead->next; while(lnCur->next != lnHead) lnCur = lnCur->next; LISTNODE *ln = (LISTNODE *)flnew(sizeof(LISTNODE)); ln->next = lnHead; ln->prev = lnCur; ln->wszCharname = new wchar_t[32]; wcscpy(ln->wszCharname, wscNewCharname.c_str()); lnCur->next = ln; return HKE_OK; } If there is an error either it did not occur yet or I just did not notice (which would be very strange, bot nothing is impossilbe ^^).[/i][/i]
-
Well I prefer a crash rather than corrupt player files For now there seems to be no better solution for this problem than the above code.
-
It depends on the version of the /renameme plugin that you are using. Earlier versions use the HkRename function in FLHook. FLHook 1.6.0 has a problem if the new character starting location is not Manhattan. A patched version of FLHook 1.6.0 is here - this fixes the problem.
An improved version of this patch is in the svn head of flhook plugin 1.6.1.
Later versions of the renameme plugin include the patch in plugin itself and so are not dependent on the flhook plugin version (hopefully). If the renameme plugin has the /movechar command then you should have the right version.
-
I haven’t noticed any rename oddities, but I am also using a patched version of the 1.5.5 rename.
The two major changes I made were to save the character before the rename and to use flnew instead of new to allocate memory for the character names (this fixes FLServer crashing upon shutdown).
For those interested:
HK_ERROR HkRename(wstring wscCharname, wstring wscNewCharname, bool bOnlyDelete) { HkSaveChar(wscCharname); //Fixes weird rename behavior HK_GET_CLIENTID(iClientID, wscCharname); if((iClientID == -1) && !HkGetAccountByCharname(wscCharname)) return HKE_CHAR_DOES_NOT_EXIST; if(!bOnlyDelete && HkGetAccountByCharname(wscNewCharname)) return HKE_CHARNAME_ALREADY_EXISTS; if(!bOnlyDelete && (wscNewCharname.length() > 23)) return HKE_CHARNAME_TOO_LONG; if(!bOnlyDelete && !wscNewCharname.length()) return HKE_CHARNAME_TOO_SHORT; CAccount *acc; wstring wscOldCharname; if(iClientID != -1) { acc = Players.FindAccountFromClientID(iClientID); wscOldCharname = Players.GetActiveCharacterName(iClientID); } else { wscOldCharname = wscCharname; acc = HkGetAccountByCharname(wscCharname); } wstring wscAccountDirname; if(!HKHKSUCCESS(HkGetAccountDirName(acc, wscAccountDirname)) || !wscAccountDirname.length())//Could not get account dir name return HKE_COULD_NOT_GET_PATH; wstring wscNewFilename; if(!bOnlyDelete && (!HKHKSUCCESS(HkGetCharFileName(wscNewCharname, wscNewFilename)) || !wscNewFilename.length()))//Could not get filename of new char return HKE_COULD_NOT_GET_PATH; wstring wscOldFilename; if(!HKHKSUCCESS(HkGetCharFileName(wscOldCharname, wscOldFilename)) || !wscOldFilename.length()) return HKE_COULD_NOT_GET_PATH; string scNewCharfilePath = scAcctPath + wstos(wscAccountDirname) + "\\" + wstos(wscNewFilename) + ".fl"; string scOldCharfilePath = scAcctPath + wstos(wscAccountDirname) + "\\" + wstos(wscOldFilename) + ".fl"; if(!bOnlyDelete) { if(!flc_decode(scOldCharfilePath.c_str(), scNewCharfilePath.c_str())) { // file wasn't encoded, thus simply rename it DeleteFile(scNewCharfilePath.c_str()); // just to get sure... CopyFile(scOldCharfilePath.c_str(), scNewCharfilePath.c_str(), FALSE); } } // delete old character flstr *str = CreateWString(wscOldCharname.c_str()); HkLockAccountAccess(acc, true); // also kicks player on this account bool bRet = Players.DeleteCharacterFromName(*str); HkUnlockAccountAccess(acc); FreeWString(str); DeleteFile(scOldCharfilePath.c_str()); // doesn't delete when previously renamed, dunno why if(bOnlyDelete) return HKE_OK; // only delete char, thus we're finished wstring wscNewNameString = L""; for(uint i = 0; (i < wscNewCharname.length()); i++) { char cHiByte = wscNewCharname[i] >> 8; char cLoByte = wscNewCharname[i] & 0xFF; wchar_t wszBuf[8]; swprintf(wszBuf, L"%02X%02X", ((uint)cHiByte) & 0xFF, ((uint)cLoByte) & 0xFF); wscNewNameString += wszBuf; } IniWrite(scNewCharfilePath, "Player", "Name", wstos(wscNewNameString)); // we'll also need to add the new character into the flname searchtree in memory(which is usually build when // flserver starts). methods like FindAccountByCharacterName won't work else // insert into flname search tree struct TREENODE { TREENODE *pLeft; TREENODE *pParent; TREENODE *pRight; ulong l1; char *szFLName; uint lLength; ulong l2; // ?? CAccount *acc; }; char *pEBP; pEBP = (char*)&Players + 0x30; char *pEDI; memcpy(&pEDI, pEBP + 4, 4); TREENODE *leaf; memcpy(&leaf, pEBP + 8, 4); // edi+4 is where the root node is TREENODE *node; memcpy(&node, pEDI + 4, 4); bool bLeft = true; TREENODE *lastparent = (TREENODE*)(pEDI + 4); while(node != leaf) { lastparent = node; int iRet = strcmp(node->szFLName, wstos(wscNewFilename + L".fl").c_str()); if(iRet >= 0) { // leftnode? node = node->pLeft; bLeft = true; } else { // rightnode? node = node->pRight; bLeft = false; } } // we need to use fl's new operator, else free might fail later when char gets deleted typedef void* (*_flnew)(unsigned int); _flnew flnew = (_flnew) SRV_ADDR(ADDR_FLNEW); TREENODE *tn = (TREENODE *)flnew(sizeof(TREENODE)); memset(tn, 0, sizeof(TREENODE)); tn->pLeft = leaf; tn->pParent = lastparent; tn->pRight = leaf; tn->szFLName = (char*)flnew(32); strcpy(tn->szFLName, wstos(wscNewFilename + L".fl").c_str()); tn->lLength = (uint)strlen(tn->szFLName); tn->l2 = 0x1F; // seems to be always 0x1F tn->acc = acc; if(bLeft) lastparent->pLeft = tn; else lastparent->pRight = tn; // increment character counter uint iNumberOfChars; memcpy(&iNumberOfChars, (char*)acc + 0x2C, 4); iNumberOfChars++; memcpy((char*)acc + 0x2C, &iNumberOfChars, 4); // finally we need to add the new char to the CAccount character list // else it will not be shown in the accounts list in the flserver window struct LISTNODE { LISTNODE *next; LISTNODE *prev; u_long l1; wchar_t *wszCharname; ulong lArray[32]; }; LISTNODE *lnHead; memcpy(&lnHead, (char*)acc + 0x28, 4); LISTNODE *lnCur = lnHead->next; while(lnCur->next != lnHead) lnCur = lnCur->next; LISTNODE *ln = (LISTNODE *)flnew(sizeof(LISTNODE)); ln->next = lnHead; ln->prev = lnCur; ln->wszCharname = (wchar_t*)flnew(sizeof(wchar_t) * 32); wcscpy(ln->wszCharname, wscNewCharname.c_str()); lnCur->next = ln; return HKE_OK; }[/i][/i]