mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
* 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>
418 lines
9.4 KiB
C++
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
|