2019-07-07 20:56:15 +00:00
# include <StdAfx.h>
2018-03-29 17:01:57 -04:00
# include "World.h"
2020-07-07 20:22:20 +00:00
# include "InferredCellData.h"
2018-03-29 17:01:57 -04:00
# include "Client.h"
# include "WeenieObject.h"
# include "PhysicsObj.h"
# include "Monster.h"
# include "Player.h"
# include "ChatMsgs.h"
# include "WorldLandBlock.h"
# include "WClassID.h"
# include "Database.h"
# include "GameMode.h"
# include "Config.h"
# include "Server.h"
# include "House.h"
2019-07-07 20:56:15 +00:00
# include "HouseManager.h"
2020-04-20 23:56:09 -07:00
# include "GameEventManager.h"
2018-03-29 17:01:57 -04:00
CWorld : : CWorld ( )
{
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " Initializing World.. \n " ) ;
2018-04-27 21:03:39 -07:00
SERVER_INFO < < " Initializing World.. " ;
2019-07-07 20:56:15 +00:00
// ZeroMemory(m_pBlocks, sizeof(m_pBlocks));
memset ( m_pBlocks , 0 , sizeof ( m_pBlocks ) ) ;
2018-03-29 17:01:57 -04:00
LoadDungeonsFile ( ) ;
LoadMOTD ( ) ;
EnumerateDungeonsFromCellData ( ) ;
if ( g_pHouseManager )
g_pHouseManager - > Load ( ) ;
m_mAllObjects . reserve ( 10000000 ) ;
m_mAllPlayers . reserve ( 5000 ) ;
m_fLastSave = g_pGlobals - > Time ( ) ;
}
void CWorld : : SaveWorld ( )
{
SaveDungeonsFile ( ) ;
if ( g_pHouseManager )
g_pHouseManager - > Save ( ) ;
}
CWorld : : ~ CWorld ( )
{
2020-09-13 17:46:03 -07:00
//if (m_pGameMode)
//{
// delete m_pGameMode;
// m_pGameMode = NULL;
//}
2018-03-29 17:01:57 -04:00
for ( auto block : m_vBlocks )
{
if ( block )
{
m_pBlocks [ block - > GetHeader ( ) ] = NULL ;
delete block ;
}
}
m_vBlocks . clear ( ) ;
for ( auto blockEntry : m_mDormantBlocks )
{
if ( CWorldLandBlock * block = blockEntry . second )
{
m_pBlocks [ block - > GetHeader ( ) ] = NULL ;
delete block ;
}
}
m_mDormantBlocks . clear ( ) ;
for ( auto blockEntry : m_mUnloadedBlocks )
{
if ( CWorldLandBlock * block = blockEntry . second )
{
m_pBlocks [ block - > GetHeader ( ) ] = NULL ;
delete block ;
}
}
m_mUnloadedBlocks . clear ( ) ;
SaveWorld ( ) ;
m_mDungeons . clear ( ) ;
for ( auto & dungeonDescEntry : m_mDungeonDescs )
{
DungeonDesc_t * pDungeonDesc = & dungeonDescEntry . second ;
SafeDeleteArray ( pDungeonDesc - > szDungeonName ) ;
SafeDeleteArray ( pDungeonDesc - > szDescription ) ;
SafeDeleteArray ( pDungeonDesc - > szAuthor ) ;
}
m_mDungeonDescs . clear ( ) ;
}
2020-07-07 20:22:20 +00:00
void CWorld : : Init ( )
{
std : : list < uint32_t > preload = g_pCellDataEx - > GetAlwaysLoaded ( ) ;
SERVER_INFO < < " Preloading " < < preload . size ( ) < < " blocks " ;
for ( auto id : preload )
ActivateBlock ( id > > 16 ) - > NeverGoDormant ( ) ;
}
2018-03-29 17:01:57 -04:00
Position CWorld : : FindDungeonDrop ( )
{
if ( m_mDungeons . empty ( ) )
{
return Position ( ) ;
}
LocationMap : : iterator dit = m_mDungeons . begin ( ) ;
long index = Random : : GenUInt ( 0 , ( long ) m_mDungeons . size ( ) - 1 ) ;
while ( index > 0 ) {
index - - ;
dit + + ;
}
return dit - > second ;
}
Position CWorld : : FindDungeonDrop ( WORD wBlockID )
{
2019-07-07 20:56:15 +00:00
LocationMap : : iterator i = m_mDungeons . upper_bound ( ( ( uint32_t ( wBlockID ) < < 16 ) + 0x100 ) - 1 ) ;
2018-03-29 17:01:57 -04:00
if ( ( i = = m_mDungeons . end ( ) ) | | ( BLOCK_WORD ( i - > second . objcell_id ) ! = wBlockID ) )
{
return Position ( ) ;
}
return i - > second ;
}
const char * CWorld : : GetMOTD ( )
{
return m_strMOTD . c_str ( ) ;
}
void CWorld : : LoadMOTD ( )
{
FILE * motd = g_pDB - > DataFileOpen ( " motd.txt " , " rt " ) ;
if ( motd )
{
long lFileSize = fsize ( motd ) ;
char * pcFileData = new char [ lFileSize + 1 ] ;
long lEnd = ( long ) fread ( pcFileData , sizeof ( char ) , lFileSize , motd ) ;
pcFileData [ lEnd ] = 0 ;
m_strMOTD = pcFileData ;
delete [ ] pcFileData ;
fclose ( motd ) ;
}
else
m_strMOTD = " No MOTD set. " ;
}
void CWorld : : LoadDungeonsFile ( )
{
FILE * wd = g_pDB - > DataFileOpen ( " worlddesc " ) ;
if ( wd )
{
long lSize = fsize ( wd ) ;
BYTE * pbData = new BYTE [ lSize ] ;
long lRead = ( long ) fread ( pbData , sizeof ( BYTE ) , lSize , wd ) ;
BinaryReader input ( pbData , lRead ) ;
2019-07-07 20:56:15 +00:00
uint32_t dwDungeonCount = input . ReadUInt32 ( ) ;
2018-03-29 17:01:57 -04:00
if ( ! input . GetLastError ( ) )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < dwDungeonCount ; i + + )
2018-03-29 17:01:57 -04:00
{
DungeonDesc_t dd ;
2019-07-07 20:56:15 +00:00
dd . wBlockID = input . ReadUInt16 ( ) ;
2018-03-29 17:01:57 -04:00
dd . szDungeonName = input . ReadString ( ) ;
dd . szAuthor = input . ReadString ( ) ;
dd . szDescription = input . ReadString ( ) ;
dd . position . UnPack ( & input ) ;
if ( input . GetLastError ( ) ) break ;
// avoid using a buffer thats going to be deleted
2019-07-07 20:56:15 +00:00
dd . szDungeonName = strdup ( dd . szDungeonName ) ;
dd . szAuthor = strdup ( dd . szAuthor ) ;
dd . szDescription = strdup ( dd . szDescription ) ;
2018-03-29 17:01:57 -04:00
m_mDungeonDescs [ dd . wBlockID ] = dd ;
}
}
delete [ ] pbData ;
fclose ( wd ) ;
}
}
void CWorld : : SaveDungeonsFile ( )
{
FILE * wd = g_pDB - > DataFileCreate ( " worlddesc " ) ;
if ( wd )
{
BinaryWriter output ;
2019-07-07 20:56:15 +00:00
output . Write < uint32_t > ( ( uint32_t ) m_mDungeonDescs . size ( ) ) ;
2018-03-29 17:01:57 -04:00
for ( DungeonDescMap : : iterator i = m_mDungeonDescs . begin ( ) ; i ! = m_mDungeonDescs . end ( ) ; i + + )
{
output . Write < WORD > ( i - > second . wBlockID ) ;
output . WriteString ( i - > second . szDungeonName ) ;
output . WriteString ( i - > second . szAuthor ) ;
output . WriteString ( i - > second . szDescription ) ;
i - > second . position . Pack ( & output ) ;
}
fwrite ( output . GetData ( ) , output . GetSize ( ) , sizeof ( BYTE ) , wd ) ;
fclose ( wd ) ;
}
else
2019-07-07 20:56:15 +00:00
//MsgBox(MB_ICONHAND, "Error opening WorldDesc file! Close NOW to avoid corruption!");
SERVER_ERROR < < " Error opening WorldDesc file! Close NOW to avoid corruption! " ;
2018-03-29 17:01:57 -04:00
}
BOOL CWorld : : DungeonExists ( WORD wBlockID )
{
2019-07-07 20:56:15 +00:00
LocationMap : : iterator i = m_mDungeons . upper_bound ( ( ( uint32_t ( wBlockID ) < < 16 ) + 0x100 ) - 1 ) ;
2018-03-29 17:01:57 -04:00
if ( ( i = = m_mDungeons . end ( ) ) | | ( BLOCK_WORD ( i - > second . objcell_id ) ! = wBlockID ) )
return FALSE ;
return TRUE ;
}
LocationMap * CWorld : : GetDungeons ( )
{
return & m_mDungeons ;
}
DungeonDescMap * CWorld : : GetDungeonDescs ( )
{
return & m_mDungeonDescs ;
}
DungeonDesc_t * CWorld : : GetDungeonDesc ( const char * szDungeonName )
{
DungeonDescMap : : iterator i = m_mDungeonDescs . begin ( ) ;
DungeonDescMap : : iterator iend = m_mDungeonDescs . end ( ) ;
2018-10-22 20:12:51 -05:00
std : : string dungeonName = " " ;
std : : string searchName = szDungeonName ;
2018-03-29 17:01:57 -04:00
while ( i ! = iend )
{
2018-10-22 20:12:51 -05:00
dungeonName = i - > second . szDungeonName ;
std : : transform ( dungeonName . begin ( ) , dungeonName . end ( ) , dungeonName . begin ( ) , : : tolower ) ;
std : : transform ( searchName . begin ( ) , searchName . end ( ) , searchName . begin ( ) , : : tolower ) ;
2018-10-22 22:43:53 -05:00
if ( dungeonName . find ( searchName ) ! = std : : string : : npos )
2018-03-29 17:01:57 -04:00
return & i - > second ;
i + + ;
}
return NULL ;
}
DungeonDesc_t * CWorld : : GetDungeonDesc ( WORD wBlockID )
{
DungeonDescMap : : iterator it = m_mDungeonDescs . find ( wBlockID ) ;
if ( it ! = m_mDungeonDescs . end ( ) )
return & it - > second ;
else
return NULL ;
}
void CWorld : : SetDungeonDesc ( WORD wBlockID , const char * szDungeonName , const char * szAuthor , const char * szDescription , const Position & position )
{
DungeonDescMap : : iterator it = m_mDungeonDescs . find ( wBlockID ) ;
if ( it ! = m_mDungeonDescs . end ( ) )
{
DungeonDesc_t * pdd = & it - > second ;
SafeDeleteArray ( pdd - > szDungeonName ) ;
SafeDeleteArray ( pdd - > szDescription ) ;
SafeDeleteArray ( pdd - > szAuthor ) ;
m_mDungeonDescs . erase ( it ) ;
}
DungeonDesc_t dd ;
dd . wBlockID = wBlockID ;
2019-07-07 20:56:15 +00:00
dd . szDungeonName = strdup ( szDungeonName ) ;
dd . szAuthor = strdup ( szAuthor ) ;
dd . szDescription = strdup ( szDescription ) ;
2018-03-29 17:01:57 -04:00
dd . position = position ;
m_mDungeonDescs [ wBlockID ] = dd ;
}
void CWorld : : ClearAllSpawns ( )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < ( 256 * 256 ) ; i + + )
2018-03-29 17:01:57 -04:00
{
if ( m_pBlocks [ i ] )
m_pBlocks [ i ] - > ClearSpawns ( ) ;
}
}
CWorldLandBlock * CWorld : : GetLandblock ( WORD wHeader , bool bActivate )
{
CWorldLandBlock * pBlock = m_pBlocks [ wHeader ] ;
if ( ! pBlock & & bActivate )
{
pBlock = ActivateBlock ( wHeader ) ;
}
return pBlock ;
}
CWorldLandBlock * CWorld : : ActivateBlock ( WORD wHeader )
{
CWorldLandBlock * * ppBlock = & m_pBlocks [ wHeader ] ;
CWorldLandBlock * pBlock ;
# if _DEBUG
pBlock = * ppBlock ;
if ( pBlock ! = NULL )
{
2018-04-27 21:03:39 -07:00
SERVER_INFO < < " Landblock already active! " ;
2018-03-29 17:01:57 -04:00
return pBlock ;
}
# endif
// make sure this isn't already in our spawned blocked...
pBlock = new CWorldLandBlock ( this , wHeader ) ;
m_vSpawns . push_back ( pBlock ) ;
* ppBlock = pBlock ;
pBlock - > Init ( ) ;
return pBlock ;
}
2018-07-12 14:41:21 -07:00
bool CWorld : : CreateEntity ( CWeenieObject * pEntity , bool bMakeAware )
2018-03-29 17:01:57 -04:00
{
if ( ! pEntity )
return false ;
2018-07-12 14:41:21 -07:00
CWeenieObject * pExistingWeenie = FindObject ( pEntity - > GetID ( ) ) ;
2019-02-10 00:05:58 +00:00
if ( pExistingWeenie )
2018-03-29 17:01:57 -04:00
{
if ( pExistingWeenie = = pEntity )
{
LOG_PRIVATE ( World , Warning , " Trying to spawn weenie twice! ID 0x%08X \n " ) ;
return true ;
}
else
{
2020-07-07 13:39:25 -07:00
//LOG_PRIVATE(World, Warning, "Trying to spawn second (different) weenie with existing ID 0x%08X! Deleting instead.\n", pEntity->GetID());
2018-07-12 14:41:21 -07:00
2019-02-10 00:05:58 +00:00
// Already exists.
delete pEntity ;
2018-03-29 17:01:57 -04:00
}
2019-02-10 00:05:58 +00:00
return false ;
2018-03-29 17:01:57 -04:00
}
double createTime ;
if ( ! pEntity - > m_Qualities . InqFloat ( CREATION_TIMESTAMP_FLOAT , createTime ) )
pEntity - > m_Qualities . SetFloat ( CREATION_TIMESTAMP_FLOAT , Timer : : cur_time ) ;
2018-11-09 00:21:21 +00:00
int lifespan = pEntity - > m_Qualities . GetInt ( LIFESPAN_INT , 0 ) ;
if ( lifespan & & ! pEntity - > m_Qualities . GetInt ( CREATION_TIMESTAMP_INT , 0 ) )
{
time_t t = std : : chrono : : system_clock : : to_time_t ( std : : chrono : : system_clock : : now ( ) ) ;
pEntity - > m_Qualities . SetInt ( CREATION_TIMESTAMP_INT , t ) ;
pEntity - > _timeToRot = Timer : : cur_time + lifespan ;
}
2018-03-29 17:01:57 -04:00
if ( ! pEntity - > GetID ( ) )
{
2019-11-13 20:57:17 +00:00
pEntity - > SetID ( CreateWorldID ( pEntity ) ) ;
2018-03-29 17:01:57 -04:00
}
if ( pEntity - > AsPlayer ( ) & & pEntity - > AsPlayer ( ) - > GetClient ( ) )
{
m_mAllPlayers [ pEntity - > GetID ( ) ] = pEntity - > AsPlayer ( ) ;
if ( g_pConfig - > ShowLogins ( ) & & pEntity - > m_Qualities . id = = W_HUMAN_CLASS ) // Admins playing as creatures should not show as logging in
{
BroadcastGlobal ( ServerBroadcast ( " System " , csprintf ( " %s has logged in. " , pEntity - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) , PRIVATE_MSG , pEntity - > GetID ( ) , FALSE , TRUE ) ;
}
}
m_mAllObjects [ pEntity - > GetID ( ) ] = pEntity ;
2020-05-24 22:25:54 -07:00
//std::string eventString;
//if (pEntity->m_Qualities.InqString(GENERATOR_EVENT_STRING, eventString))
//{
// _eventWeenies.insert(std::pair<std::string, uint32_t>(eventString, pEntity->GetID()));
// GameEventDef *ed = g_pGameEventManager->GetEvent(eventString.c_str());
// if (ed)
// pEntity->CheckEventState(eventString, ed);
//}
2018-03-29 17:01:57 -04:00
pEntity - > InitPhysicsObj ( ) ;
pEntity - > SetupWeenie ( ) ;
pEntity - > RecacheHasOwner ( ) ;
if ( pEntity - > m_Position . objcell_id )
{
Position startPos = pEntity - > m_Position ;
pEntity - > enter_world ( & startPos ) ;
if ( ! pEntity - > m_Position . objcell_id )
{
LOG_PRIVATE ( World , Warning , " Trying to spawn a weenie in an invalid position! Deleting instead. \n " , pEntity - > GetID ( ) ) ;
RemoveEntity ( pEntity ) ;
// Bad spawn position.
// delete pEntity;
return false ;
}
if ( ! pEntity - > CachedHasOwner ( ) )
{
WORD wHeader = BLOCK_WORD ( pEntity - > GetLandcell ( ) ) ;
CWorldLandBlock * pBlock = m_pBlocks [ wHeader ] ;
if ( ! pBlock )
{
pBlock = ActivateBlock ( wHeader ) ;
}
pEntity - > PreSpawnCreate ( ) ;
pBlock - > Insert ( pEntity , 0 , TRUE , bMakeAware ) ;
}
}
else
{
pEntity - > PreSpawnCreate ( ) ;
}
if ( bMakeAware )
2019-10-04 18:02:31 -07:00
pEntity - > MakeAware ( pEntity , true ) ;
2018-03-29 17:01:57 -04:00
2020-05-24 22:25:54 -07:00
std : : string eventString ;
if ( pEntity - > m_Qualities . InqString ( GENERATOR_EVENT_STRING , eventString ) )
{
_eventWeenies . insert ( std : : pair < std : : string , uint32_t > ( eventString , pEntity - > GetID ( ) ) ) ;
GameEventDef * ed = g_pGameEventManager - > GetEvent ( eventString . c_str ( ) ) ;
if ( ed )
pEntity - > CheckEventState ( eventString , ed ) ;
}
else
pEntity - > InitCreateGenerator ( ) ;
2018-03-29 17:01:57 -04:00
pEntity - > PostSpawn ( ) ;
if ( pEntity - > cell )
{
assert ( pEntity - > GetLandcell ( ) = = pEntity - > cell - > id ) ;
}
# ifdef _DEBUG
2020-05-29 01:34:33 -07:00
SERVER_INFO < < " Spawned ID " < < pEntity - > GetID ( ) < < " - " < < pEntity - > GetName ( ) . c_str ( ) < < " memory object @ " < < ( uint64_t ) pEntity ;
2018-03-29 17:01:57 -04:00
# endif
return true ;
}
2019-11-13 20:57:17 +00:00
uint32_t CWorld : : CreateWorldID ( CWeenieObject * pEntity )
{
bool useEphemeral = ( pEntity - > m_PhysicsState & MISSILE_PS )
// player corpses are invisible at create time
2020-03-16 18:15:40 +00:00
| | ( pEntity - > IsCorpse ( ) & & pEntity - > m_Qualities . GetBool ( VISIBILITY_BOOL , true ) )
| | pEntity - > IsStuck ( )
;
2019-11-13 20:57:17 +00:00
if ( pEntity - > GetWorldTopLevelOwner ( ) & & pEntity - > GetWorldTopLevelOwner ( ) - > m_Qualities . GetInt ( MERCHANDISE_ITEM_TYPES_INT , 0 ) > 0 )
useEphemeral = true ;
2020-08-07 21:29:08 -07:00
uint32_t isPlayerRange = 0 ;
if ( pEntity - > m_Qualities . InqInstanceID ( VICTIM_IID , isPlayerRange ) & & isPlayerRange > = 1342177280 & & isPlayerRange < = 1610612735 )
useEphemeral = false ;
2019-11-13 20:57:17 +00:00
return GenerateGUID ( useEphemeral ? eEphemeral : eDynamicGUID ) ;
}
2018-03-29 17:01:57 -04:00
void CWorld : : InsertTeleportLocation ( TeleTownList_s l )
{
m_vTeleTown . push_back ( l ) ;
}
std : : string CWorld : : GetTeleportList ( )
{
std : : string result ;
2019-07-07 20:56:15 +00:00
for ( TeleTownList_s var : m_vTeleTown )
2018-03-29 17:01:57 -04:00
{
result . append ( var . m_teleString ) . append ( " , " ) ;
}
if ( ! result . empty ( ) & & result . back ( ) = = 0x20 ) { //Get out behind of bad formatting
result . pop_back ( ) ;
result . pop_back ( ) ;
}
return result ;
}
TeleTownList_s CWorld : : GetTeleportLocation ( std : : string location )
{
TeleTownList_s val ;
std : : transform ( location . begin ( ) , location . end ( ) , location . begin ( ) , : : tolower ) ;
2019-07-07 20:56:15 +00:00
for ( TeleTownList_s var : m_vTeleTown )
2018-03-29 17:01:57 -04:00
{
//Lets waste a bunch of time with this.. Hey, if its the first one on the list its O(1)
std : : string town = var . m_teleString ;
std : : transform ( town . begin ( ) , town . end ( ) , town . begin ( ) , : : tolower ) ;
2018-10-22 15:56:09 -05:00
if ( town [ 0 ] = = location [ 0 ] & & town . find ( location ) ! = std : : string : : npos ) {
2018-03-29 17:01:57 -04:00
val = var ;
break ;
}
}
return val ;
}
2018-07-12 14:41:21 -07:00
void CWorld : : InsertEntity ( CWeenieObject * pEntity , BOOL bSilent )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
uint32_t cell_id = pEntity - > GetLandcell ( ) ;
2018-03-29 17:01:57 -04:00
if ( cell_id & & ! pEntity - > HasOwner ( ) )
{
WORD wHeader = BLOCK_WORD ( cell_id ) ;
CWorldLandBlock * pBlock = m_pBlocks [ wHeader ] ;
if ( ! pBlock )
{
pBlock = ActivateBlock ( wHeader ) ;
}
if ( bSilent )
pBlock - > Insert ( pEntity , wHeader ) ;
else
pBlock - > Insert ( pEntity ) ;
}
// these should not be necessary... ?
if ( pEntity - > AsPlayer ( ) )
{
m_mAllPlayers [ pEntity - > GetID ( ) ] = pEntity - > AsPlayer ( ) ;
}
m_mAllObjects [ pEntity - > GetID ( ) ] = pEntity ;
}
2018-07-12 14:41:21 -07:00
void CWorld : : JuggleEntity ( WORD wOld , CWeenieObject * pEntity )
2018-03-29 17:01:57 -04:00
{
if ( ! pEntity - > HasOwner ( ) )
{
WORD wHeader = BLOCK_WORD ( pEntity - > GetLandcell ( ) ) ;
CWorldLandBlock * pBlock = GetLandblock ( wHeader ) ;
if ( ! pBlock )
{
pBlock = ActivateBlock ( wHeader ) ;
}
if ( pEntity - > _IsPlayer ( ) | | pBlock - > IsTickingWithWorld ( ) )
{
pBlock - > Insert ( pEntity , wOld ) ;
}
else
{
if ( pEntity - > ShouldSave ( ) )
{
pEntity - > Save ( ) ;
}
EnsureRemoved ( pEntity ) ;
2019-07-07 20:56:15 +00:00
uint32_t RemoveObject [ 3 ] ;
2018-03-29 17:01:57 -04:00
RemoveObject [ 0 ] = 0xF747 ;
RemoveObject [ 1 ] = pEntity - > GetID ( ) ;
RemoveObject [ 2 ] = pEntity - > _instance_timestamp ;
BroadcastPVS ( pEntity - > GetLandcell ( ) , RemoveObject , sizeof ( RemoveObject ) ) ;
pEntity - > exit_world ( ) ;
pEntity - > leave_world ( ) ;
pEntity - > unset_parent ( ) ;
pEntity - > unparent_children ( ) ;
2019-07-07 20:56:15 +00:00
if ( uint32_t generator_id = pEntity - > InqIIDQuality ( GENERATOR_IID , 0 ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * target = g_pWorld - > FindObject ( generator_id ) ;
2018-03-29 17:01:57 -04:00
if ( target )
target - > NotifyGeneratedDeath ( pEntity ) ;
}
2018-07-12 14:41:21 -07:00
DELETE_ENTITY ( pEntity ) ;
2018-03-29 17:01:57 -04:00
}
}
}
PlayerWeenieMap * CWorld : : GetPlayers ( )
{
return & m_mAllPlayers ;
}
2019-07-07 20:56:15 +00:00
uint32_t CWorld : : GetNumPlayers ( )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
return ( uint32_t ) m_mAllPlayers . size ( ) ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
CWeenieObject * CWorld : : FindObject ( uint32_t object_id , bool allowLandblockActivation , bool lockObject )
2018-03-29 17:01:57 -04:00
{
if ( ! object_id )
return NULL ;
WeenieMap : : iterator result = m_mAllObjects . find ( object_id ) ;
if ( result = = m_mAllObjects . end ( ) & & allowLandblockActivation )
{
if ( ! g_pDBIO - > IsWeenieInDatabase ( object_id ) )
return NULL ; //not in the database either
2018-07-12 14:41:21 -07:00
CWeenieObject * weenie = CWeenieObject : : Load ( object_id ) ;
2018-03-29 17:01:57 -04:00
if ( ! weenie )
return NULL ;
//try getting a valid cellId to search in
Position pos ;
2019-07-07 20:56:15 +00:00
uint32_t cellId = weenie - > m_Position . objcell_id ;
2018-03-29 17:01:57 -04:00
if ( ! cellId & & weenie - > m_Qualities . InqPosition ( LOCATION_POSITION , pos ) )
cellId = pos . objcell_id ;
if ( ! cellId & & weenie - > m_Qualities . InqPosition ( INSTANTIATION_POSITION , pos ) )
cellId = pos . objcell_id ;
if ( cellId )
{
WORD header = ( cellId > > 16 ) ;
CWorldLandBlock * block = GetLandblock ( header , false ) ;
if ( ! block ) //we're not active
{
block = GetLandblock ( header , true ) ;
if ( block ) //now we're active!
{
block - > Think ( ) ; //force a tick so we spawn stuff and hopefully what we are looking for.
result = m_mAllObjects . find ( object_id ) ; //try again now that we loaded the landblock that supposedly contains the weenie.
}
}
}
2018-07-12 14:41:21 -07:00
delete weenie ;
2018-03-29 17:01:57 -04:00
}
if ( result = = m_mAllObjects . end ( ) )
return NULL ;
2018-09-29 11:05:26 -07:00
2018-03-29 17:01:57 -04:00
return result - > second ;
}
2019-07-07 20:56:15 +00:00
bool CWorld : : FindObjectName ( uint32_t object_id , std : : string & name )
2018-03-29 17:01:57 -04:00
{
WeenieMap : : iterator result = m_mAllObjects . find ( object_id ) ;
if ( result = = m_mAllObjects . end ( ) )
return false ;
name = result - > second - > GetName ( ) ;
return true ;
}
//==================================================
//Global, player search by GUID.
//==================================================
2019-07-07 20:56:15 +00:00
CPlayerWeenie * CWorld : : FindPlayer ( uint32_t dwGUID )
2018-03-29 17:01:57 -04:00
{
PlayerWeenieMap : : iterator result = m_mAllPlayers . find ( dwGUID ) ;
if ( result = = m_mAllPlayers . end ( ) )
return NULL ;
return result - > second ;
}
2019-07-07 20:56:15 +00:00
std : : string CWorld : : GetPlayerName ( uint32_t playerId , bool allowOffline )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
CPlayerWeenie * player = FindPlayer ( playerId ) ;
2018-03-29 17:01:57 -04:00
if ( player )
return player - > GetName ( ) ;
if ( allowOffline )
return g_pDBIO - > GetPlayerCharacterName ( playerId ) ;
return " " ;
}
2019-07-07 20:56:15 +00:00
uint32_t CWorld : : GetPlayerId ( const char * name , bool allowOffline )
2018-03-29 17:01:57 -04:00
{
if ( * name = = ' + ' )
name + + ;
2018-07-12 14:41:21 -07:00
CPlayerWeenie * player = FindPlayer ( name ) ;
2018-03-29 17:01:57 -04:00
if ( player )
return player - > GetID ( ) ;
if ( allowOffline )
return g_pDBIO - > GetPlayerCharacterId ( name ) ;
return 0 ;
}
//==================================================
//Global, case insensitive player name search.
//==================================================
2018-07-12 14:41:21 -07:00
CPlayerWeenie * CWorld : : FindPlayer ( const char * target_name )
2018-03-29 17:01:57 -04:00
{
2018-10-31 20:16:03 -05:00
if ( ! target_name )
return NULL ;
2018-03-29 17:01:57 -04:00
if ( * target_name = = ' + ' )
target_name + + ;
for ( auto entry : m_mAllPlayers )
{
2018-07-12 14:41:21 -07:00
CPlayerWeenie * player = entry . second ;
2018-03-29 17:01:57 -04:00
if ( player )
{
std : : string player_name_ = player - > GetName ( ) ;
const char * player_name = player_name_ . c_str ( ) ;
if ( * player_name = = ' + ' )
player_name + + ;
2019-07-07 20:56:15 +00:00
if ( ! stricmp ( target_name , player_name ) )
2018-03-29 17:01:57 -04:00
return player ;
}
}
return NULL ;
}
2019-07-07 20:56:15 +00:00
void CWorld : : SendNetMessage ( CNetDeliveryTargets * target , void * data , uint32_t len , WORD group , uint32_t ignore_ent , BOOL game_event )
2018-03-29 17:01:57 -04:00
{
UNFINISHED ( ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t cell_id : target - > _target_cell_pvs )
2018-03-29 17:01:57 -04:00
{
CWorldLandBlock * landBlock = GetLandblock ( cell_id > > 16 , false ) ;
if ( ! landBlock )
continue ;
CObjCell * cell = landBlock - > GetObjCell ( cell_id & 0xFFFF ) ;
if ( ! cell )
continue ;
// could use stab list, but sometimes messages are sent outside of stab list.. sigh, really need to use some form of voyeur tracking
}
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastPVS ( CPhysicsObj * physobj , void * _data , uint32_t _len , WORD _group , uint32_t ignore_ent , BOOL _game_event , bool ephemeral )
2018-03-29 17:01:57 -04:00
{
if ( ! physobj )
return ;
2018-07-12 14:41:21 -07:00
CPhysicsObj * topLevel = physobj - > parent ? physobj - > parent : physobj ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t cell_id ;
2018-03-29 17:01:57 -04:00
cell_id = topLevel - > m_Position . objcell_id ;
2019-05-12 09:21:34 -07:00
BroadcastPVS ( cell_id , _data , _len , _group , ignore_ent , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t old_cell_id = topLevel - > last_tick_cell_id ;
2018-03-29 17:01:57 -04:00
if ( cell_id ! = old_cell_id & & old_cell_id )
{
2019-05-12 09:21:34 -07:00
BroadcastPVS ( old_cell_id , _data , _len , _group , ignore_ent , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
}
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastPVS ( CWeenieObject * weenie , void * _data , uint32_t _len , WORD _group , uint32_t ignore_ent , BOOL _game_event , bool ephemeral )
2018-03-29 17:01:57 -04:00
{
if ( ! weenie )
return ;
if ( weenie - > IsContained ( ) | |
( weenie - > IsEquipped ( ) & & weenie - > InqIntQuality ( PARENT_LOCATION_INT , 0 ) = = 0 ) ) //we're equipped but we dont have a physical presence in the world, make sure to include us here.
{
2019-07-07 20:56:15 +00:00
uint32_t topLevelID = weenie - > GetTopLevelID ( ) ;
2018-03-29 17:01:57 -04:00
if ( topLevelID ! = weenie - > GetID ( ) & & ignore_ent ! = topLevelID )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * owner = FindObject ( topLevelID ) ;
2018-03-29 17:01:57 -04:00
if ( owner )
{
2019-05-12 09:21:34 -07:00
owner - > SendNetMessage ( _data , _len , _group , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
if ( owner - > AsContainer ( ) ! = NULL & & owner - > AsContainer ( ) - > _openedById ! = 0 )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * openedBy = FindObject ( owner - > AsContainer ( ) - > _openedById ) ;
2018-03-29 17:01:57 -04:00
if ( openedBy )
2019-05-12 09:21:34 -07:00
openedBy - > SendNetMessage ( _data , _len , _group , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
}
}
}
}
else
{
2019-05-12 09:21:34 -07:00
BroadcastPVS ( ( CPhysicsObj * ) weenie , _data , _len , _group , ignore_ent , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
}
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastPVS ( const Position & pos , void * _data , uint32_t _len , WORD _group , uint32_t ignore_ent , BOOL _game_event , bool ephemeral )
2018-03-29 17:01:57 -04:00
{
2019-05-12 09:21:34 -07:00
BroadcastPVS ( pos . objcell_id , _data , _len , _group , ignore_ent , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastPVS ( uint32_t dwCell , void * _data , uint32_t _len , WORD _group , uint32_t ignore_ent , BOOL _game_event , bool ephemeral )
2018-03-29 17:01:57 -04:00
{
if ( ! dwCell )
return ;
// Don't ask.
WORD block = BLOCK_WORD ( dwCell ) ;
WORD cell = CELL_WORD ( dwCell ) ;
2019-07-07 20:56:15 +00:00
uint32_t basex = BASE_OFFSET ( BLOCK_X ( block ) , CELL_X ( cell ) ) ;
uint32_t basey = BASE_OFFSET ( BLOCK_Y ( block ) , CELL_Y ( cell ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t minx = basex ;
uint32_t maxx = basex ;
uint32_t miny = basey ;
uint32_t maxy = basey ;
2018-03-29 17:01:57 -04:00
//if ( cell < 0xFF ) //indoor structure
{
if ( minx > = ( dwMinimumCellX + PVC_RANGE ) ) minx - = PVC_RANGE ; else minx = dwMinimumCellX ;
if ( maxx < = ( dwMaximumCellX - PVC_RANGE ) ) maxx + = PVC_RANGE ; else maxx = dwMaximumCellX ;
if ( miny > = ( dwMinimumCellY + PVC_RANGE ) ) miny - = PVC_RANGE ; else miny = dwMinimumCellY ;
if ( maxy < = ( dwMaximumCellY - PVC_RANGE ) ) maxy + = PVC_RANGE ; else maxy = dwMaximumCellY ;
}
minx = BLOCK_OFFSET ( minx ) < < 8 ;
miny = BLOCK_OFFSET ( miny ) ;
maxx = BLOCK_OFFSET ( maxx ) < < 8 ;
maxy = BLOCK_OFFSET ( maxy ) ;
CWorldLandBlock * pBlock = m_pBlocks [ block ] ;
2018-08-04 18:58:24 -05:00
if ( ( pBlock & & ( dwCell & 0xFFFF ) > 0x100 ) & & ! pBlock - > PossiblyVisibleToOutdoors ( dwCell ) ) //check if inside
2018-03-29 17:01:57 -04:00
{
// dungeons are usually contained in water blocks usually and we will only broadcast to them individually
2019-05-12 09:21:34 -07:00
pBlock - > Broadcast ( _data , _len , _group , ignore_ent , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
}
else
{
2019-07-07 20:56:15 +00:00
for ( uint32_t xit = minx ; xit < = maxx ; xit + = 0x100 ) {
for ( uint32_t yit = miny ; yit < = maxy ; yit + = 1 )
2018-03-29 17:01:57 -04:00
{
CWorldLandBlock * pBlock = m_pBlocks [ xit | yit ] ;
if ( pBlock )
2019-05-12 09:21:34 -07:00
pBlock - > Broadcast ( _data , _len , _group , ignore_ent , _game_event , ephemeral ) ;
2018-03-29 17:01:57 -04:00
}
}
}
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastGlobal ( BinaryWriter * writer , WORD group , uint32_t ignore_ent , BOOL game_event , BOOL should_delete )
2018-03-29 17:01:57 -04:00
{
BroadcastGlobal ( writer - > GetData ( ) , writer - > GetSize ( ) , group , ignore_ent , game_event ) ;
if ( should_delete )
{
delete writer ;
}
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastGlobal ( void * _data , uint32_t _len , WORD _group , uint32_t ignore_ent , BOOL _game_event )
2018-03-29 17:01:57 -04:00
{
for ( auto & playerEntry : m_mAllPlayers )
{
2018-07-12 14:41:21 -07:00
if ( CPlayerWeenie * pPlayer = playerEntry . second )
2018-03-29 17:01:57 -04:00
{
if ( ! ignore_ent | | ( pPlayer - > GetID ( ) ! = ignore_ent ) )
{
pPlayer - > SendNetMessage ( _data , _len , _group , _game_event ) ;
}
}
}
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastLocal ( uint32_t cellid , std : : string text )
2018-04-25 23:07:52 -05:00
{
BinaryWriter * textMsg = ServerText ( text . c_str ( ) , LTT_DEFAULT ) ;
g_pWorld - > BroadcastPVS ( cellid , textMsg - > GetData ( ) , textMsg - > GetSize ( ) , PRIVATE_MSG , 0 , false ) ;
delete textMsg ;
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastLocal ( uint32_t cellid , std : : string text , LogTextType channel )
2018-09-14 18:46:57 -05:00
{
BinaryWriter * textMsg = ServerText ( text . c_str ( ) , channel ) ;
g_pWorld - > BroadcastPVS ( cellid , textMsg - > GetData ( ) , textMsg - > GetSize ( ) , PRIVATE_MSG , 0 , false ) ;
delete textMsg ;
}
2018-03-29 17:01:57 -04:00
void CWorld : : Test ( )
{
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " <CWorld::Test()> \n " ) ;
WINLOG ( Temp , Normal , " Portal: v%lu, %lu files. \n " , g_pPortal - > GetVersion ( ) , g_pPortal - > GetFileCount ( ) ) ;
WINLOG ( Temp , Normal , " Cell: v%lu, %u files. \n " , g_pCell - > GetVersion ( ) , g_pCell - > GetFileCount ( ) ) ;
WINLOG ( Temp , Normal , " %u objects " , m_mAllObjects . size ( ) ) ;
WINLOG ( Temp , Normal , " %u players: \n " , m_mAllPlayers . size ( ) ) ;
2018-03-29 17:01:57 -04:00
for ( PlayerWeenieMap : : iterator pit = m_mAllPlayers . begin ( ) ; pit ! = m_mAllPlayers . end ( ) ; pit + + )
{
2018-07-12 14:41:21 -07:00
CPlayerWeenie * pPlayer = pit - > second ;
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " %08X %s \n " , pPlayer - > GetID ( ) , pPlayer - > GetName ( ) . c_str ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " %u active blocks: \n " , m_vBlocks . size ( ) ) ;
2018-03-29 17:01:57 -04:00
for ( LandblockVector : : iterator it = m_vBlocks . begin ( ) ; it ! = m_vBlocks . end ( ) ; it + + )
{
CWorldLandBlock * pBlock = * it ;
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " %04X %u players %u entities \n " , pBlock - > GetHeader ( ) , pBlock - > PlayerCount ( ) , pBlock - > LiveCount ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " %u dormant blocks: \n " , m_mDormantBlocks . size ( ) ) ;
2018-03-29 17:01:57 -04:00
for ( LandblockMap : : iterator it = m_mDormantBlocks . begin ( ) ; it ! = m_mDormantBlocks . end ( ) ; it + + )
{
CWorldLandBlock * pBlock = it - > second ;
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " %04X %u players %u entities \n " , pBlock - > GetHeader ( ) , pBlock - > PlayerCount ( ) , pBlock - > LiveCount ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " %u unloaded blocks: \n " , m_mUnloadedBlocks . size ( ) ) ;
2018-03-29 17:01:57 -04:00
for ( LandblockMap : : iterator it = m_mUnloadedBlocks . begin ( ) ; it ! = m_mUnloadedBlocks . end ( ) ; it + + )
{
CWorldLandBlock * pBlock = it - > second ;
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " %04X %u players %u entities \n " , pBlock - > GetHeader ( ) , pBlock - > PlayerCount ( ) , pBlock - > LiveCount ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-22 11:05:24 -07:00
WINLOG ( Temp , Normal , " </CWorld::Test()> \n " ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
void CWorld : : RemoveEntity ( CWeenieObject * pEntity )
2018-03-29 17:01:57 -04:00
{
if ( ! pEntity )
return ;
2020-09-13 17:46:03 -07:00
//if (m_pGameMode)
// m_pGameMode->OnRemoveEntity(pEntity);
2018-03-29 17:01:57 -04:00
if ( pEntity - > AsPlayer ( ) & & g_pConfig - > ShowLogins ( ) & & pEntity - > m_Qualities . id = = W_HUMAN_CLASS )
{
BroadcastGlobal ( ServerBroadcast ( " System " , csprintf ( " %s has logged out. " , pEntity - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) , PRIVATE_MSG , pEntity - > GetID ( ) , FALSE , TRUE ) ;
}
CWorldLandBlock * pBlock = pEntity - > GetBlock ( ) ;
if ( ! pBlock )
{
if ( pEntity - > ShouldSave ( ) )
pEntity - > Save ( ) ;
pEntity - > exit_world ( ) ;
pEntity - > leave_world ( ) ;
pEntity - > unset_parent ( ) ;
pEntity - > unparent_children ( ) ;
2018-07-12 14:41:21 -07:00
EnsureRemoved ( pEntity ) ;
2019-07-07 20:56:15 +00:00
if ( uint32_t generator_id = pEntity - > InqIIDQuality ( GENERATOR_IID , 0 ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * target = g_pWorld - > FindObject ( generator_id ) ;
2018-03-29 17:01:57 -04:00
if ( target )
target - > NotifyGeneratedDeath ( pEntity ) ;
}
2018-06-23 23:34:47 +01:00
2018-07-12 14:41:21 -07:00
DELETE_ENTITY ( pEntity ) ;
2018-03-29 17:01:57 -04:00
}
else
{
pBlock - > Destroy ( pEntity ) ;
}
}
2018-07-12 14:41:21 -07:00
void CWorld : : EnsureRemoved ( CWeenieObject * pEntity )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_mAllPlayers . erase ( pEntity - > GetID ( ) ) ;
m_mAllObjects . erase ( pEntity - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
std : : string eventString ;
if ( pEntity - > m_Qualities . InqString ( GENERATOR_EVENT_STRING , eventString ) )
{
auto range_pair = _eventWeenies . equal_range ( eventString ) ;
2018-07-12 14:41:21 -07:00
for ( auto it = range_pair . first ; it ! = range_pair . second ; + + it ) {
if ( it - > second = = pEntity - > GetID ( ) ) {
2018-03-29 17:01:57 -04:00
_eventWeenies . erase ( it ) ;
break ;
}
}
}
}
void CWorld : : CheckDormantLandblocks ( )
{
LandblockMap : : iterator lit = m_mDormantBlocks . begin ( ) ;
LandblockMap : : iterator lend = m_mDormantBlocks . end ( ) ;
unsigned int minNumToCleanup = 0 ;
if ( m_mDormantBlocks . size ( ) > = g_pConfig - > MaxDormantLandblocks ( ) )
2019-07-07 20:56:15 +00:00
minNumToCleanup = ( uint32_t ) ( m_mDormantBlocks . size ( ) - g_pConfig - > MaxDormantLandblocks ( ) ) ;
2018-03-29 17:01:57 -04:00
double dormantCleanupTime = g_pConfig - > DormantLandblockCleanupTime ( ) ;
while ( lit ! = lend )
{
CWorldLandBlock * pBlock = lit - > second ;
if ( ! minNumToCleanup & & ( pBlock - > GetDormancyTime ( ) + dormantCleanupTime ) > = Timer : : cur_time )
{
// theoretically these are sorted with the most recent last
break ;
}
else
{
lit = m_mDormantBlocks . erase ( lit ) ;
lend = m_mDormantBlocks . end ( ) ;
pBlock - > UnloadSpawnsUntilNextTick ( ) ;
m_mUnloadedBlocks [ pBlock - > GetHeader ( ) ] = pBlock ;
minNumToCleanup - - ;
}
}
}
void CWorld : : Think ( )
{
if ( ! m_SendPerformanceInfoToPlayer )
{
LandblockVector : : iterator lit = m_vBlocks . begin ( ) ;
LandblockVector : : iterator lend = m_vBlocks . end ( ) ;
while ( lit ! = lend )
{
CWorldLandBlock * pBlock = * lit ;
if ( pBlock - > Think ( ) | | pBlock - > GetDormancyStatus ( ) ! = LandblockDormancyStatus : : Dormant )
{
lit + + ;
}
else
{
lit = m_vBlocks . erase ( lit ) ;
lend = m_vBlocks . end ( ) ;
m_mDormantBlocks [ pBlock - > GetHeader ( ) ] = pBlock ;
pBlock - > SetIsTickingWithWorld ( false ) ;
}
}
CheckDormantLandblocks ( ) ;
}
else
{
// Debug performance
double fSlowestBlock = - 1.0 ;
CWorldLandBlock * pSlowestBlock = NULL ;
CStopWatch measureBlocks ;
LandblockVector : : iterator lit = m_vBlocks . begin ( ) ;
LandblockVector : : iterator lend = m_vBlocks . end ( ) ;
while ( lit ! = lend )
{
CWorldLandBlock * pBlock = * lit ;
CStopWatch measureBlock ;
if ( pBlock - > Think ( ) )
{
double elapsed = measureBlock . GetElapsed ( ) ;
if ( elapsed > fSlowestBlock )
{
fSlowestBlock = elapsed ;
pSlowestBlock = pBlock ;
}
lit + + ;
}
else
{
lit + + ;
// dead
//lit = m_vBlocks.erase(lit);
//lend = m_vBlocks.end();
//m_pBlocks[pBlock->GetHeader()] = NULL;
//delete pBlock;
}
}
double totalElapsed = measureBlocks . GetElapsed ( ) ;
2018-07-12 14:41:21 -07:00
CPlayerWeenie * player = FindPlayer ( m_SendPerformanceInfoToPlayer ) ;
2018-03-29 17:01:57 -04:00
if ( player )
{
player - > SendText ( csprintf ( " FrameTime: %f " , totalElapsed ) , LTT_DEFAULT ) ;
if ( pSlowestBlock )
{
player - > SendText ( csprintf ( " Slowest block %04X took %f seconds (%u objects, %u players), avg block took. %f seconds " ,
pSlowestBlock - > GetHeader ( ) , fSlowestBlock , pSlowestBlock - > LiveCount ( ) , pSlowestBlock - > PlayerCount ( ) , totalElapsed / ( double ) m_vBlocks . size ( ) ) , LTT_DEFAULT ) ;
}
}
m_SendPerformanceInfoToPlayer = 0 ;
}
if ( ! m_vSpawns . empty ( ) )
{
std : : copy ( m_vSpawns . begin ( ) , m_vSpawns . end ( ) , std : : back_inserter ( m_vBlocks ) ) ;
m_vSpawns . clear ( ) ;
}
if ( ( m_fLastSave + 300.0f ) < = g_pGlobals - > Time ( ) )
{
SaveWorld ( ) ;
m_fLastSave = g_pGlobals - > Time ( ) ;
}
2020-09-13 17:46:03 -07:00
//if (m_pGameMode)
//{
// m_pGameMode->Think();
//}
2018-03-29 17:01:57 -04:00
2019-01-13 10:55:05 -06:00
//#ifdef _DEBUG
// for (auto worldObject : m_mAllObjects)
// {
// if (worldObject.second)
// worldObject.second->DebugValidate();
// }
//#endif
2018-03-29 17:01:57 -04:00
}
CGameMode * CWorld : : GetGameMode ( )
{
return m_pGameMode ;
}
void CWorld : : SetNewGameMode ( CGameMode * pGameMode )
{
2020-09-13 17:46:03 -07:00
return ;
2018-03-29 17:01:57 -04:00
if ( pGameMode )
{
g_pWorld - > BroadcastGlobal ( ServerText ( csprintf ( " Setting game mode to %s " , pGameMode - > GetName ( ) ) ) , PRIVATE_MSG ) ;
}
else
{
if ( ! pGameMode & & m_pGameMode )
{
g_pWorld - > BroadcastGlobal ( ServerText ( csprintf ( " Turning off game mode %s " , m_pGameMode - > GetName ( ) ) ) , PRIVATE_MSG ) ;
}
}
if ( m_pGameMode )
{
delete m_pGameMode ;
}
m_pGameMode = pGameMode ;
}
2018-07-12 14:41:21 -07:00
void CWorld : : EnumNearby ( const Position & position , float fRange , std : : list < CWeenieObject * > * pResults )
2018-03-29 17:01:57 -04:00
{
// Enumerate nearby world objects
2019-07-07 20:56:15 +00:00
uint32_t dwCell = position . objcell_id ;
2018-03-29 17:01:57 -04:00
WORD block = BLOCK_WORD ( dwCell ) ;
WORD cell = CELL_WORD ( dwCell ) ;
CWorldLandBlock * pBlock = m_pBlocks [ block ] ;
2018-08-04 18:58:24 -05:00
if ( ( pBlock & & ( dwCell & 0xFFFF ) > 0x100 ) & & ! pBlock - > PossiblyVisibleToOutdoors ( dwCell ) ) //check if inside
2018-03-29 17:01:57 -04:00
{
pBlock - > EnumNearby ( position , fRange , pResults ) ;
}
else
{
2019-07-07 20:56:15 +00:00
uint32_t basex = BASE_OFFSET ( BLOCK_X ( block ) , CELL_X ( cell ) ) ;
uint32_t basey = BASE_OFFSET ( BLOCK_Y ( block ) , CELL_Y ( cell ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t minx = basex ;
uint32_t maxx = basex ;
uint32_t miny = basey ;
uint32_t maxy = basey ;
2018-03-29 17:01:57 -04:00
//if ( cell < 0xFF ) // indoor structure
{
if ( minx > = ( dwMinimumCellX + PVC_RANGE ) ) minx - = PVC_RANGE ; else minx = dwMinimumCellX ;
if ( maxx < = ( dwMaximumCellX - PVC_RANGE ) ) maxx + = PVC_RANGE ; else maxx = dwMaximumCellX ;
if ( miny > = ( dwMinimumCellY + PVC_RANGE ) ) miny - = PVC_RANGE ; else miny = dwMinimumCellY ;
if ( maxy < = ( dwMaximumCellY - PVC_RANGE ) ) maxy + = PVC_RANGE ; else maxy = dwMaximumCellY ;
}
minx = BLOCK_OFFSET ( minx ) < < 8 ;
miny = BLOCK_OFFSET ( miny ) ;
maxx = BLOCK_OFFSET ( maxx ) < < 8 ;
maxy = BLOCK_OFFSET ( maxy ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t xit = minx ; xit < = maxx ; xit + = 0x100 ) {
for ( uint32_t yit = miny ; yit < = maxy ; yit + = 1 )
2018-03-29 17:01:57 -04:00
{
CWorldLandBlock * pBlock = m_pBlocks [ xit | yit ] ;
if ( pBlock )
{
pBlock - > EnumNearby ( position , fRange , pResults ) ;
}
}
}
}
}
2018-07-12 14:41:21 -07:00
void CWorld : : EnumNearbyPlayers ( const Position & position , float fRange , std : : list < CWeenieObject * > * pResults )
2018-03-29 17:01:57 -04:00
{
// Enumerate nearby world objects
2019-07-07 20:56:15 +00:00
uint32_t dwCell = position . objcell_id ;
2018-03-29 17:01:57 -04:00
WORD block = BLOCK_WORD ( dwCell ) ;
WORD cell = CELL_WORD ( dwCell ) ;
CWorldLandBlock * pBlock = m_pBlocks [ block ] ;
2018-08-04 18:58:24 -05:00
if ( ( pBlock & & ( dwCell & 0xFFFF ) > 0x100 ) & & ! pBlock - > PossiblyVisibleToOutdoors ( dwCell ) ) //check if inside
2018-03-29 17:01:57 -04:00
{
pBlock - > EnumNearbyPlayers ( position , fRange , pResults ) ;
}
else
{
2019-07-07 20:56:15 +00:00
uint32_t basex = BASE_OFFSET ( BLOCK_X ( block ) , CELL_X ( cell ) ) ;
uint32_t basey = BASE_OFFSET ( BLOCK_Y ( block ) , CELL_Y ( cell ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t minx = basex ;
uint32_t maxx = basex ;
uint32_t miny = basey ;
uint32_t maxy = basey ;
2018-03-29 17:01:57 -04:00
//if ( cell < 0xFF ) // indoor structure
{
if ( minx > = ( dwMinimumCellX + PVC_RANGE ) ) minx - = PVC_RANGE ; else minx = dwMinimumCellX ;
if ( maxx < = ( dwMaximumCellX - PVC_RANGE ) ) maxx + = PVC_RANGE ; else maxx = dwMaximumCellX ;
if ( miny > = ( dwMinimumCellY + PVC_RANGE ) ) miny - = PVC_RANGE ; else miny = dwMinimumCellY ;
if ( maxy < = ( dwMaximumCellY - PVC_RANGE ) ) maxy + = PVC_RANGE ; else maxy = dwMaximumCellY ;
}
minx = BLOCK_OFFSET ( minx ) < < 8 ;
miny = BLOCK_OFFSET ( miny ) ;
maxx = BLOCK_OFFSET ( maxx ) < < 8 ;
maxy = BLOCK_OFFSET ( maxy ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t xit = minx ; xit < = maxx ; xit + = 0x100 ) {
for ( uint32_t yit = miny ; yit < = maxy ; yit + = 1 )
2018-03-29 17:01:57 -04:00
{
CWorldLandBlock * pBlock = m_pBlocks [ xit | yit ] ;
if ( pBlock )
{
pBlock - > EnumNearbyPlayers ( position , fRange , pResults ) ;
}
}
}
}
}
void CWorld : : EnsureBlockIsTicking ( CWorldLandBlock * pBlock )
{
if ( ! pBlock - > IsTickingWithWorld ( ) )
{
LandblockMap : : iterator entry ;
entry = m_mDormantBlocks . find ( pBlock - > GetHeader ( ) ) ;
if ( entry ! = m_mDormantBlocks . end ( ) )
{
m_mDormantBlocks . erase ( entry ) ;
m_vSpawns . push_back ( pBlock ) ;
pBlock - > SetIsTickingWithWorld ( true ) ;
return ;
}
entry = m_mUnloadedBlocks . find ( pBlock - > GetHeader ( ) ) ;
if ( entry ! = m_mUnloadedBlocks . end ( ) )
{
m_mUnloadedBlocks . erase ( entry ) ;
m_vSpawns . push_back ( pBlock ) ;
pBlock - > SetIsTickingWithWorld ( true ) ;
return ;
}
}
}
2018-07-12 14:41:21 -07:00
void CWorld : : EnumNearby ( CWeenieObject * pSource , float fRange , std : : list < CWeenieObject * > * pResults )
2018-03-29 17:01:57 -04:00
{
// Enumerate nearby world objects
if ( pSource ! = NULL & & ! pSource - > HasOwner ( ) )
{
2019-07-07 20:56:15 +00:00
uint32_t dwCell = pSource - > GetLandcell ( ) ;
2018-03-29 17:01:57 -04:00
WORD block = BLOCK_WORD ( dwCell ) ;
WORD cell = CELL_WORD ( dwCell ) ;
CWorldLandBlock * pBlock = m_pBlocks [ block ] ;
2018-08-04 18:58:24 -05:00
if ( ( pBlock & & ( dwCell & 0xFFFF ) > 0x100 ) & & ! pBlock - > PossiblyVisibleToOutdoors ( dwCell ) ) //check if inside
2018-03-29 17:01:57 -04:00
{
pBlock - > EnumNearby ( pSource , fRange , pResults ) ;
}
else
{
2019-07-07 20:56:15 +00:00
uint32_t basex = BASE_OFFSET ( BLOCK_X ( block ) , CELL_X ( cell ) ) ;
uint32_t basey = BASE_OFFSET ( BLOCK_Y ( block ) , CELL_Y ( cell ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t minx = basex ;
uint32_t maxx = basex ;
uint32_t miny = basey ;
uint32_t maxy = basey ;
2018-03-29 17:01:57 -04:00
//if ( cell < 0xFF ) // indoor structure
{
if ( minx > = ( dwMinimumCellX + PVC_RANGE ) ) minx - = PVC_RANGE ; else minx = dwMinimumCellX ;
if ( maxx < = ( dwMaximumCellX - PVC_RANGE ) ) maxx + = PVC_RANGE ; else maxx = dwMaximumCellX ;
if ( miny > = ( dwMinimumCellY + PVC_RANGE ) ) miny - = PVC_RANGE ; else miny = dwMinimumCellY ;
if ( maxy < = ( dwMaximumCellY - PVC_RANGE ) ) maxy + = PVC_RANGE ; else maxy = dwMaximumCellY ;
}
minx = BLOCK_OFFSET ( minx ) < < 8 ;
miny = BLOCK_OFFSET ( miny ) ;
maxx = BLOCK_OFFSET ( maxx ) < < 8 ;
maxy = BLOCK_OFFSET ( maxy ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t xit = minx ; xit < = maxx ; xit + = 0x100 ) {
for ( uint32_t yit = miny ; yit < = maxy ; yit + = 1 )
2018-03-29 17:01:57 -04:00
{
CWorldLandBlock * pBlock = m_pBlocks [ xit | yit ] ;
if ( pBlock )
{
pBlock - > EnumNearby ( pSource , fRange , pResults ) ;
}
}
}
}
}
}
2018-07-11 04:53:32 +00:00
void CWorld : : EnumNearbyPlayers ( CWeenieObject * pSource , float fRange , std : : list < CWeenieObject * > * pResults )
2018-03-29 17:01:57 -04:00
{
// Enumerate nearby world objects
if ( pSource ! = NULL & & ! pSource - > HasOwner ( ) )
{
2019-07-07 20:56:15 +00:00
uint32_t dwCell = pSource - > GetLandcell ( ) ;
2018-03-29 17:01:57 -04:00
WORD block = BLOCK_WORD ( dwCell ) ;
WORD cell = CELL_WORD ( dwCell ) ;
CWorldLandBlock * pBlock = m_pBlocks [ block ] ;
2018-08-04 18:58:24 -05:00
if ( ( pBlock & & ( dwCell & 0xFFFF ) > 0x100 ) & & ! pBlock - > PossiblyVisibleToOutdoors ( dwCell ) ) //check if inside
2018-03-29 17:01:57 -04:00
{
pBlock - > EnumNearbyPlayers ( pSource , fRange , pResults ) ;
}
else
{
2019-07-07 20:56:15 +00:00
uint32_t basex = BASE_OFFSET ( BLOCK_X ( block ) , CELL_X ( cell ) ) ;
uint32_t basey = BASE_OFFSET ( BLOCK_Y ( block ) , CELL_Y ( cell ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t minx = basex ;
uint32_t maxx = basex ;
uint32_t miny = basey ;
uint32_t maxy = basey ;
2018-03-29 17:01:57 -04:00
//if ( cell < 0xFF ) // indoor structure
{
if ( minx > = ( dwMinimumCellX + PVC_RANGE ) ) minx - = PVC_RANGE ; else minx = dwMinimumCellX ;
if ( maxx < = ( dwMaximumCellX - PVC_RANGE ) ) maxx + = PVC_RANGE ; else maxx = dwMaximumCellX ;
if ( miny > = ( dwMinimumCellY + PVC_RANGE ) ) miny - = PVC_RANGE ; else miny = dwMinimumCellY ;
if ( maxy < = ( dwMaximumCellY - PVC_RANGE ) ) maxy + = PVC_RANGE ; else maxy = dwMaximumCellY ;
}
minx = BLOCK_OFFSET ( minx ) < < 8 ;
miny = BLOCK_OFFSET ( miny ) ;
maxx = BLOCK_OFFSET ( maxx ) < < 8 ;
maxy = BLOCK_OFFSET ( maxy ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t xit = minx ; xit < = maxx ; xit + = 0x100 ) {
for ( uint32_t yit = miny ; yit < = maxy ; yit + = 1 )
2018-03-29 17:01:57 -04:00
{
CWorldLandBlock * pBlock = m_pBlocks [ xit | yit ] ;
if ( pBlock )
{
pBlock - > EnumNearbyPlayers ( pSource , fRange , pResults ) ;
}
}
}
}
}
}
2019-07-07 20:56:15 +00:00
CWeenieObject * CWorld : : FindWithinPVS ( CWeenieObject * source , uint32_t object_id )
2018-03-29 17:01:57 -04:00
{
if ( ! source | | ! object_id )
return NULL ;
if ( source - > GetID ( ) = = object_id )
return source ;
//Find nearby world objects.
if ( ! source - > HasOwner ( ) )
{
2019-07-07 20:56:15 +00:00
uint32_t dwCell = source - > GetLandcell ( ) ;
2018-03-29 17:01:57 -04:00
WORD block = BLOCK_WORD ( dwCell ) ;
WORD cell = CELL_WORD ( dwCell ) ;
2019-07-07 20:56:15 +00:00
uint32_t basex = BASE_OFFSET ( BLOCK_X ( block ) , CELL_X ( cell ) ) ;
uint32_t basey = BASE_OFFSET ( BLOCK_Y ( block ) , CELL_Y ( cell ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t minx = basex ;
uint32_t maxx = basex ;
uint32_t miny = basey ;
uint32_t maxy = basey ;
2018-03-29 17:01:57 -04:00
//if ( cell < 0xFF ) //indoor structure
{
if ( minx > = ( dwMinimumCellX + PVC_RANGE ) ) minx - = PVC_RANGE ; else minx = dwMinimumCellX ;
if ( maxx < = ( dwMaximumCellX - PVC_RANGE ) ) maxx + = PVC_RANGE ; else maxx = dwMaximumCellX ;
if ( miny > = ( dwMinimumCellY + PVC_RANGE ) ) miny - = PVC_RANGE ; else miny = dwMinimumCellY ;
if ( maxy < = ( dwMaximumCellY - PVC_RANGE ) ) maxy + = PVC_RANGE ; else maxy = dwMaximumCellY ;
}
minx = BLOCK_OFFSET ( minx ) < < 8 ;
miny = BLOCK_OFFSET ( miny ) ;
maxx = BLOCK_OFFSET ( maxx ) < < 8 ;
maxy = BLOCK_OFFSET ( maxy ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t xit = minx ; xit < = maxx ; xit + = 0x100 ) {
for ( uint32_t yit = miny ; yit < = maxy ; yit + = 1 )
2018-03-29 17:01:57 -04:00
{
CWorldLandBlock * pBlock = m_pBlocks [ xit | yit ] ;
if ( pBlock )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * pEntity = pBlock - > FindEntity ( object_id ) ;
2018-03-29 17:01:57 -04:00
if ( pEntity )
return pEntity ;
}
}
}
}
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * externalObject = g_pWorld - > FindObject ( object_id ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( CContainerWeenie * externalContainer = externalObject - > GetWorldTopLevelContainer ( ) )
2018-03-29 17:01:57 -04:00
{
if ( externalContainer - > _openedById = = source - > GetID ( ) )
{
return externalObject ;
}
}
}
return source - > FindContained ( object_id ) ;
}
void CWorld : : EnumerateDungeonsFromCellData ( )
{
# ifndef QUICKSTART
// FILE *dropsFile = fopen("d:\\temp\\dungeonDrops.txt", "wt");
// This creates a list of dungeons
FILEMAP * pFiles = g_pCell - > GetFiles ( ) ;
FILEMAP : : iterator i = pFiles - > begin ( ) ;
FILEMAP : : iterator iend = pFiles - > end ( ) ;
while ( i ! = iend )
{
2019-07-07 20:56:15 +00:00
uint32_t dwID = i - > first ;
2018-03-29 17:01:57 -04:00
if ( ( ( dwID & 0xFFFF ) > = 0xFFFE ) | | ( ( dwID & 0xFFFF ) < 0x100 ) )
{
i + + ;
continue ;
}
CEnvCell * pEnvCell = CEnvCell : : Get ( dwID ) ;
if ( ! pEnvCell )
{
i + + ;
continue ;
}
Frame drop ;
bool bFoundDrop = false ;
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < pEnvCell - > num_static_objects ; i + + )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
uint32_t setupID = pEnvCell - > static_object_ids [ i ] ;
2018-03-29 17:01:57 -04:00
if ( ( setupID > = 0x02000C39 & & setupID < = 0x02000C48 ) | | ( setupID = = 0x02000F4A ) )
{
drop = pEnvCell - > static_object_frames [ i ] ;
bFoundDrop = true ;
break ;
}
}
/*
if ( dropsFile )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < pEnvCell - > num_static_objects ; i + + )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
uint32_t setupID = pEnvCell - > static_object_ids [ i ] ;
2018-03-29 17:01:57 -04:00
if ( ( setupID > = 0x02000C39 & & setupID < = 0x02000C48 ) | | ( setupID = = 0x02000F4A ) )
{
fprintf ( dropsFile , " %08X %f %f %f %f %f %f %f \n " ,
dwID ,
pEnvCell - > static_object_frames [ i ] . m_origin . x ,
pEnvCell - > static_object_frames [ i ] . m_origin . y ,
pEnvCell - > static_object_frames [ i ] . m_origin . z ,
pEnvCell - > static_object_frames [ i ] . m_angles . w ,
pEnvCell - > static_object_frames [ i ] . m_angles . x ,
pEnvCell - > static_object_frames [ i ] . m_angles . y ,
pEnvCell - > static_object_frames [ i ] . m_angles . z ) ;
break ;
}
}
}
*/
CEnvCell : : Release ( pEnvCell ) ;
if ( bFoundDrop )
{
Position dropPos ;
dropPos . objcell_id = dwID ;
dropPos . frame = drop ;
m_mDungeons [ dwID ] = dropPos ;
2019-07-07 20:56:15 +00:00
if ( dwID < ( uint32_t ) ( 0 - 0x10100 ) )
2018-03-29 17:01:57 -04:00
i = pFiles - > upper_bound ( ( ( dwID & 0xFFFF0000 ) + 0x10100 ) - 1 ) ;
else
break ;
}
else
{
i + + ;
}
}
# endif
}
2019-07-07 20:56:15 +00:00
void CWorld : : BroadcastChatChannel ( uint32_t channel_id , CPlayerWeenie * sender , const std : : u16string & message )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
uint32_t sender_monarch_id = 0 ;
2018-03-29 17:01:57 -04:00
if ( channel_id = = Allegiance_ChatChannel )
{
sender_monarch_id = sender - > InqIIDQuality ( MONARCH_IID , 0 ) ;
if ( ! sender_monarch_id )
{
return ;
}
}
BinaryWriter chatPayload ;
2019-07-07 20:56:15 +00:00
chatPayload . Write < uint32_t > ( channel_id ) ;
2018-03-29 17:01:57 -04:00
chatPayload . AppendWStringFromString ( sender - > GetName ( ) ) ;
2019-07-07 20:56:15 +00:00
//chatPayload.AppendWStringFromString(message);
chatPayload . Write < std : : u16string > ( message ) ;
chatPayload . Write < uint32_t > ( 12 ) ; // size of next data
chatPayload . Write < uint32_t > ( sender - > GetID ( ) ) ;
chatPayload . Write < uint32_t > ( 0 ) ;
chatPayload . Write < uint32_t > ( 2 ) ;
2018-03-29 17:01:57 -04:00
BinaryWriter chatPackage ;
2019-07-07 20:56:15 +00:00
chatPackage . Write < uint32_t > ( 0xF7DE ) ;
chatPackage . Write < uint32_t > ( chatPayload . GetSize ( ) + 32 ) ;
chatPackage . Write < uint32_t > ( 1 ) ; // type
chatPackage . Write < uint32_t > ( 1 ) ;
chatPackage . Write < uint32_t > ( 1 ) ;
chatPackage . Write < uint32_t > ( 0xB0045 ) ;
chatPackage . Write < uint32_t > ( 1 ) ;
chatPackage . Write < uint32_t > ( 0xB0045 ) ;
chatPackage . Write < uint32_t > ( 0 ) ;
chatPackage . Write < uint32_t > ( chatPayload . GetSize ( ) ) ;
2018-03-29 17:01:57 -04:00
chatPackage . Write ( & chatPayload ) ;
for ( auto & entry : m_mAllPlayers )
{
2018-07-12 14:41:21 -07:00
CPlayerWeenie * player = entry . second ;
2018-03-29 17:01:57 -04:00
2018-09-21 06:16:42 -07:00
if ( player & & ! player - > IsPlayerSquelched ( sender - > GetID ( ) , true ) )
2018-03-29 17:01:57 -04:00
{
2018-09-21 06:16:42 -07:00
BOOL bShouldHear = FALSE ;
switch ( channel_id )
2018-03-29 17:01:57 -04:00
{
2018-09-21 06:16:42 -07:00
case General_ChatChannel :
bShouldHear = ( player - > GetCharacterOptions2 ( ) & HearGeneralChat_CharacterOptions2 ) ;
break ;
case Trade_ChatChannel :
bShouldHear = ( player - > GetCharacterOptions2 ( ) & HearTradeChat_CharacterOptions2 ) ;
break ;
case LFG_ChatChannel :
bShouldHear = ( player - > GetCharacterOptions2 ( ) & HearLFGChat_CharacterOptions2 ) ;
break ;
case Roleplay_ChatChannel :
bShouldHear = ( player - > GetCharacterOptions2 ( ) & HearRoleplayChat_CharacterOptions2 ) ;
break ;
case Allegiance_ChatChannel :
if ( player - > GetCharacterOptions ( ) & HearAllegianceChat_CharacterOption )
{
if ( sender_monarch_id & & sender_monarch_id = = player - > InqIIDQuality ( MONARCH_IID , 0 ) )
bShouldHear = TRUE ;
2020-08-07 10:58:05 -07:00
if ( player - > IsAllegGagged ( ) )
bShouldHear = FALSE ;
2018-09-21 06:16:42 -07:00
}
break ;
2018-03-29 17:01:57 -04:00
}
2018-09-21 06:16:42 -07:00
if ( bShouldHear )
{
player - > SendNetMessage ( & chatPackage , 4 , FALSE , FALSE ) ;
}
2018-03-29 17:01:57 -04:00
}
}
}
std : : string CWorld : : GetServerStatus ( )
{
std : : string status ;
extern CPhatServer * g_pPhatServer ;
2019-07-07 20:56:15 +00:00
uint32_t runTime = ( uint32_t ) ( g_pGlobals - > Time ( ) - g_pPhatServer - > GetStartupTime ( ) ) ;
uint32_t runSeconds = runTime % 60 ;
2018-03-29 17:01:57 -04:00
runTime / = 60 ;
2019-07-07 20:56:15 +00:00
uint32_t runMinutes = runTime % 60 ;
2018-03-29 17:01:57 -04:00
runTime / = 60 ;
2019-07-07 20:56:15 +00:00
uint32_t runHours = runTime ;
2018-03-29 17:01:57 -04:00
status + = csprintf ( " Server runtime: %uh %um %us \n " , runHours , runMinutes , runSeconds ) ;
2019-07-07 20:56:15 +00:00
status + = csprintf ( " %u MB used, %u / %u MB physical mem free. \n " , ( uint32_t ) ( GetProcessMemoryUsage ( ) > > 20 ) , ( uint32_t ) ( GetFreeMemory ( ) > > 20 ) , ( uint32_t ) ( GetTotalMemory ( ) > > 20 ) ) ;
2018-03-29 17:01:57 -04:00
{
// check bucket health
2019-07-07 20:56:15 +00:00
uint32_t biggestBucket = 0 ;
for ( uint32_t i = 0 ; i < m_mAllPlayers . bucket_count ( ) ; i + + )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
uint32_t bucketSize = ( uint32_t ) m_mAllPlayers . bucket_size ( i ) ;
2018-03-29 17:01:57 -04:00
if ( bucketSize > = biggestBucket )
biggestBucket = bucketSize ;
}
status + = csprintf ( " %u players (%u buckets [%u in biggest].) \n " , m_mAllPlayers . size ( ) , m_mAllPlayers . bucket_count ( ) , biggestBucket ) ;
}
{
2019-07-07 20:56:15 +00:00
std : : map < uint64_t , CWorldLandBlock * > sortedBlocks ;
2018-03-29 17:01:57 -04:00
unsigned int activeBlocks = 0 ;
unsigned int dormantPendingBlocks = 0 ;
unsigned int dormantBlocks = 0 ;
2019-07-07 20:56:15 +00:00
uint32_t totalActiveObjects = 0 ;
2018-03-29 17:01:57 -04:00
// find the top 5 most active blocks
for ( auto block : m_vBlocks )
{
if ( ! block )
continue ;
2019-07-07 20:56:15 +00:00
uint32_t liveCount = block - > LiveCount ( ) ;
2018-03-29 17:01:57 -04:00
switch ( block - > GetDormancyStatus ( ) )
{
case LandblockDormancyStatus : : DoNotGoDormant :
activeBlocks + + ;
totalActiveObjects + = liveCount ;
break ;
case LandblockDormancyStatus : : WaitToGoDormant :
dormantPendingBlocks + + ;
totalActiveObjects + = liveCount ;
break ;
case LandblockDormancyStatus : : Dormant :
dormantBlocks + + ;
break ;
}
liveCount = ( liveCount < < 16 ) | block - > PlayerCount ( ) ;
2019-07-07 20:56:15 +00:00
sortedBlocks [ ( ( 0xFFFFFFFF - ( ( uint64_t ) liveCount ) ) < < 32 ) | ( uint64_t ) block - > GetHeader ( ) ] = block ;
2018-03-29 17:01:57 -04:00
}
{
// check bucket health
/*
2019-07-07 20:56:15 +00:00
uint32_t biggestBucket = 0 ;
for ( uint32_t i = 0 ; i < m_mAllObjects . bucket_count ( ) ; i + + )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
uint32_t bucketSize = ( uint32_t ) m_mAllObjects . bucket_size ( i ) ;
2018-03-29 17:01:57 -04:00
if ( bucketSize > = biggestBucket )
biggestBucket = bucketSize ;
}
status + = csprintf ( " %u objects (%u buckets [%u in biggest].) \n " , m_mAllObjects . size ( ) , m_mAllObjects . bucket_count ( ) , biggestBucket ) ;
*/
status + = csprintf ( " %u active objects, %u total objects (%u buckets.) \n " , totalActiveObjects , m_mAllObjects . size ( ) , m_mAllObjects . bucket_count ( ) ) ;
}
status + = csprintf ( " %u total blocks loaded. %u active. %u pending dormancy. %u dormant. %u unloaded. \n " ,
2019-07-07 20:56:15 +00:00
m_vBlocks . size ( ) + m_vSpawns . size ( ) , activeBlocks , dormantPendingBlocks , ( uint32_t ) m_mDormantBlocks . size ( ) , ( uint32_t ) m_mUnloadedBlocks . size ( ) ) ;
2018-03-29 17:01:57 -04:00
unsigned int numBlocksToShow = 5 ;
status + = csprintf ( " Top %u most active blocks \n " , numBlocksToShow ) ;
for ( auto block : sortedBlocks )
{
2019-07-07 20:56:15 +00:00
uint32_t numObjects = ( 0xFFFFFFFF - ( uint32_t ) ( block . first > > 32 ) ) ;
uint32_t blockID = ( block . first & 0xFFFFFFFF ) ;
2018-03-29 17:01:57 -04:00
status + = csprintf ( " %04X - %u objects %u players \n " , blockID , HIWORD ( numObjects ) , LOWORD ( numObjects ) ) ;
numBlocksToShow - - ;
if ( ! numBlocksToShow )
break ;
}
}
return status ;
}
2019-07-07 20:56:15 +00:00
uint32_t CWorld : : GenerateGUID ( eGUIDClass type )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
uint32_t new_iid = g_pObjectIDGen - > GenerateGUID ( type ) ;
2018-03-29 17:01:57 -04:00
2019-11-13 20:57:17 +00:00
//while (FindObject(new_iid))
//{
// new_iid = g_pObjectIDGen->GenerateGUID(type);
//}
2018-03-29 17:01:57 -04:00
return new_iid ;
}
2020-04-20 23:56:09 -07:00
void CWorld : : NotifyEventStarted ( std : : string eventName , GameEventDef * event )
2018-03-29 17:01:57 -04:00
{
auto result = _eventWeenies . equal_range ( eventName ) ;
for ( auto it = result . first ; it ! = result . second ; it + + )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * weenie = FindObject ( it - > second ) )
2018-03-29 17:01:57 -04:00
{
2020-04-20 23:56:09 -07:00
weenie - > CheckEventState ( eventName , event ) ;
2018-03-29 17:01:57 -04:00
}
}
}
2020-04-20 23:56:09 -07:00
void CWorld : : NotifyEventStopped ( std : : string eventName , GameEventDef * event )
2018-03-29 17:01:57 -04:00
{
auto result = _eventWeenies . equal_range ( eventName ) ;
for ( auto it = result . first ; it ! = result . second ; it + + )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * weenie = FindObject ( it - > second ) )
2018-03-29 17:01:57 -04:00
{
2020-04-20 23:56:09 -07:00
weenie - > CheckEventState ( eventName , event ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-09-25 18:39:40 -07:00
}
2019-07-07 20:56:15 +00:00
void CWorld : : AddToUsedMergedItems ( uint32_t item )
2018-09-25 18:39:40 -07:00
{
2019-07-07 20:56:15 +00:00
_stackableOnGround . try_emplace ( item , false ) ;
2018-09-25 18:39:40 -07:00
}
2019-07-07 20:56:15 +00:00
bool CWorld : : IsItemInUse ( uint32_t item )
2018-09-25 18:39:40 -07:00
{
2019-07-07 20:56:15 +00:00
std : : map < uint32_t , bool > : : const_iterator it = _stackableOnGround . find ( item ) ;
2018-09-25 18:39:40 -07:00
if ( it = = _stackableOnGround . end ( ) )
return false ;
if ( it - > second = = true )
return true ;
_stackableOnGround [ item ] = true ;
return false ;
}
2019-07-07 20:56:15 +00:00
void CWorld : : RemoveMergedItem ( uint32_t item )
2018-09-25 18:39:40 -07:00
{
_stackableOnGround . erase ( item ) ;
}