uox3/source/ObjectFactory.cpp
2022-11-04 17:12:13 -04:00

504 lines
17 KiB
C++

// This class is responsible for the creation and destruction of ingame objects
#include "ObjectFactory.h"
#include "cChar.h" // Includes CChar
#include "cItem.h" // Includes CItem, CSpawnItem
#include "cMultiObj.h" // Includes CMultiObj, CBoatObj
#include <iostream>
#include <algorithm>
#include <climits>
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::SerialGen_st::SerialGen_st()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Constructor
//o------------------------------------------------------------------------------------------------o
ObjectFactory::SerialGen_st::SerialGen_st( UI32 initial ) :serialNumber( initial )
{
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::SerialGen_st::Next()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Return what next serial will be
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::SerialGen_st::Next() -> UI32
{
return serialNumber++;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::SerialGen_st::RegisterSerial()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Register next serial number in series
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::SerialGen_st::RegisterSerial(UI32 serial) -> void
{
if( serial >= serialNumber )
{
serialNumber = serial + 1;
}
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::SerialGen_st::UnregisterSerial()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Free up specified serial number if it was the last one registered
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::SerialGen_st::UnregisterSerial( UI32 serial ) -> void
{
if( serialNumber == ( serial + 1 ))
{
serialNumber = serial;
}
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::SerialGen_st::operator = ()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Override operators
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::SerialGen_st::operator = ( UI32 value ) ->SerialGen_st&
{
serialNumber = value;
return *this;
}
auto ObjectFactory::SerialGen_st::operator = ( SI32 value ) ->SerialGen_st&
{
serialNumber = static_cast<UI32>( value );
return *this;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::ObjectFactory()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Constructor
//|
//| Notes - Starting Characters with a serial of 1, rather than 0.
//| The UO Client doesn't always respond well to a serial of 0
//o------------------------------------------------------------------------------------------------o
ObjectFactory::ObjectFactory():item_serials( BASEITEMSERIAL ), character_serials( 1 )
{
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::GetSingleton()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Creates and returns singleton instance for object factory
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::GetSingleton() -> ObjectFactory&
{
static ObjectFactory instance;
return instance;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::NextSerial()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Finds the next free serial to use when creating an object of a given type
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::NextSerial( ObjectType type ) -> UI32
{
switch( type )
{
case OT_ITEM:
case OT_MULTI:
case OT_BOAT:
case OT_SPAWNER:
return item_serials.Next();
case OT_CHAR:
return character_serials.Next();
default:
return std::numeric_limits<UI32>::max();
}
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::CollectionForType()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Return collection of objects of specific type
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::CollectionForType( ObjectType type ) -> factory_collection*
{
factory_collection *collection = nullptr;
switch( type )
{
case OT_MULTI:
case OT_BOAT:
collection = &multis;
break;
case OT_SPAWNER:
case OT_ITEM:
collection = &items;
break;
case OT_CHAR:
collection = &chars;
break;
default:
break;
}
return collection;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::CollectionForType() const
//o------------------------------------------------------------------------------------------------o
//| Purpose - Return const collection of objects of specific type
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::CollectionForType( ObjectType type ) const -> const factory_collection*
{
const factory_collection *collection = nullptr;
switch( type )
{
case OT_MULTI:
case OT_BOAT:
collection = &multis;
break;
case OT_SPAWNER:
case OT_ITEM:
collection = &items;
break;
case OT_CHAR:
collection = &chars;
break;
default:
break;
}
return collection;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::FindCharacter()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Find and return item from collection based on specified serial
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::FindCharacter( UI32 serial ) ->CBaseObject*
{
auto iter = chars.find( serial );
if( iter != chars.end() )
{
return iter->second;
}
return nullptr;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::FindItem()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Find and return item from collection based on specified serial
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::FindItem( UI32 serial ) ->CBaseObject*
{
// We look for items first
CBaseObject *object = nullptr;
auto iter = items.find( serial );
if( iter != items.end() )
{
object = iter->second;
}
else
{
iter = multis.find( serial );
if( iter!= multis.end() )
{
object = iter->second;
}
}
return object;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::RemoveObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Erase object from collection, if found there
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::RemoveObject( UI32 serial, factory_collection *collection ) -> bool
{
auto rValue = false;
auto iter = collection->find( serial );
if( iter != collection->end() )
{
rValue = true;
collection->erase( iter );
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::RegisterObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - We want to register an object with the world, that previously
//| does not exist in our containers
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::RegisterObject( CBaseObject *object ) -> bool
{
auto rValue = false;
if( object )
{
rValue = this->RegisterObject( object, object->GetSerial() );
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::RegisterObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Register object using specified serial number
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::RegisterObject( CBaseObject *object, UI32 serial ) -> bool
{
auto rValue = false;
if( object )
{
switch( object->GetObjType() )
{
case OT_MULTI:
case OT_BOAT:
rValue = true;
item_serials.RegisterSerial( serial );
multis.insert_or_assign( serial, object );
break;
case OT_SPAWNER:
case OT_ITEM:
rValue = true;
item_serials.RegisterSerial( serial );
items.insert_or_assign( serial, object );
break;
case OT_CHAR:
rValue = true;
character_serials.RegisterSerial( serial );
chars.insert_or_assign( serial, object );
break;
default:
break;
}
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::UnregisterObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Remove object from collection - but don't destroy it
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::UnregisterObject( CBaseObject *object ) -> bool
{
auto rValue = false;
if( object )
{
auto collection = CollectionForType( object->GetObjType() );
rValue = RemoveObject( object->GetSerial(), collection );
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::IterateOver()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Iterate over all objects of a specified object type
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::IterateOver( ObjectType type, UI32 &b, void *extra, std::function<bool( CBaseObject*, UI32 &, void * )> function ) -> UI32
{
auto collection = CollectionForType( type );
if( collection )
{
// less safe way
for( auto [serial, object] : *collection )
{
if( object )
{
if( !function( object, b, extra ))
{
break;
}
}
}
return 0;
}
return 0xFFFFFFFF;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::DestroyObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Unregister object and destroy it from memory, either as part of server shutdown,
//| or because object has been deleted.
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::DestroyObject( CBaseObject *object ) -> bool
{
auto rValue = false;
if( object )
{
UnregisterObject( object );
delete object;
object = nullptr;
rValue = true;
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::CreateObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Create a new object with a serial number, and return it back to the creator
//| From DFNs, or a PC, by and large.
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::CreateObject( ObjectType type ) -> CBaseObject *
{
auto object = CreateBlankObject( type );
if( object )
{
object->SetSerial(NextSerial( type ));
}
return object;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::CreateBlankObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Create a new blank object without a serial number. Serial will be provided
//| when loading object from worldfiles
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::CreateBlankObject( ObjectType type ) ->CBaseObject *
{
CBaseObject *object = nullptr;
switch( type )
{
case OT_ITEM:
object = new CItem();
break;
case OT_MULTI:
object = new CMultiObj();
break;
case OT_BOAT:
object = new CBoatObj();
break;
case OT_SPAWNER:
object = new CSpawnItem();
break;
case OT_CHAR:
object = new CChar();
break;
default:
break;
}
return object;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::FindObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Calculate and return object from provided serial
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::FindObject( UI32 serial ) -> CBaseObject *
{
CBaseObject *object = nullptr;
if( serial >= BASEITEMSERIAL )
{
object = FindItem( serial );
}
else
{
object = FindCharacter( serial );
}
return object;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::CountOfObjects()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns the amount of objects that exist of a given object type
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::CountOfObjects( ObjectType type ) const -> UI32
{
auto rValue = UI32( 0 );
auto collection = CollectionForType( type );
if( collection )
{
rValue = static_cast<UI32>( collection->size() );
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::SizeOfObjects()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns the size of memory allocated to given object type
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::SizeOfObjects( ObjectType type ) const -> size_t
{
auto collection = CollectionForType( type );
auto size = size_t( 0 );
switch( type )
{
case OT_ITEM:
case OT_SPAWNER:
size = sizeof( CItem );
break;
case OT_MULTI:
case OT_BOAT:
size = sizeof( CMultiObj );
break;
case OT_CHAR:
size = sizeof( CChar );
break;
default:
break;
}
return collection->size() * size;
}
//o------------------------------------------------------------------------------------------------o
//| Function - ObjectFactory::ValidObject()
//o------------------------------------------------------------------------------------------------o
//| Purpose - (Unused) Checks if specified object is a valid object of specified type
//o------------------------------------------------------------------------------------------------o
auto ObjectFactory::ValidObject( CBaseObject *object, ObjectType type ) -> bool
{
auto findObject = []( CBaseObject* object, factory_collection &collect )
{
auto iter = std::find_if( collect.begin(), collect.end(), [object] ( std::pair<UI32, CBaseObject *> entry )
{
return entry.second = object;
});
if( iter != collect.end() )
{
return true;
}
return false;
};
auto rValue = false;
if( type == ObjectType::OT_CHAR )
{
rValue = findObject( object, chars );
}
else if(( type == ObjectType::OT_BOAT ) || ( type == ObjectType::OT_MULTI ))
{
rValue = findObject( object, multis );
}
else if(( type == ObjectType::OT_ITEM ) || ( type == ObjectType::OT_SPAWNER ))
{
rValue = findObject( object, items );
}
else
{
rValue = findObject( object, chars );
if( !rValue )
{
rValue = findObject( object, items );
if( !rValue )
{
rValue = findObject( object, multis );
}
}
}
return rValue;
}