2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
|
|
|
|
|
*/
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "objecthash.h"
|
|
|
|
|
|
Savefile rewrite (#601)
* rewrite of saving, replaced operator way with a generic add method, thus
not everywhere the formating of the savefiles is hardcoded.
since its the last spot which uses the old formating lib, remobed the
lib
* removed cmake of old format lib
* testscripts for load/save of UObject,Item,Armor,Weapon
* fixed: member faster_cast_recovery and faster_cast_recovery_mod getter returned
a wrong value
* wrong/missing docs
* test containers, lockable, map, spellbooks
fixed save bug in map and spellbook
removed ancient savestrategy experiments
* added corpse test
splitted testfiles
* fixed loading (ancient bug) and saving (PR bug) of Reportables
added tests for houses, boats, accounts and chars
* fixed include
* fix shutdown leak
* added npc tests
upload complete coretest folder also on failure
* do not write and load RegisteredHouse for NPCs two times
readded extra newline between accounts
* tests for guild, party, realm
added resource cfgs, but a test is not really possible since nothing of
interest is stored
* added datafile, storage test
* activated resource loading, 25year old bug, but since the stored values
are senseless it makes no real difference.
added a few wtf comments
catch all exceptions during formatting of log lines
* replaced .write with explixit .begin, .end and .comment.
for leftovers.txt the StreamSaver was also used, since the format is
different use directly ofstream
* added corechanges
2024-01-24 18:49:06 +01:00
|
|
|
#include <fstream>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <stddef.h>
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
#include "../clib/clib_endian.h"
|
|
|
|
|
#include "../clib/logfacility.h"
|
|
|
|
|
#include "../clib/streamsaver.h"
|
|
|
|
|
#include "../plib/systemstate.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "accounts/account.h"
|
|
|
|
|
#include "globals/state.h"
|
|
|
|
|
#include "mobile/charactr.h"
|
|
|
|
|
#include "ufunc.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace Core
|
|
|
|
|
{
|
|
|
|
|
ObjectHash::ObjectHash() : hash(), reap_iterator( hash.end() ){};
|
|
|
|
|
|
|
|
|
|
ObjectHash::~ObjectHash(){};
|
|
|
|
|
|
|
|
|
|
bool ObjectHash::Insert( UObject* obj )
|
|
|
|
|
{
|
|
|
|
|
OH_iterator itr = hash.find( obj->serial );
|
|
|
|
|
if ( itr != hash.end() )
|
|
|
|
|
{
|
|
|
|
|
if ( Plib::systemstate.config.loglevel >= 5 )
|
2024-05-05 09:13:12 +02:00
|
|
|
POLLOGLN( "ObjectHash insert failed for object serial {:#x}. (duplicate serial?)",
|
2024-01-16 17:55:42 +01:00
|
|
|
obj->serial );
|
2016-02-19 19:26:35 +01:00
|
|
|
return false;
|
2016-02-11 22:54:43 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
hash.insert( hash.end(), std::make_pair( obj->serial, UObjectRef( obj ) ) );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ObjectHash::Remove( u32 /*serial*/ )
|
|
|
|
|
{
|
2018-04-03 04:13:03 +02:00
|
|
|
// unsigned int num_erased = hash.erase( serial );
|
|
|
|
|
// return (num_erased>0);
|
2016-02-19 19:26:35 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UObject* ObjectHash::Find( u32 serial )
|
|
|
|
|
{
|
|
|
|
|
OH_iterator itr = hash.find( serial );
|
|
|
|
|
if ( itr != hash.end() )
|
|
|
|
|
return ( itr->second ).get();
|
|
|
|
|
else
|
2018-07-31 14:30:29 +02:00
|
|
|
return nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 ObjectHash::GetNextUnusedItemSerial()
|
|
|
|
|
{
|
|
|
|
|
u32 curr = GetCurrentItemSerialNumber();
|
|
|
|
|
u32 tempserial = curr + 1;
|
|
|
|
|
|
|
|
|
|
for ( ;; )
|
|
|
|
|
{
|
|
|
|
|
// recycle time. when we roll over the max serial, start from the beginning. now the find()
|
|
|
|
|
// below may take some time to get the next unused.
|
|
|
|
|
if ( tempserial < ITEMSERIAL_START || tempserial > ITEMSERIAL_END )
|
|
|
|
|
tempserial = ITEMSERIAL_START;
|
|
|
|
|
|
|
|
|
|
if ( hash.find( tempserial ) != hash.end() )
|
|
|
|
|
{
|
|
|
|
|
tempserial++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if ( dirty_deleted.count( tempserial ) )
|
|
|
|
|
{
|
|
|
|
|
tempserial++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if ( clean_deleted.count( tempserial ) )
|
|
|
|
|
{
|
|
|
|
|
tempserial++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return tempserial;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
u32 ObjectHash::GetNextUnusedCharSerial()
|
|
|
|
|
{
|
|
|
|
|
u32 curr = GetCurrentCharSerialNumber();
|
|
|
|
|
u32 tempserial = curr + 1;
|
|
|
|
|
|
|
|
|
|
for ( ;; )
|
|
|
|
|
{
|
|
|
|
|
// recycle time. when we roll over the max serial, start from the beginning. now the find()
|
|
|
|
|
// below may take some time to get the next unused.
|
|
|
|
|
if ( tempserial < CHARACTERSERIAL_START || tempserial > CHARACTERSERIAL_END )
|
|
|
|
|
tempserial = CHARACTERSERIAL_START;
|
|
|
|
|
|
|
|
|
|
if ( hash.find( tempserial ) != hash.end() )
|
|
|
|
|
{
|
|
|
|
|
tempserial++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if ( dirty_deleted.find( tempserial ) != dirty_deleted.end() )
|
|
|
|
|
{
|
|
|
|
|
tempserial++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if ( clean_deleted.find( tempserial ) != clean_deleted.end() )
|
|
|
|
|
{
|
|
|
|
|
tempserial++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return tempserial;
|
|
|
|
|
};
|
|
|
|
|
|
Savefile rewrite (#601)
* rewrite of saving, replaced operator way with a generic add method, thus
not everywhere the formating of the savefiles is hardcoded.
since its the last spot which uses the old formating lib, remobed the
lib
* removed cmake of old format lib
* testscripts for load/save of UObject,Item,Armor,Weapon
* fixed: member faster_cast_recovery and faster_cast_recovery_mod getter returned
a wrong value
* wrong/missing docs
* test containers, lockable, map, spellbooks
fixed save bug in map and spellbook
removed ancient savestrategy experiments
* added corpse test
splitted testfiles
* fixed loading (ancient bug) and saving (PR bug) of Reportables
added tests for houses, boats, accounts and chars
* fixed include
* fix shutdown leak
* added npc tests
upload complete coretest folder also on failure
* do not write and load RegisteredHouse for NPCs two times
readded extra newline between accounts
* tests for guild, party, realm
added resource cfgs, but a test is not really possible since nothing of
interest is stored
* added datafile, storage test
* activated resource loading, 25year old bug, but since the stored values
are senseless it makes no real difference.
added a few wtf comments
catch all exceptions during formatting of log lines
* replaced .write with explixit .begin, .end and .comment.
for leftovers.txt the StreamSaver was also used, since the format is
different use directly ofstream
* added corechanges
2024-01-24 18:49:06 +01:00
|
|
|
void ObjectHash::PrintContents( std::ofstream* os ) const
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
OH_const_iterator itr, itrend;
|
Savefile rewrite (#601)
* rewrite of saving, replaced operator way with a generic add method, thus
not everywhere the formating of the savefiles is hardcoded.
since its the last spot which uses the old formating lib, remobed the
lib
* removed cmake of old format lib
* testscripts for load/save of UObject,Item,Armor,Weapon
* fixed: member faster_cast_recovery and faster_cast_recovery_mod getter returned
a wrong value
* wrong/missing docs
* test containers, lockable, map, spellbooks
fixed save bug in map and spellbook
removed ancient savestrategy experiments
* added corpse test
splitted testfiles
* fixed loading (ancient bug) and saving (PR bug) of Reportables
added tests for houses, boats, accounts and chars
* fixed include
* fix shutdown leak
* added npc tests
upload complete coretest folder also on failure
* do not write and load RegisteredHouse for NPCs two times
readded extra newline between accounts
* tests for guild, party, realm
added resource cfgs, but a test is not really possible since nothing of
interest is stored
* added datafile, storage test
* activated resource loading, 25year old bug, but since the stored values
are senseless it makes no real difference.
added a few wtf comments
catch all exceptions during formatting of log lines
* replaced .write with explixit .begin, .end and .comment.
for leftovers.txt the StreamSaver was also used, since the format is
different use directly ofstream
* added corechanges
2024-01-24 18:49:06 +01:00
|
|
|
*os << fmt::format( "Object Count: {}\n", hash.size() );
|
2016-02-19 19:26:35 +01:00
|
|
|
for ( itr = hash.begin(), itrend = hash.end(); itr != itrend; ++itr )
|
|
|
|
|
{
|
2024-05-05 09:13:12 +02:00
|
|
|
*os << fmt::format( "type: {} serial: {:#x} name: {}\n", itr->second->classname(),
|
Savefile rewrite (#601)
* rewrite of saving, replaced operator way with a generic add method, thus
not everywhere the formating of the savefiles is hardcoded.
since its the last spot which uses the old formating lib, remobed the
lib
* removed cmake of old format lib
* testscripts for load/save of UObject,Item,Armor,Weapon
* fixed: member faster_cast_recovery and faster_cast_recovery_mod getter returned
a wrong value
* wrong/missing docs
* test containers, lockable, map, spellbooks
fixed save bug in map and spellbook
removed ancient savestrategy experiments
* added corpse test
splitted testfiles
* fixed loading (ancient bug) and saving (PR bug) of Reportables
added tests for houses, boats, accounts and chars
* fixed include
* fix shutdown leak
* added npc tests
upload complete coretest folder also on failure
* do not write and load RegisteredHouse for NPCs two times
readded extra newline between accounts
* tests for guild, party, realm
added resource cfgs, but a test is not really possible since nothing of
interest is stored
* added datafile, storage test
* activated resource loading, 25year old bug, but since the stored values
are senseless it makes no real difference.
added a few wtf comments
catch all exceptions during formatting of log lines
* replaced .write with explixit .begin, .end and .comment.
for leftovers.txt the StreamSaver was also used, since the format is
different use directly ofstream
* added corechanges
2024-01-24 18:49:06 +01:00
|
|
|
itr->second->serial, itr->second->name() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ObjectHash::Reap()
|
|
|
|
|
{
|
|
|
|
|
// this is called every 2 seconds (approximately)
|
|
|
|
|
// iterate through enough of the object hash that it will be swept entirely once every 30 minutes
|
|
|
|
|
// 2 minutes = 120 seconds = 60 reap calls per sweep
|
|
|
|
|
// 30 minutes = 1800 seconds = 900 reap calls per sweep
|
|
|
|
|
|
|
|
|
|
// first, figure out how many objects to check:
|
|
|
|
|
hs::size_type count = hash.size();
|
|
|
|
|
if ( count == 0 )
|
|
|
|
|
return;
|
|
|
|
|
hs::size_type count_this = count / 60;
|
|
|
|
|
if ( count_this < 1 )
|
|
|
|
|
count_this = 1;
|
|
|
|
|
if ( reap_iterator == hash.end() )
|
|
|
|
|
reap_iterator = hash.begin();
|
|
|
|
|
|
|
|
|
|
while ( count_this-- )
|
|
|
|
|
{
|
|
|
|
|
UObject* obj = ( *reap_iterator ).second.get();
|
|
|
|
|
|
|
|
|
|
// We want the objecthash to be the holder of the last reference to an
|
|
|
|
|
// object when it is deleted - hence the ref_counted_count() check.
|
|
|
|
|
if ( obj->orphan() && obj->ref_counted_count() == 1 )
|
|
|
|
|
{
|
|
|
|
|
dirty_deleted.insert( cfBEu32( obj->serial_ext ) );
|
|
|
|
|
hash.erase( reap_iterator++ );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
++reap_iterator;
|
|
|
|
|
|
|
|
|
|
if ( reap_iterator == hash.end() )
|
|
|
|
|
{
|
|
|
|
|
reap_iterator = hash.begin();
|
|
|
|
|
if ( reap_iterator == hash.end() )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-13 14:23:36 +01:00
|
|
|
void ObjectHash::Clear( bool shutdown )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
bool any;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
any = false;
|
|
|
|
|
for ( OH_iterator itr = hash.begin(), itrend = hash.end(); itr != itrend; )
|
|
|
|
|
{
|
2023-11-13 14:23:36 +01:00
|
|
|
UObject* obj = itr->second.get();
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
if ( obj->orphan() && obj->ref_counted_count() == 1 )
|
|
|
|
|
{
|
2023-11-13 14:23:36 +01:00
|
|
|
itr = hash.erase( itr );
|
2016-02-19 19:26:35 +01:00
|
|
|
any = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
++itr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while ( any );
|
2023-11-13 14:23:36 +01:00
|
|
|
|
|
|
|
|
reap_iterator = hash.begin(); // set itr for ::Reap back to the beginning
|
|
|
|
|
if ( shutdown && !hash.empty() )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Leftover objects in objecthash: {}", hash.size() );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
// the hash will be cleared after main() exits, with other statics.
|
|
|
|
|
// this usually causes assertion failures and crashes.
|
|
|
|
|
// creating a copy of the internal hash will ensure no refcounts reach zero.
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Leaking a copy of the objecthash in order to avoid a crash." );
|
2016-02-19 19:26:35 +01:00
|
|
|
new hs( hash );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ObjectHash::ClearCharacterAccountReferences()
|
|
|
|
|
{
|
|
|
|
|
for ( OH_const_iterator itr = hash.begin(), itrend = hash.end(); itr != itrend; ++itr )
|
|
|
|
|
{
|
|
|
|
|
UObject* obj = ( *itr ).second.get();
|
|
|
|
|
if ( !obj->orphan() && obj->ismobile() )
|
|
|
|
|
{
|
|
|
|
|
Mobile::Character* chr = static_cast<Mobile::Character*>( obj );
|
|
|
|
|
// if (!chr->logged_in)
|
|
|
|
|
//{
|
|
|
|
|
chr->acct.clear(); // dave added 9/27/03, accounts and player characters have a mutual
|
|
|
|
|
// reference that prevents them getting cleaned up
|
|
|
|
|
// properly. So clear the reference now.
|
|
|
|
|
chr->destroy();
|
|
|
|
|
//}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ObjectHash::hs::const_iterator ObjectHash::begin() const
|
|
|
|
|
{
|
|
|
|
|
return hash.begin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ObjectHash::hs::const_iterator ObjectHash::end() const
|
|
|
|
|
{
|
|
|
|
|
return hash.end();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ObjectHash::ds::const_iterator ObjectHash::dirty_deleted_begin() const
|
|
|
|
|
{
|
|
|
|
|
return dirty_deleted.begin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ObjectHash::ds::const_iterator ObjectHash::dirty_deleted_end() const
|
|
|
|
|
{
|
|
|
|
|
return dirty_deleted.end();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ObjectHash::ClearDeleted()
|
|
|
|
|
{
|
|
|
|
|
dirty_deleted.clear();
|
|
|
|
|
clean_deleted.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ObjectHash::CleanDeleted()
|
|
|
|
|
{
|
|
|
|
|
clean_deleted.insert( dirty_deleted.begin(), dirty_deleted.end() );
|
|
|
|
|
dirty_deleted.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ObjectHash::RegisterCleanDeletedSerial( u32 serial )
|
|
|
|
|
{
|
|
|
|
|
clean_deleted.insert( serial );
|
|
|
|
|
}
|
2023-11-13 14:23:36 +01:00
|
|
|
} // namespace Core
|
|
|
|
|
} // namespace Pol
|