It turns out that HkRename doesn’t work properly if the starting base is not Manhattan - the call to Server.CreateNewCharacter fails. Those mysterious numbers in the SCreateCharacterInfo structure do change when a different starting location is used. I’ve got a fix for this problem.
If any one wants a copy of the patched flhook.dll let me know and I’ll make it available.
Here’s the patched lines in the rename function. It’s a bit hacky but it works for me…
...
SCreateCharacterInfo newcharinfo;
wcsncpy(newcharinfo.wszCharname, wscNewCharname.c_str(), 23);
// CHANGE STARTS HERE
newcharinfo.iNickName = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","nickname","new_player").c_str());
newcharinfo.iBase = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","base", "Li01_01_Base").c_str());
newcharinfo.iPackage = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","Package","ge_fighter").c_str());
newcharinfo.iPilot = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","Pilot","trent").c_str());
// CHANGE ENDS HERE
// Fill struct with valid data (though it isnt used it is needed)
newcharinfo.iDunno[4] = 65536;
...
Here’s the SCreateCharacterInfo structure and the full rename function…
struct SCreateCharacterInfo
{
wchar_t wszCharname[23];
uint iNickName; // From [Faction] section of newcharacter.ini
uint iBase; Â // From [Faction] section of newcharacter.ini
uint iPackage; // From [Faction] section of newcharacter.ini
uint iPilot; // From [Faction] section of newcharacter.ini
uint iDunno[96];
};
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) {
// delete character
flstr *str = CreateWString(wscOldCharname.c_str());
HkLockAccountAccess(acc, true); // also kicks player on this account
Players.DeleteCharacterFromName(*str);
HkUnlockAccountAccess(acc);
FreeWString(str);
return HKE_OK;
}
HkLockAccountAccess(acc, true); // kick player if online
HkUnlockAccountAccess(acc);
// Copy existing char file into tmp
string scTmpPath = scOldCharfilePath+".tmp";
DeleteFile(scTmpPath.c_str());
CopyFile(scOldCharfilePath.c_str(), scTmpPath.c_str(), FALSE);
// Delete existing char otherwise a rename of the char in slot 5 fails.
flstr *str = CreateWString(wscOldCharname.c_str());
Players.DeleteCharacterFromName(*str);
FreeWString(str);
// Emulate char create
SLoginInfo logindata;
wcsncpy(logindata.wszAccount, HkGetAccountID(acc).c_str(), 36);
Players.login(logindata, Players.GetMaxPlayerCount()+1);
SCreateCharacterInfo newcharinfo;
wcsncpy(newcharinfo.wszCharname, wscNewCharname.c_str(), 23);
newcharinfo.iNickName = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","nickname","").c_str());
newcharinfo.iBase = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","base", "").c_str());
newcharinfo.iPackage = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","Package","").c_str());
newcharinfo.iPilot = CreateID(IniGetS("..\\DATA\\CHARACTERS\\newcharacter.ini","Faction","Pilot","").c_str());
// Fill struct with valid data (though it isnt used it is needed)
newcharinfo.iDunno[4] = 65536;
newcharinfo.iDunno[5] = 65538;
newcharinfo.iDunno[6] = 0;
newcharinfo.iDunno[7] = 1058642330;
newcharinfo.iDunno[8] = 3206125978;
newcharinfo.iDunno[9] = 65537;
newcharinfo.iDunno[10] = 0;
newcharinfo.iDunno[11] = 3206125978;
newcharinfo.iDunno[12] = 65539;
newcharinfo.iDunno[13] = 65540;
newcharinfo.iDunno[14] = 65536;
newcharinfo.iDunno[15] = 65538;
Server.CreateNewCharacter(newcharinfo, Players.GetMaxPlayerCount()+1);
HkSaveChar(wscNewCharname);
Players.logout(Players.GetMaxPlayerCount()+1);
// Decode the backup of the old char and overwrite the new char file
if(!flc_decode(scTmpPath.c_str(), scNewCharfilePath.c_str()))
{ // file wasn't encoded, thus simply rename it
DeleteFile(scNewCharfilePath.c_str()); // just to get sure...
CopyFile(scTmpPath.c_str(), scNewCharfilePath.c_str(), FALSE);
}
DeleteFile(scTmpPath.c_str());
// Update the char name in the new char file.
// Add a space to the value so the ini file line looks like " <key>= <value>"
// otherwise Ioncross Server Operator can't decode the file correctly
string scValue = " ";
for(uint i = 0; (i < wscNewCharname.length()); i++)
{
char cHiByte = wscNewCharname[i] >> 8;
char cLoByte = wscNewCharname[i] & 0xFF;
char szBuf[8];
sprintf(szBuf, "%02X%02X", ((uint)cHiByte) & 0xFF, ((uint)cLoByte) & 0xFF);
scValue += szBuf;
}
IniWrite(scNewCharfilePath, "Player", "Name", scValue);
// Re-encode the char file if needed.
if (!set_bDisableCharfileEncryption)
if (!flc_encode(scNewCharfilePath.c_str(),scNewCharfilePath.c_str()))
return HKE_COULD_NOT_ENCODE_CHARFILE;
return HKE_OK;
}
[/i][/i]</value></key>