polserver/pol-core/pol/storage.cpp
turleypol 24c8c8b92f
Tidy modernize for loops (#862)
* trigger loop convert

* Automated clang-tidy change: modernize-loop-convert

* fixed refactor

* Automated clang-tidy change: modernize-loop-convert

* compile

* first look through

* fixes and start to use a few ranges

* revert autogenerated file

* compilation fix

* second pass

* renamed loop variable

---------

Co-authored-by: Clang Tidy <clang-tidy@users.noreply.github.com>
2026-01-31 09:14:02 +01:00

418 lines
9.4 KiB
C++

/** @file
*
* @par History
* - 2005/11/26 Shinigami: changed "strcmp" into "stricmp" to suppress Script Errors
*/
#include "storage.h"
#include <exception>
#include <string>
#include <time.h>
#include "../bscript/berror.h"
#include "../bscript/bobject.h"
#include "../bscript/contiter.h"
#include "../bscript/impstr.h"
#include "../clib/cfgelem.h"
#include "../clib/cfgfile.h"
#include "../clib/clib.h"
#include "../clib/logfacility.h"
#include "../clib/rawtypes.h"
#include "../clib/stlutil.h"
#include "../clib/streamsaver.h"
#include "../plib/poltype.h"
#include "../plib/systemstate.h"
#include "containr.h"
#include "fnsearch.h"
#include "globals/object_storage.h"
#include "globals/uvars.h"
#include "item/item.h"
#include "loaddata.h"
#include "mkscrobj.h"
#include "ufunc.h"
namespace Pol::Core
{
using namespace Bscript;
StorageArea::StorageArea( std::string name ) : _name( name ) {}
StorageArea::~StorageArea()
{
while ( !_items.empty() )
{
Cont::iterator itr = _items.begin();
Items::Item* item = ( *itr ).second;
item->destroy();
_items.erase( itr );
}
}
size_t StorageArea::estimateSize() const
{
size_t size = _name.capacity() + Clib::memsize( _items );
return size;
}
Items::Item* StorageArea::find_root_item( const std::string& name )
{
// LINEAR_SEARCH
Cont::iterator itr = _items.find( name );
if ( itr != _items.end() )
{
return ( *itr ).second;
}
return nullptr;
}
bool StorageArea::delete_root_item( const std::string& name )
{
Cont::iterator itr = _items.find( name );
if ( itr != _items.end() )
{
Items::Item* item = ( *itr ).second;
item->destroy();
_items.erase( itr );
return true;
}
return false;
}
void StorageArea::insert_root_item( Items::Item* item )
{
item->inuse( true );
_items.insert( make_pair( item->name(), item ) );
}
extern Items::Item* read_item( Clib::ConfigElem& elem ); // from UIMPORT.CPP
void StorageArea::load_item( Clib::ConfigElem& elem )
{
u32 container_serial = 0; // defaults to item at storage root,
(void)elem.remove_prop( "CONTAINER", &container_serial ); // so the return value can be ignored
Items::Item* item = read_item( elem );
// Austin added 8/10/2006, protect against further crash if item is null. Should throw instead?
if ( item == nullptr )
{
elem.warn_with_line( "Error reading item SERIAL or OBJTYPE." );
return;
}
if ( container_serial == 0 )
{
insert_root_item( item );
}
else
{
Items::Item* cont_item = Core::system_find_item( container_serial );
if ( cont_item )
{
add_loaded_item( cont_item, item );
}
else
{
defer_item_insertion( item, container_serial );
}
}
}
StorageArea* Storage::find_area( const std::string& name )
{
AreaCont::iterator itr = areas.find( name );
if ( itr == areas.end() )
return nullptr;
return ( *itr ).second;
}
StorageArea* Storage::create_area( const std::string& name )
{
AreaCont::iterator itr = areas.find( name );
if ( itr == areas.end() )
{
StorageArea* area = new StorageArea( name );
areas[name] = area;
return area;
}
return ( *itr ).second;
}
StorageArea* Storage::create_area( Clib::ConfigElem& elem )
{
const char* rest = elem.rest();
if ( rest != nullptr && rest[0] )
{
return create_area( rest );
}
std::string name = elem.remove_string( "NAME" );
return create_area( name );
}
void StorageArea::print( Clib::StreamWriter& sw ) const
{
for ( const auto& cont_item : _items )
{
const Items::Item* item = cont_item.second;
if ( item->saveonexit() )
item->printOn( sw );
}
}
void StorageArea::on_delete_realm( Realms::Realm* realm )
{
for ( const auto& _item : _items )
{
Items::Item* item = _item.second;
if ( item )
{
setrealmif( item, (void*)realm );
if ( item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
{
UContainer* cont = static_cast<UContainer*>( item );
cont->for_each_item( setrealmif, (void*)realm );
}
}
}
}
void Storage::on_delete_realm( Realms::Realm* realm )
{
for ( const auto& area : areas )
{
area.second->on_delete_realm( realm );
}
}
void Storage::read( Clib::ConfigFile& cf )
{
static int num_until_dot = 1000;
unsigned int nobjects = 0;
StorageArea* area = nullptr;
Clib::ConfigElem elem;
clock_t start = clock();
while ( cf.read( elem ) )
{
if ( --num_until_dot == 0 )
{
INFO_PRINT( "." );
num_until_dot = 1000;
}
if ( elem.type_is( "StorageArea" ) )
{
area = create_area( elem );
}
else if ( elem.type_is( "Item" ) )
{
if ( area != nullptr )
{
try
{
area->load_item( elem );
}
catch ( std::exception& )
{
if ( !Plib::systemstate.config.ignore_load_errors )
throw;
}
}
else
{
ERROR_PRINTLN( "Storage: Got an ITEM element, but don't have a StorageArea to put it." );
throw std::runtime_error( "Data file integrity error" );
}
}
else
{
ERROR_PRINTLN( "Unexpected element type {} in storage file.", elem.type() );
throw std::runtime_error( "Data file integrity error" );
}
++nobjects;
}
clock_t end = clock();
int ms = static_cast<int>( ( end - start ) * 1000.0 / CLOCKS_PER_SEC );
INFO_PRINTLN( " {} elements in {} ms.", nobjects, ms );
}
void Storage::print( Clib::StreamWriter& sw ) const
{
for ( const auto& area : areas )
{
sw.begin( "StorageArea" );
sw.add( "Name", area.first );
sw.end();
area.second->print( sw );
}
}
void Storage::clear()
{
while ( !areas.empty() )
{
delete ( ( *areas.begin() ).second );
areas.erase( areas.begin() );
}
}
size_t Storage::estimateSize() const
{
size_t size = Clib::memsize( areas );
for ( const auto& area : areas )
{
if ( area.second != nullptr )
size += area.second->estimateSize();
}
return size;
}
class StorageAreaIterator final : public ContIterator
{
public:
StorageAreaIterator( StorageArea* area, BObject* pIter );
BObject* step() override;
private:
BObject* m_pIterVal;
std::string key;
StorageArea* _area;
};
StorageAreaIterator::StorageAreaIterator( StorageArea* area, BObject* pIter )
: ContIterator(), m_pIterVal( pIter ), key( "" ), _area( area )
{
}
BObject* StorageAreaIterator::step()
{
StorageArea::Cont::iterator itr = _area->_items.lower_bound( key );
if ( !key.empty() && itr != _area->_items.end() )
{
++itr;
}
if ( itr == _area->_items.end() )
return nullptr;
key = ( *itr ).first;
m_pIterVal->setimp( new String( key ) );
BObject* result = new BObject( make_itemref( ( *itr ).second ) );
return result;
}
ContIterator* StorageAreaImp::createIterator( BObject* pIterVal )
{
return new StorageAreaIterator( _area, pIterVal );
}
BObjectRef StorageAreaImp::get_member( const char* membername )
{
if ( stricmp( membername, "count" ) == 0 )
{
return BObjectRef( new BLong( static_cast<int>( _area->_items.size() ) ) );
}
if ( stricmp( membername, "totalcount" ) == 0 )
{
unsigned int total = 0;
for ( auto& _item : _area->_items )
{
Items::Item* item = _item.second;
total += item->item_count();
}
return BObjectRef( new BLong( total ) );
}
return BObjectRef( UninitObject::create() );
}
class StorageAreasIterator final : public ContIterator
{
public:
StorageAreasIterator( BObject* pIter );
BObject* step() override;
private:
BObject* m_pIterVal;
std::string key;
};
StorageAreasIterator::StorageAreasIterator( BObject* pIter )
: ContIterator(), m_pIterVal( pIter ), key( "" )
{
}
BObject* StorageAreasIterator::step()
{
Storage::AreaCont::iterator itr = gamestate.storage.areas.lower_bound( key );
if ( !key.empty() && itr != gamestate.storage.areas.end() )
{
++itr;
}
if ( itr == gamestate.storage.areas.end() )
return nullptr;
key = ( *itr ).first;
m_pIterVal->setimp( new String( key ) );
BObject* result = new BObject( new StorageAreaImp( ( *itr ).second ) );
return result;
}
class StorageAreasImp final : public BObjectImp
{
public:
StorageAreasImp() : BObjectImp( BObjectImp::OTUnknown ) {}
BObjectImp* copy() const override { return new StorageAreasImp(); }
std::string getStringRep() const override { return "<StorageAreas>"; }
size_t sizeEstimate() const override { return sizeof( *this ); }
ContIterator* createIterator( BObject* pIterVal ) override
{
return new StorageAreasIterator( pIterVal );
}
BObjectRef get_member( const char* membername ) override;
BObjectRef OperSubscript( const BObject& obj ) override;
};
BObjectImp* CreateStorageAreasImp()
{
return new StorageAreasImp();
}
BObjectRef StorageAreasImp::get_member( const char* membername )
{
if ( stricmp( membername, "count" ) == 0 )
{
return BObjectRef( new BLong( static_cast<int>( gamestate.storage.areas.size() ) ) );
}
return BObjectRef( UninitObject::create() );
}
BObjectRef StorageAreasImp::OperSubscript( const BObject& obj )
{
if ( obj.isa( OTString ) )
{
String& rtstr = (String&)obj.impref();
std::string key = rtstr.value();
Storage::AreaCont::iterator itr = gamestate.storage.areas.find( key );
if ( itr != gamestate.storage.areas.end() )
{
return BObjectRef( new BObject( new StorageAreaImp( ( *itr ).second ) ) );
}
return BObjectRef( new BObject( new BError( "Storage Area not found" ) ) );
}
return BObjectRef( new BObject( new BError( "Invalid parameter type" ) ) );
}
} // namespace Pol::Core