Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2586 lines
66 KiB
C++
2586 lines
66 KiB
C++
//===========================================================================//
|
|
// File: Entity.cpp //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 11/29/94 JMA Initial coding. //
|
|
// 08/25/97 JMA Infrastructure changes //
|
|
// 08/25/97 ECH Infrastructure changes //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994-97, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "AdeptHeaders.hpp"
|
|
|
|
#include "EntityManager.hpp"
|
|
#include "EntityAttribute.hpp"
|
|
#include "RendererManager.hpp"
|
|
#include "VideoComponentWeb.hpp"
|
|
#include "EntityClassData.hpp"
|
|
#include "Map.hpp"
|
|
#include "Application.hpp"
|
|
#include <ElementRenderer\GroupElement.hpp>
|
|
#include <ElementRenderer\StateChange.hpp>
|
|
#include "DamageObject.hpp"
|
|
#include "GameModelAttribute.hpp"
|
|
#include "NameTable.hpp"
|
|
#include "CollisionVolume.hpp"
|
|
#include "CollisionGrid.hpp"
|
|
#include "Zone.hpp"
|
|
#include "Tile.hpp"
|
|
|
|
#include <MLR\MLRTexturePool.hpp>
|
|
#include <MLR\MLRTexture.hpp>
|
|
|
|
//#define HUNT_BUG "jmalbert"
|
|
//#define TIME_BUG "your_loginname_here"
|
|
extern int g_nMR;
|
|
|
|
char g_LastEntity[255] = "";
|
|
|
|
//#############################################################################
|
|
//############################# Entity ##################################
|
|
//#############################################################################
|
|
|
|
HGOSHEAP
|
|
Entity::s_Heap = NULL,
|
|
Entity::s_CollisionHeap = NULL;
|
|
|
|
Entity::ClassData*
|
|
Entity::DefaultData = NULL;
|
|
|
|
const Receiver::MessageEntry
|
|
Entity::MessageEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(Entity, Destroy),
|
|
MESSAGE_ENTRY(Entity, Update),
|
|
MESSAGE_ENTRY(Entity, TakeDamage),
|
|
MESSAGE_ENTRY(Entity, BecomeInteresting)
|
|
};
|
|
|
|
int Entity::s_EntitiesSynced;
|
|
DWORD Entity_Count;
|
|
DECLARE_TIMER(static, Renderer_Loading);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::InitializeClass()
|
|
{
|
|
Verify(!s_Heap);
|
|
s_Heap = gos_CreateMemoryHeap("Entities", 0, g_LibraryHeap);
|
|
Check_Pointer(s_Heap);
|
|
|
|
Verify(!s_CollisionHeap);
|
|
s_CollisionHeap = gos_CreateMemoryHeap("Collision", 0, g_LibraryHeap);
|
|
Check_Pointer(s_CollisionHeap);
|
|
|
|
Check_Object(ExecutionStateEngine::DefaultData);
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
EntityClassID,
|
|
"Adept::Entity",
|
|
BaseClass::DefaultData,
|
|
ELEMENTS(MessageEntries), MessageEntries,
|
|
Entity::Make,
|
|
Entity::CreateMessage::ConstructCreateMessage,
|
|
ExecutionStateEngine::DefaultData,
|
|
Entity::GameModel::ConstructGameModel,
|
|
(Entity::GameModel::Factory)GameModel::ConstructOBBStream,
|
|
Entity::GameModel::ReadAndVerify,
|
|
Entity::GameModel::WriteToText,
|
|
Entity::GameModel::SaveGameModel
|
|
);
|
|
Check_Object(DefaultData);
|
|
|
|
INDIRECT_STATE_ATTRIBUTE(
|
|
Entity,
|
|
ExecutionState,
|
|
executionState,
|
|
Entity__ExecutionStateEngine
|
|
);
|
|
|
|
CUSTOM_DIRECT_ATTRIBUTE(
|
|
Entity,
|
|
IsDestroyed,
|
|
isDestroyed,
|
|
int,
|
|
IntClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_ATTRIBUTE(
|
|
Entity,
|
|
VisualRepresentation,
|
|
visualRepresentation,
|
|
int,
|
|
IntClassID
|
|
);
|
|
|
|
DIRECT_ATTRIBUTE(
|
|
Entity,
|
|
LightIntensity,
|
|
lightIntensity,
|
|
Scalar
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Entity__GameModel,
|
|
Collider,
|
|
collider,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Entity__GameModel,
|
|
CanBeWalkedOn,
|
|
canBeWalkedOn,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Entity__GameModel,
|
|
CanBeShot,
|
|
canBeShot,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Entity__GameModel,
|
|
WaterSurface,
|
|
waterSurface,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Entity__GameModel,
|
|
OBBCollides,
|
|
OBBCollides,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
{
|
|
AttributeEntry *attribute_entry =
|
|
new LocalToWorldAttributeEntry(
|
|
LocalToWorldAttributeID,
|
|
"LocalToWorld"
|
|
);
|
|
Check_Object(attribute_entry);
|
|
Check_Object(DefaultData);
|
|
DefaultData->attributeTable.AddAttributeEntry(attribute_entry);
|
|
}
|
|
|
|
#if !defined(NO_STATS)
|
|
AddStatistic("Entities", "entities", gos_DWORD, &Entity_Count, 0);
|
|
AddStatistic("Entities Sync'd", "entities", gos_DWORD, &s_EntitiesSynced, Stat_AutoReset);
|
|
#endif
|
|
|
|
Initialize_Timer(Renderer_Loading, "Renderer Loading");
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::TerminateClass()
|
|
{
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
|
|
Check_Pointer(s_CollisionHeap);
|
|
gos_DestroyMemoryHeap(s_CollisionHeap);
|
|
s_CollisionHeap = NULL;
|
|
|
|
Check_Pointer(s_Heap);
|
|
gos_DestroyMemoryHeap(s_Heap);
|
|
s_Heap = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity::ClassData*
|
|
Entity::GetClassData()
|
|
{
|
|
return Cast_Pointer(ClassData*, classData);
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity*
|
|
Entity::Make(
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
gos_PushCurrentHeap(s_Heap);
|
|
Entity *new_entity = new Entity(DefaultData, message, base_id, NULL);
|
|
Check_Object(new_entity);
|
|
gos_PopCurrentHeap();
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Replicator::CreateMessage*
|
|
Entity::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
|
|
//
|
|
//-----------------------------------
|
|
// Make sure that the stuff is synced
|
|
//-----------------------------------
|
|
//
|
|
#if 0
|
|
SyncMatrices(true);
|
|
#endif
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Make sure there is enough room for the factory request on the stream
|
|
//---------------------------------------------------------------------
|
|
//
|
|
stream->AllocateBytes(sizeof(CreateMessage));
|
|
BaseClass::SaveMakeMessage(stream, res_file);
|
|
CreateMessage *message =
|
|
Cast_Pointer(CreateMessage*, stream->GetPointer());
|
|
message->messageLength = sizeof(*message);
|
|
|
|
//
|
|
//----------------------
|
|
// Save the data list ID
|
|
//----------------------
|
|
//
|
|
Verify(dataListResource.DoesResourceExist());
|
|
message->dataListID = dataListResource.GetResourceID();
|
|
|
|
//
|
|
//-------------------------------------
|
|
// Save the initial state of the entity
|
|
//-------------------------------------
|
|
//
|
|
message->localToParent = initialLocalToParent;
|
|
message->initialAge =
|
|
static_cast<Scalar>(lastExecuted - lastParameterization);
|
|
Check_Object(executionState);
|
|
executionState->Save(&message->executionState);
|
|
|
|
//
|
|
//--------------------------------
|
|
// Save the Save the instance Name
|
|
//--------------------------------
|
|
//
|
|
if(NameTable::GetInstance())
|
|
{
|
|
Check_Object(NameTable::GetInstance());
|
|
message->nameID = NameTable::GetInstance()->FindID(instanceName);
|
|
}
|
|
else
|
|
{
|
|
message->nameID = NameTable::NullObjectID;
|
|
}
|
|
|
|
//
|
|
//----------------------
|
|
//Save out the Alignment
|
|
//----------------------
|
|
//
|
|
message->alignment = alignment;
|
|
|
|
return message;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::Reuse(
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Verify that an entity can be created now
|
|
//-----------------------------------------
|
|
//
|
|
BaseClass::Reuse(message, base_id);
|
|
|
|
#ifdef _ARMOR
|
|
Application *app = Application::GetInstance();
|
|
Check_Object(app);
|
|
Verify(!app->InPreCollisionPhase());
|
|
#endif
|
|
|
|
#if defined(HUNT_BUG)
|
|
SPEW((HUNT_BUG, "Reusing %s(+", GetClassString()));
|
|
Spew(HUNT_BUG, GetReplicatorID());
|
|
if (owningConnection==Connection::Local)
|
|
SPEW((HUNT_BUG, "*+"));
|
|
switch (GetReplicatorMode())
|
|
{
|
|
case MasterMode:
|
|
SPEW((HUNT_BUG, ") as master"));
|
|
break;
|
|
case IndependentMode:
|
|
SPEW((HUNT_BUG, ") as independent"));
|
|
break;
|
|
case HermitMode:
|
|
SPEW((HUNT_BUG, ") as hermit"));
|
|
break;
|
|
case ReplicantMode:
|
|
SPEW((HUNT_BUG, ") as replicant"));
|
|
break;
|
|
case ClientMasterMode:
|
|
SPEW((HUNT_BUG, ") as ClientMasterMode"));
|
|
break;
|
|
case ServerMasterMode:
|
|
SPEW((HUNT_BUG, ") as ServerMasterMode"));
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//----------------------
|
|
// Set up the data list and
|
|
//----------------------
|
|
//
|
|
lastExecuted = gos_GetElapsedTime();
|
|
lastParameterization = lastExecuted - message->initialAge;
|
|
SetInterestMask(DormantInterestLevel);
|
|
updateFlags = 0;
|
|
#if defined(TIME_BUG)
|
|
SPEW((TIME_BUG, "Reusing %s(+", GetClassString()));
|
|
Spew(TIME_BUG, GetReplicatorID());
|
|
SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds()));
|
|
#endif
|
|
|
|
lightIntensity = 0.0f;
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Set up the game model and set the flags that come from the game model
|
|
//----------------------------------------------------------------------
|
|
//
|
|
Verify(dataListResource.DoesResourceExist());
|
|
Verify(gameModelResource.DoesResourceExist());
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
replicatorFlags &= ~GameModelMask;
|
|
replicatorFlags |= model->defaultFlags;
|
|
if (IsACollider() && IsTileBound())
|
|
replicatorFlags &= ~ColliderFlag;
|
|
|
|
//
|
|
//--------------------------
|
|
// Create the locator object
|
|
//--------------------------
|
|
//
|
|
Check_Object(VideoRenderer::Instance);
|
|
Resource element_stream(model->elementResourceID);
|
|
Verify(element_stream.DoesResourceExist());
|
|
|
|
//
|
|
//-------------------------
|
|
// Read in the entity state
|
|
//-------------------------
|
|
//
|
|
gos_PushCurrentHeap(ElementRenderer::g_Heap);
|
|
Check_Object(entityElement);
|
|
#ifdef _DEBUG
|
|
{static void* s_p = (void*)0x08f40500;
|
|
if (s_p == (void*)this) {
|
|
int n = 0;
|
|
n++;
|
|
n--;
|
|
}}
|
|
#endif // _DEBUG
|
|
entityElement->SetClientData(this);
|
|
unsigned state;
|
|
element_stream >> state;
|
|
entityElement->SetElementState(state);
|
|
element_stream >> entityElement->m_localOBB;
|
|
Verify(!solidVolume);
|
|
Verify(!hierarchicalVolume);
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Read a state change from stream, but if it has no changes, kill it
|
|
//-------------------------------------------------------------------
|
|
//
|
|
ElementRenderer::StateChange *states =
|
|
new ElementRenderer::StateChange(
|
|
&element_stream,
|
|
ElementRenderer::CurrentERFVersion
|
|
);
|
|
Check_Object(states);
|
|
if (states->IsRealStateChange())
|
|
entityElement->AdoptStateChange(states);
|
|
else
|
|
{
|
|
Check_Object(states);
|
|
delete states;
|
|
}
|
|
gos_PopCurrentHeap();
|
|
|
|
//
|
|
//-------------------------------
|
|
// Set the position of the entity
|
|
//-------------------------------
|
|
//
|
|
initialLocalToParent = message->localToParent;
|
|
entityElement->SetLocalToParent(message->localToParent);
|
|
NeedMatrixSync();
|
|
|
|
//
|
|
//------------------------------
|
|
// Load up the execution engines
|
|
//------------------------------
|
|
//
|
|
Check_Object(executionState);
|
|
executionState->Reuse(&message->executionState);
|
|
|
|
//
|
|
//------------------------------------------------
|
|
//Load the instance Name if it exists in the Table
|
|
//------------------------------------------------
|
|
//
|
|
objectID = message->nameID;
|
|
dontHit = NULL;
|
|
if (oldCollisions)
|
|
{
|
|
delete oldCollisions;
|
|
oldCollisions = NULL;
|
|
}
|
|
Verify(!newCollisions);
|
|
|
|
alignment = message->alignment;
|
|
isDestroyed = 0;
|
|
// if (visualRepresentation == PrestineBothState || visualRepresentation == DestroyedBothState )
|
|
// visualRepresentation=PrestineBothState;
|
|
// else
|
|
visualRepresentation=PrestineInternalState;
|
|
ClearDestroyedFlag();
|
|
ClearTriedToMoveOffMapThisFrameFlag();
|
|
|
|
|
|
RendererComponentWeb *renderer_web = GetComponentWeb(RendererManager::VideoRendererType);
|
|
if(renderer_web)
|
|
{
|
|
VideoComponentWeb *video_web = Cast_Object(VideoComponentWeb *, renderer_web);
|
|
video_web->CleanDamage();
|
|
}
|
|
ExecuteChildComponentWebs();
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::Respawn(CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
BaseClass::Respawn(message);
|
|
//
|
|
//-----------------------------------------
|
|
// Verify that an entity can be created now
|
|
//-----------------------------------------
|
|
//
|
|
#ifdef _ARMOR
|
|
Application *app = Application::GetInstance();
|
|
Check_Object(app);
|
|
Verify(!app->InPreCollisionPhase());
|
|
#endif
|
|
|
|
#if defined(HUNT_BUG)
|
|
SPEW((HUNT_BUG, "Reusing %s(+", GetClassString()));
|
|
Spew(HUNT_BUG, GetReplicatorID());
|
|
if (owningConnection==Connection::Local)
|
|
SPEW((HUNT_BUG, "*+"));
|
|
switch (GetReplicatorMode())
|
|
{
|
|
case MasterMode:
|
|
SPEW((HUNT_BUG, ") as master"));
|
|
break;
|
|
case IndependentMode:
|
|
SPEW((HUNT_BUG, ") as independent"));
|
|
break;
|
|
case HermitMode:
|
|
SPEW((HUNT_BUG, ") as hermit"));
|
|
break;
|
|
case ReplicantMode:
|
|
SPEW((HUNT_BUG, ") as replicant"));
|
|
break;
|
|
case ClientMasterMode:
|
|
SPEW((HUNT_BUG, ") as ClientMasterMode"));
|
|
break;
|
|
case ServerMasterMode:
|
|
SPEW((HUNT_BUG, ") as ServerMasterMode"));
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//----------------------
|
|
// Set up the data list and
|
|
//----------------------
|
|
//
|
|
lastExecuted = gos_GetElapsedTime();
|
|
lastParameterization = lastExecuted - message->initialAge;
|
|
updateFlags = 0;
|
|
#if defined(TIME_BUG)
|
|
SPEW((TIME_BUG, "Reusing %s(+", GetClassString()));
|
|
Spew(TIME_BUG, GetReplicatorID());
|
|
SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds()));
|
|
#endif
|
|
|
|
lightIntensity = 0.0f;
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Set up the game model and set the flags that come from the game model
|
|
//----------------------------------------------------------------------
|
|
//
|
|
Verify(dataListResource.DoesResourceExist());
|
|
Verify(gameModelResource.DoesResourceExist());
|
|
|
|
replicatorFlags &= InterestLevelMask|GameModelMask;
|
|
replicatorFlags |= message->replicatorFlags & ~(InterestLevelMask|GameModelMask);
|
|
if (IsACollider() && IsTileBound())
|
|
replicatorFlags &= ~ColliderFlag;
|
|
|
|
|
|
// here we go...
|
|
// if we are the server than we own everything..
|
|
if (owningConnection != Connection::Hermit)
|
|
{
|
|
Verify(GetReplicatorMode() != HermitMode);
|
|
|
|
SetReplicatorMode(MasterMode);
|
|
|
|
|
|
if (Network::GetInstance()->AmIServer())
|
|
{
|
|
|
|
// if we don't own it and it is a master it will be the ServerMasterMode ( the receiver of a ClientMaster )
|
|
if ((owningConnection != Connection::Local) && (owningConnection != Connection::Hermit))
|
|
{
|
|
if (GetReplicatorMode() == MasterMode)
|
|
SetReplicatorMode(ServerMasterMode);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// we are a client so we don't own anything.
|
|
|
|
if ((owningConnection == Connection::Local) && (GetReplicatorMode() == MasterMode))
|
|
{
|
|
SetReplicatorMode(ClientMasterMode);
|
|
}
|
|
else if ((owningConnection != Connection::Local) && GetReplicatorMode() == MasterMode)
|
|
{
|
|
SetReplicatorMode(ReplicantMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (damageBit != -1)
|
|
{
|
|
EntityManager::GetInstance()->SetNetworkDamageBit(false, damageBit);
|
|
}
|
|
|
|
//
|
|
//-------------------------------
|
|
// Set the position of the entity
|
|
//-------------------------------
|
|
//
|
|
initialLocalToParent = message->localToParent;
|
|
entityElement->SetLocalToParent(message->localToParent);
|
|
NeedMatrixSync();
|
|
|
|
//
|
|
//------------------------------
|
|
// Load up the execution engines
|
|
//------------------------------
|
|
//
|
|
if(executionState)
|
|
executionState->Reuse(&message->executionState);
|
|
|
|
//
|
|
//------------------------------------------------
|
|
//Load the instance Name if it exists in the Table
|
|
//------------------------------------------------
|
|
//
|
|
|
|
alignment = message->alignment;
|
|
isDestroyed = 0;
|
|
visualRepresentation=PrestineState;
|
|
ClearDestroyedFlag();
|
|
ClearTriedToMoveOffMapThisFrameFlag();
|
|
if (oldCollisions)
|
|
{
|
|
delete oldCollisions;
|
|
oldCollisions = NULL;
|
|
}
|
|
Verify(!newCollisions);
|
|
|
|
m_whoShotMeLast = ReplicatorID::Null;
|
|
m_weaponShotMeLast = -1;
|
|
|
|
RendererComponentWeb *renderer_web = GetComponentWeb(RendererManager::VideoRendererType);
|
|
if(renderer_web)
|
|
{
|
|
VideoComponentWeb *video_web = Cast_Object(VideoComponentWeb *, renderer_web);
|
|
video_web->CleanDamage();
|
|
}
|
|
|
|
ExecuteChildComponentWebs();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SentenceToDeathRow()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Check_Object(EntityManager::GetInstance());
|
|
if (!EntityManager::GetInstance()->deathRow.IsPlugMember(this))
|
|
EntityManager::GetInstance()->deathRow.Add(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity *
|
|
Entity::CreateEntity(
|
|
MemoryStream *stream,
|
|
ReplicatorID *base_id,
|
|
bool use_armory
|
|
)
|
|
{
|
|
Check_Object(stream);
|
|
|
|
Entity::CreateMessage *message =
|
|
Cast_Pointer(Entity::CreateMessage*, stream->GetPointer());
|
|
Entity *entity;
|
|
|
|
#if 0
|
|
if(use_armory)
|
|
{
|
|
Check_Object(EntityManager::GetInstance());
|
|
if ((entity = EntityManager::GetInstance()->RequestFromArmory(message->dataListID)) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->Reuse(message);
|
|
entity->PostReuse();
|
|
return entity;
|
|
}
|
|
}
|
|
#endif
|
|
RegisteredClass::ClassID class_id = message->classID;
|
|
Entity::ClassData *class_data =
|
|
Cast_Pointer(Entity::ClassData*, RegisteredClass::FindClassData(class_id));
|
|
Check_Object(class_data);
|
|
entity =
|
|
Cast_Object(
|
|
Entity*,
|
|
(*class_data->replicatorFactory)(message, base_id)
|
|
);
|
|
Check_Object(entity);
|
|
#if 0
|
|
Check_Object(EntityManager::GetInstance());
|
|
EntityManager::GetInstance()->EntityCreation(entity);
|
|
#endif
|
|
|
|
#if defined(LAB_ONLY)
|
|
class_data->creationCount++;
|
|
#endif
|
|
|
|
return entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity::Entity(
|
|
ClassData *class_data,
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
Replicator(class_data, message, base_id),
|
|
parentEntity(NULL),
|
|
childEntityChain(NULL),
|
|
m_deathEntity(NULL)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
minTileRow=maxTileRow=0xff;
|
|
minTileColumn=maxTileColumn=0xff;
|
|
collisionAllowed=true;
|
|
|
|
executionState = NULL;
|
|
//
|
|
//-----------------------------------------
|
|
// Verify that an entity can be created now
|
|
//-----------------------------------------
|
|
//
|
|
#ifdef _ARMOR
|
|
Application *app = Application::GetInstance();
|
|
Check_Object(app);
|
|
Verify(!app->InPreCollisionPhase());
|
|
#endif
|
|
++Entity_Count;
|
|
|
|
#if defined(HUNT_BUG)
|
|
SPEW((HUNT_BUG, "Creating %s(+", GetClassString()));
|
|
Spew(HUNT_BUG, GetReplicatorID());
|
|
if (owningConnection==Connection::Local)
|
|
SPEW((HUNT_BUG, "*+"));
|
|
switch (GetReplicatorMode())
|
|
{
|
|
case MasterMode:
|
|
SPEW((HUNT_BUG, ") as master"));
|
|
break;
|
|
case IndependentMode:
|
|
SPEW((HUNT_BUG, ") as independent"));
|
|
break;
|
|
case HermitMode:
|
|
SPEW((HUNT_BUG, ") as hermit"));
|
|
break;
|
|
case ReplicantMode:
|
|
SPEW((HUNT_BUG, ") as replicant"));
|
|
break;
|
|
case ClientMasterMode:
|
|
SPEW((HUNT_BUG, ") as ClientMasterMode"));
|
|
break;
|
|
case ServerMasterMode:
|
|
SPEW((HUNT_BUG, ") as ServerMasterMode"));
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//----------------------
|
|
// Set up the data list and
|
|
//----------------------
|
|
//
|
|
lastExecuted = gos_GetElapsedTime();
|
|
lastParameterization = lastExecuted - message->initialAge;
|
|
updateFlags = 0;
|
|
#if defined(TIME_BUG)
|
|
SPEW((TIME_BUG, "Creating %s(+", GetClassString()));
|
|
Spew(TIME_BUG, GetReplicatorID());
|
|
SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds()));
|
|
#endif
|
|
|
|
|
|
isPlayerVehicle = false;
|
|
|
|
lightIntensity = 0.0f;
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Set up the game model and set the flags that come from the game model
|
|
//----------------------------------------------------------------------
|
|
//
|
|
dataListResource.FindID(message->dataListID);
|
|
Verify(dataListResource.DoesResourceExist());
|
|
ResourceID *data_list = Cast_Pointer(ResourceID*, dataListResource.GetPointer());
|
|
gameModelResource.FindID(*data_list);
|
|
Verify(gameModelResource.DoesResourceExist());
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
replicatorFlags &= ~GameModelMask;
|
|
replicatorFlags |= model->defaultFlags;
|
|
if (IsACollider() && IsTileBound())
|
|
replicatorFlags &= ~ColliderFlag;
|
|
SetInterestMask(DormantInterestLevel);
|
|
|
|
//
|
|
//------------------------------------------------
|
|
//Load the instance Name if it exists in the Table
|
|
//------------------------------------------------
|
|
//
|
|
if(NameTable::GetInstance())
|
|
{
|
|
Check_Object(NameTable::GetInstance());
|
|
instanceName = NameTable::GetInstance()->FindName(message->nameID);
|
|
NameTable::GetInstance()->SetData(message->nameID, this);
|
|
// entityElement->SetName(instanceName);
|
|
#if defined(LAB_ONLY)
|
|
if (!instanceName)
|
|
g_LastEntity[0] = '\0';
|
|
else
|
|
{
|
|
strncpy(g_LastEntity, instanceName, sizeof(g_LastEntity)-1);
|
|
g_LastEntity[sizeof(g_LastEntity)-1] = '\0';
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
instanceName = NULL;
|
|
// entityElement->SetName(dataListResource.GetName());
|
|
#if defined(LAB_ONLY)
|
|
g_LastEntity[0] = '\0';
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//--------------------------
|
|
// Create the locator object
|
|
//--------------------------
|
|
//
|
|
Check_Object(VideoRenderer::Instance);
|
|
Resource element_stream(model->elementResourceID);
|
|
Verify(element_stream.DoesResourceExist());
|
|
gos_PushCurrentHeap(ElementRenderer::GroupElement::s_Heap);
|
|
if (element)
|
|
{
|
|
Check_Object(element);
|
|
entityElement = element;
|
|
}
|
|
else
|
|
{
|
|
entityElement = new ElementRenderer::GroupElement;
|
|
Check_Object(entityElement);
|
|
}
|
|
Check_Object(entityElement);
|
|
#ifdef _DEBUG
|
|
{static void* s_p = (void*)0x08f40500;
|
|
if (s_p == (void*)this) {
|
|
int n = 0;
|
|
n++;
|
|
n--;
|
|
}}
|
|
#endif // _DEBUG
|
|
entityElement->SetClientData(this);
|
|
unsigned state;
|
|
element_stream >> state;
|
|
entityElement->SetElementState(state);
|
|
element_stream >> entityElement->m_localOBB;
|
|
solidVolume = NULL;
|
|
hierarchicalVolume = NULL;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Read a state change from stream, but if it has no changes, kill it
|
|
//-------------------------------------------------------------------
|
|
//
|
|
ElementRenderer::StateChange *states =
|
|
new ElementRenderer::StateChange(
|
|
&element_stream,
|
|
ElementRenderer::CurrentERFVersion
|
|
);
|
|
Check_Object(states);
|
|
if (states->IsRealStateChange())
|
|
entityElement->AdoptStateChange(states);
|
|
else
|
|
{
|
|
Check_Object(states);
|
|
delete states;
|
|
}
|
|
gos_PopCurrentHeap();
|
|
|
|
//
|
|
//-------------------------------
|
|
// Set the position of the entity
|
|
//-------------------------------
|
|
//
|
|
initialLocalToParent = message->localToParent;
|
|
entityElement->SetLocalToParent(message->localToParent);
|
|
NeedMatrixSync();
|
|
|
|
//
|
|
//------------------------------
|
|
// Load up the execution engines
|
|
//------------------------------
|
|
//
|
|
ExecutionStateEngine::ClassData *execution_class =
|
|
class_data->executionStateClass;
|
|
Check_Pointer(execution_class);
|
|
executionState = execution_class->Make(this, &message->executionState);
|
|
Check_Object(executionState);
|
|
objectID = message->nameID;
|
|
dontHit = NULL;
|
|
|
|
damageBit = -1;
|
|
damageObject = NULL;
|
|
|
|
alignment = message->alignment;
|
|
isDestroyed = 0;
|
|
visualRepresentation=PrestineState;
|
|
m_doesNeedToUpdateWebs = false;
|
|
if(IsDestroyed())
|
|
{
|
|
isDestroyed = 1;
|
|
SetDestroyedRepresentation();
|
|
}
|
|
ClearTriedToMoveOffMapThisFrameFlag();
|
|
|
|
oldCollisions = NULL;
|
|
newCollisions = NULL;
|
|
|
|
m_whoShotMeLast = ReplicatorID::Null;
|
|
m_weaponShotMeLast = -1;
|
|
for (unsigned i=0; i<RendererManager::RendererTypeCount; ++i)
|
|
componentWebs[i] = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity::~Entity()
|
|
{
|
|
DESTRUCTOR("Entity");
|
|
|
|
Check_Object(this);
|
|
|
|
if (oldCollisions)
|
|
{
|
|
DESTRUCTOR("Entity::OldCollisions");
|
|
delete oldCollisions;
|
|
oldCollisions = NULL;
|
|
}
|
|
Verify(!newCollisions);
|
|
|
|
//
|
|
//----------------
|
|
// Delete children
|
|
//----------------
|
|
//
|
|
--Entity_Count;
|
|
{
|
|
DESTRUCTOR("Entity::DeleteChildren");
|
|
DeleteChildEntities();
|
|
}
|
|
|
|
//
|
|
//-----------------------------
|
|
// Delete the collision volumes
|
|
//-----------------------------
|
|
//
|
|
{
|
|
DESTRUCTOR("Entity::Volumes");
|
|
if (solidVolume)
|
|
{
|
|
|
|
Check_Object(solidVolume);
|
|
delete solidVolume;
|
|
solidVolume = NULL;
|
|
}
|
|
if (hierarchicalVolume)
|
|
{
|
|
Check_Object(hierarchicalVolume);
|
|
delete hierarchicalVolume;
|
|
hierarchicalVolume = NULL;
|
|
}
|
|
}
|
|
|
|
{
|
|
DESTRUCTOR("Entity::Webs");
|
|
//
|
|
//------------------------------------
|
|
// Delete any remaining component webs
|
|
//------------------------------------
|
|
//
|
|
for (unsigned i=0; i<RendererManager::RendererTypeCount; ++i)
|
|
{
|
|
RendererComponentWeb *web = componentWebs[i];
|
|
if (web)
|
|
{
|
|
Check_Object(web);
|
|
if (web->ShouldWebBeKilled())
|
|
{
|
|
Check_Object(web);
|
|
delete web;
|
|
componentWebs[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
DESTRUCTOR("Entity::Element");
|
|
|
|
//
|
|
//-------------------
|
|
// Delete the element
|
|
//-------------------
|
|
//
|
|
Check_Object(entityElement);
|
|
delete entityElement;
|
|
}
|
|
|
|
if (executionState)
|
|
{
|
|
|
|
|
|
DESTRUCTOR("Entity::ExecutionState");
|
|
//
|
|
//----------------------------
|
|
// Remove the execution states
|
|
//----------------------------
|
|
//
|
|
Check_Object(executionState);
|
|
delete executionState;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::DestroyMessageHandler(const Message *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == DestroyMessageID);
|
|
|
|
//
|
|
//-----------------
|
|
// Destroy children
|
|
//-----------------
|
|
//
|
|
STOP(("Not implemented"));
|
|
#if 0
|
|
DeleteChildEntities();
|
|
#endif
|
|
|
|
//
|
|
//---------------------------
|
|
// Entered into deathrow once
|
|
//---------------------------
|
|
//
|
|
Check_Object(EntityManager::GetInstance());
|
|
if (!EntityManager::GetInstance()->deathRow.IsPlugMember(this))
|
|
{
|
|
EntityManager::GetInstance()->deathRow.Add(this);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::UpdateMessageHandler(const UpdateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(GetReplicatorMode() == ReplicantMode);
|
|
|
|
SetNewLocalToParent(message->localToParent);
|
|
SyncMatrices(true);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool
|
|
Entity::FriendlyFire(const TakeDamageMessage *message)
|
|
{
|
|
return false;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::TakeDamageMessageHandler(const TakeDamageMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == TakeDamageMessageID);
|
|
|
|
if(damageObject)
|
|
{
|
|
if (!FriendlyFire(message))
|
|
{
|
|
Check_Pointer(damageObject);
|
|
damageObject->TakeDamage((TakeDamageMessage *)message, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::BecomeInterestingMessageHandler(const BecomeInterestingMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == BecomeInterestingMessageID);
|
|
Verify(message->m_render);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Find the zone the entity lives in. If the zone is no longer interesting,
|
|
// ignore the message
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
ElementRenderer::Element *element = GetElement();
|
|
Check_Object(element);
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
if (element->GetClassID() == TileClassID)
|
|
{
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
}
|
|
Zone *zone = Cast_Object(Zone*, element);
|
|
|
|
//
|
|
//------------------
|
|
// Is this the hole?
|
|
//------------------
|
|
//
|
|
Entity::InterestLevel
|
|
zone_interest = zone->GetInterestLevel(),
|
|
entity_interest = GetInterestLevel();
|
|
|
|
switch ((zone_interest<<2) | entity_interest)
|
|
{
|
|
case (Entity::DormantInterestLevel<<2)|Entity::DormantInterestLevel:
|
|
STOP(("Dormant:Dormant is unhandled"));
|
|
break;
|
|
|
|
case (Entity::DormantInterestLevel<<2)|Entity::SimulationInterestLevel:
|
|
STOP(("Dormant:Simulation is unhandled"));
|
|
break;
|
|
|
|
case (Entity::DormantInterestLevel<<2)|Entity::RenderingInterestLevel:
|
|
STOP(("Dormant:Rendering is unhandled"));
|
|
break;
|
|
|
|
case (Entity::SimulationInterestLevel<<2)|Entity::DormantInterestLevel:
|
|
STOP(("Simulation:Dormant is unhandled"));
|
|
break;
|
|
|
|
case (Entity::RenderingInterestLevel<<2)|Entity::DormantInterestLevel:
|
|
Verify(zone->m_dormant.IsPlugMember(this));
|
|
Verify(!zone->m_simulated.IsPlugMember(this));
|
|
Verify(!zone->m_rendered.IsPlugMember(this));
|
|
zone->m_dormant.Remove(this);
|
|
zone->m_rendered.Add(this);
|
|
BecomeInteresting(true);
|
|
break;
|
|
|
|
case (Entity::SimulationInterestLevel<<2)|Entity::SimulationInterestLevel:
|
|
case (Entity::SimulationInterestLevel<<2)|Entity::RenderingInterestLevel:
|
|
Verify(!zone->m_dormant.IsPlugMember(this));
|
|
Verify(zone->m_simulated.IsPlugMember(this));
|
|
Verify(!zone->m_rendered.IsPlugMember(this));
|
|
break;
|
|
|
|
case (Entity::RenderingInterestLevel<<2)|Entity::SimulationInterestLevel:
|
|
Verify(!zone->m_dormant.IsPlugMember(this));
|
|
Verify(zone->m_simulated.IsPlugMember(this));
|
|
Verify(!zone->m_rendered.IsPlugMember(this));
|
|
zone->m_simulated.Remove(this);
|
|
zone->m_rendered.Add(this);
|
|
BecomeInteresting(true);
|
|
break;
|
|
|
|
case (Entity::RenderingInterestLevel<<2)|Entity::RenderingInterestLevel:
|
|
Verify(!zone->m_dormant.IsPlugMember(this));
|
|
if (zone->m_simulated.IsPlugMember(this))
|
|
{
|
|
Verify(!zone->m_rendered.IsPlugMember(this));
|
|
zone->m_simulated.Remove(this);
|
|
zone->m_rendered.Add(this);
|
|
}
|
|
else
|
|
{
|
|
Verify(!zone->m_simulated.IsPlugMember(this));
|
|
Verify(zone->m_rendered.IsPlugMember(this));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
STOP(("Illegal interest level setting"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::RequestUpdate(int update_flags)
|
|
{
|
|
Check_Object(this);
|
|
Verify(update_flags != 0);
|
|
Verify(GetReplicatorMode() == MasterMode);
|
|
Verify(owningConnection == Connection::Local);
|
|
|
|
#if defined(HUNT_BUG)
|
|
SPEW((HUNT_BUG, "Requesting Update for %s(+", GetClassString()));
|
|
Spew(HUNT_BUG, GetReplicatorID());
|
|
SPEW((HUNT_BUG, ")"));
|
|
#endif
|
|
|
|
if (!updateFlags)
|
|
{
|
|
updateFlags = update_flags;
|
|
Check_Object(EntityManager::GetInstance());
|
|
EntityManager::GetInstance()->RequestUpdate(this);
|
|
}
|
|
else
|
|
updateFlags |= update_flags;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity::UpdateMessage*
|
|
Entity::ConstructUpdate(Stuff::MemoryStream *stream)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
Verify(updateFlags);
|
|
Verify(GetReplicatorMode() == MasterMode);
|
|
Verify(owningConnection == Connection::Local);
|
|
|
|
#if defined(HUNT_BUG)
|
|
SPEW((HUNT_BUG, "Constructing Update for %s(+", GetClassString()));
|
|
Spew(HUNT_BUG, GetReplicatorID());
|
|
SPEW((HUNT_BUG, ")"));
|
|
#endif
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// Make sure there is enough room for the update on the stream
|
|
//------------------------------------------------------------
|
|
//
|
|
stream->AllocateBytes(sizeof(UpdateMessage));
|
|
UpdateMessage *message =
|
|
new(stream->GetPointer()) UpdateMessage(
|
|
replicatorID,
|
|
GetLocalToWorld()
|
|
);
|
|
return message;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetInterestLevel(InterestLevel interest)
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//---------------------------------------------
|
|
// Tell the zone to update our interest setting
|
|
//---------------------------------------------
|
|
//
|
|
ElementRenderer::Element *element = GetElement();
|
|
Check_Object(element);
|
|
Zone *zone = Cast_Object(Zone*, element->GetParentElement());
|
|
zone->SetInterestLevel(this, interest);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::BindToZone()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------------------------------
|
|
// If we are already zone bound, just return
|
|
//------------------------------------------
|
|
//
|
|
if (!IsTileBound())
|
|
return;
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// We are tile bound now, so find the tile through our element's parent
|
|
//---------------------------------------------------------------------
|
|
//
|
|
ElementRenderer::Element *element = GetElement();
|
|
Check_Object(element);
|
|
Tile *tile = Cast_Object(Tile*, element->GetParentElement());
|
|
ElementRenderer::Element *mid = tile->GetParentElement();
|
|
Check_Object(mid);
|
|
Zone *zone = Cast_Object(Zone*, mid->GetParentElement());
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// Unhook the collision, change the flag and hook it back up again
|
|
//----------------------------------------------------------------
|
|
//
|
|
zone->DetachChild(element);
|
|
replicatorFlags &= ~TileBoundFlag;
|
|
zone->AttachChild(element);
|
|
element->Sync();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::BindToTile()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------------------------------
|
|
// If we are already tile bound, just return
|
|
//------------------------------------------
|
|
//
|
|
if (IsTileBound())
|
|
return;
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// We are tile bound now, so find the tile through our element's parent
|
|
//---------------------------------------------------------------------
|
|
//
|
|
ElementRenderer::Element *element = GetElement();
|
|
Check_Object(element);
|
|
Zone *zone = Cast_Object(Zone*, element->GetParentElement());
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// Unhook the collision, change the flag and hook it back up again
|
|
//----------------------------------------------------------------
|
|
//
|
|
zone->DetachChild(element);
|
|
replicatorFlags |= TileBoundFlag;
|
|
zone->AttachChild(element);
|
|
element->Sync();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetCollisionMask(CollisionMask mask)
|
|
{
|
|
Check_Object(this);
|
|
Verify(GetParentEntity() == Map::GetInstance());
|
|
|
|
//
|
|
//----------------------------------
|
|
// Find the zone we are connected to
|
|
//----------------------------------
|
|
//
|
|
ElementRenderer::Element *element = GetElement();
|
|
Check_Object(element);
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
if (element->GetClassID() == TileClassID)
|
|
{
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
}
|
|
Zone *zone = Cast_Object(Zone*, element);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Unhook from the current zone and reattach to it after setting our mask
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
zone->UnhookCollision(this);
|
|
replicatorFlags &= ~AlwaysCollidesMask;
|
|
replicatorFlags |= mask;
|
|
zone->HookUpCollision(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetDestroyedFlag(int damage_mode)
|
|
{
|
|
Check_Object(this);
|
|
replicatorFlags |= DestroyedFlag;
|
|
// MSL 5.05 Torso
|
|
if((damage_mode == InternalDamageObject::DestructionDamageMode) ||
|
|
(damage_mode == InternalDamageObject::DetachableDamageMode) ||
|
|
(damage_mode == InternalDamageObject::ArmLeftDamageMode) ||
|
|
(damage_mode == InternalDamageObject::ArmRightDamageMode))
|
|
{
|
|
if (solidVolume)
|
|
{
|
|
Check_Object(solidVolume);
|
|
if (!solidVolume->IsDestroyed())
|
|
solidVolume->Destroy();
|
|
}
|
|
if (hierarchicalVolume)
|
|
{
|
|
Check_Object(hierarchicalVolume);
|
|
if (!hierarchicalVolume->IsDestroyed())
|
|
hierarchicalVolume->Destroy();
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetTriedToMoveOffMapThisFrameFlag()
|
|
{
|
|
Check_Object(this);
|
|
replicatorFlags |= TriedToMoveOffMapThisFrameFlag;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetDestroyedRepresentation()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(visualRepresentation == PrestineState)
|
|
visualRepresentation = DestroyedState;
|
|
else if(visualRepresentation == PrestineInternalState)
|
|
visualRepresentation = DestroyedInternalState;
|
|
else if(visualRepresentation == PrestineBothState)
|
|
visualRepresentation = DestroyedBothState;
|
|
else if(visualRepresentation == PrestineNoneState)
|
|
visualRepresentation = DestroyedNoneState;
|
|
|
|
|
|
m_doesNeedToUpdateWebs = true;
|
|
|
|
//THIS CAN'T BE CALLED HERE EVER!!!!!!!
|
|
//ExecuteChildComponentWebs();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetInternalRepresentation()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(visualRepresentation == PrestineState || visualRepresentation == PrestineBothState || visualRepresentation == PrestineNoneState)
|
|
visualRepresentation = PrestineInternalState;
|
|
else if(visualRepresentation == DestroyedState || visualRepresentation == DestroyedBothState || visualRepresentation == DestroyedNoneState)
|
|
visualRepresentation = DestroyedInternalState;
|
|
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
|
|
while((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->SetInternalRepresentation();
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetBothRepresentation()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(visualRepresentation == PrestineState || visualRepresentation == PrestineInternalState || visualRepresentation == PrestineNoneState)
|
|
visualRepresentation = PrestineBothState;
|
|
else if(visualRepresentation == DestroyedState || visualRepresentation == DestroyedInternalState || visualRepresentation == DestroyedNoneState)
|
|
visualRepresentation = DestroyedBothState;
|
|
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
|
|
while((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->SetBothRepresentation();
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetNoneRepresentation()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(visualRepresentation == PrestineState || visualRepresentation == PrestineInternalState || visualRepresentation == PrestineBothState)
|
|
visualRepresentation = PrestineNoneState;
|
|
else if(visualRepresentation == DestroyedState || visualRepresentation == DestroyedInternalState || visualRepresentation == DestroyedBothState)
|
|
visualRepresentation = DestroyedNoneState;
|
|
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
|
|
while((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->SetNoneRepresentation();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetExternalRepresentation()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(visualRepresentation == PrestineInternalState || visualRepresentation == PrestineBothState || visualRepresentation == PrestineNoneState)
|
|
visualRepresentation = PrestineState;
|
|
else if(visualRepresentation == DestroyedInternalState || visualRepresentation == DestroyedBothState || visualRepresentation == DestroyedNoneState)
|
|
visualRepresentation = DestroyedState;
|
|
|
|
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
|
|
while((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->SetExternalRepresentation();
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::ClearDestroyedFlag()
|
|
{
|
|
Check_Object(this);
|
|
replicatorFlags &= ~DestroyedFlag;
|
|
if (solidVolume)
|
|
{
|
|
Check_Object(solidVolume);
|
|
solidVolume->Restore();
|
|
}
|
|
if (hierarchicalVolume)
|
|
{
|
|
Check_Object(hierarchicalVolume);
|
|
hierarchicalVolume->Restore();
|
|
}
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::ClearTriedToMoveOffMapThisFrameFlag()
|
|
{
|
|
Check_Object(this);
|
|
replicatorFlags &= ~TriedToMoveOffMapThisFrameFlag;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetDamageObject(DamageObject *damage_object)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(damage_object);
|
|
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
//Need to set the damage object and the damage object for its children
|
|
//--------------------------------------------------------------------
|
|
//
|
|
while((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
if(entity->damageObject == NULL)
|
|
{
|
|
entity->SetDamageObject(damage_object);
|
|
}
|
|
}
|
|
damageObject = damage_object;
|
|
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::DestroyChildren(int damage_mode)
|
|
{
|
|
Check_Object(this);
|
|
|
|
DestroyDamageObjects();
|
|
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
|
|
while((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->DestroyChildren(damage_mode);
|
|
}
|
|
|
|
Entity::ReactToDestruction(damage_mode, 0);
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool
|
|
Entity::IsDestroyable()
|
|
{
|
|
if (damageObject != NULL)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void
|
|
Entity::ReactToDestruction(int damage_mode,int damage_type)
|
|
{
|
|
Check_Object(this);
|
|
isDestroyed = 1;
|
|
SetDestroyedRepresentation();
|
|
SetDestroyedFlag(damage_mode);
|
|
|
|
if (damageBit != -1)
|
|
{
|
|
//SPEW(("jerryeds", "ENTITY DESTROYED - TILE : %d : %d", minTileRow, minTileColumn));
|
|
EntityManager::GetInstance()->SetNetworkDamageBit(true, damageBit);
|
|
}
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::ApplyVisualDamage(const TakeDamageMessage *message, int armor_zone)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
if (message->quickDamage)
|
|
return;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
//Apply a procedural Damage Effect to ourselves if we have not before
|
|
//-------------------------------------------------------------------
|
|
//
|
|
if(!IsDestroyed())
|
|
{
|
|
Check_Object(VideoRenderer::Instance);
|
|
LinearMatrix4D damage_matrix = LinearMatrix4D::Identity;
|
|
Point3D damage_location;
|
|
RendererComponentWeb *renderer_web = GetComponentWeb(RendererManager::VideoRendererType);
|
|
if(renderer_web)
|
|
{
|
|
VideoComponentWeb *video_web = Cast_Object(VideoComponentWeb *, renderer_web);
|
|
|
|
damage_location.MultiplyByInverse(message->hitOffset, GetLocalToWorld());
|
|
damage_matrix.BuildTranslation(damage_location);
|
|
Vector3D damage_rotation;
|
|
damage_rotation.Negate(message->normal);
|
|
damage_matrix.AlignLocalAxisToWorldVector(damage_rotation, Z_Axis, Y_Axis, X_Axis);
|
|
|
|
Scalar radius = message->amountOfDamage * 0.1f;
|
|
|
|
Clamp(radius, 0.5f, 1.0f);
|
|
|
|
if(armor_zone == DamageObject::DefaultArmorZone)
|
|
{
|
|
if(!HasPlacedDamageDecal())
|
|
{
|
|
MidLevelRenderer::MLRTexture *texture =
|
|
(*MidLevelRenderer::MLRTexturePool::Instance)((const char *)"scorch");
|
|
if(texture)
|
|
{
|
|
Check_Object(texture);
|
|
damage_matrix(3,0) -= damage_matrix(2,0);
|
|
damage_matrix(3,1) -= damage_matrix(2,1);
|
|
damage_matrix(3,2) -= damage_matrix(2,2);
|
|
radius *= 5.0f;
|
|
video_web->ApplyDamageDecal(damage_matrix, radius, texture);
|
|
SetDamageDecalFlag();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
video_web->ApplyDamage(damage_matrix, radius);
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
Entity *entity_to_check = GetParentEntity();
|
|
|
|
// traverse parents looking for a web
|
|
while (entity_to_check!=NULL)
|
|
{
|
|
// stop at the map
|
|
if (entity_to_check == Map::GetInstance())
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// stop at a parent with a web
|
|
RendererComponentWeb *renderer_web = entity_to_check->GetComponentWeb(RendererManager::VideoRendererType);
|
|
if (renderer_web != NULL)
|
|
{
|
|
entity_to_check->ApplyVisualDamage(message,armor_zone);
|
|
break;
|
|
}
|
|
}
|
|
entity_to_check = entity_to_check->GetParentEntity();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
AttributeEntry*
|
|
Entity::GetAttributeEntry(AttributeID attribute_ID)
|
|
{
|
|
ClassData *class_data = Cast_Pointer(ClassData*, classData);
|
|
Check_Object(class_data);
|
|
return class_data->attributeTable.GetAttributeEntry(attribute_ID);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
AttributeEntry*
|
|
Entity::GetAttributeEntry(const char *attribute_name)
|
|
{
|
|
ClassData *class_data = Cast_Pointer(ClassData*, classData);
|
|
Check_Object(class_data);
|
|
return class_data->attributeTable.GetAttributeEntry(attribute_name);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::GetGameModelResourceFromDataListID(
|
|
Resource *resource,
|
|
const ResourceID &data_list
|
|
)
|
|
{
|
|
Resource stream(data_list);
|
|
Verify(stream.GetSize() >= sizeof(ResourceID));
|
|
ResourceID resource_id;
|
|
stream >> resource_id;
|
|
resource->FindID(resource_id);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
RegisteredClass::ClassID
|
|
Entity::GetClassIDFromDataListID(const ResourceID &model_list)
|
|
{
|
|
Resource resource;
|
|
GetGameModelResourceFromDataListID(&resource, model_list);
|
|
GameModel *model = Cast_Pointer(GameModel*,resource.GetPointer());
|
|
return model->classID;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::AddChild(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
//
|
|
//-----------------------------
|
|
// Hook up the entity hierarchy
|
|
//-----------------------------
|
|
//
|
|
Verify(!entity->parentEntity);
|
|
entity->parentEntity = this;
|
|
childEntityChain.Add(entity);
|
|
entity->NeedMatrixSync();
|
|
ElementRenderer::Element *child_element = entity->GetElement();
|
|
Check_Object(child_element);
|
|
Check_Object(entityElement);
|
|
entityElement->AttachChild(child_element);
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// If are bounds are not locked, calculate them again
|
|
//---------------------------------------------------
|
|
//
|
|
if (
|
|
!entityElement->AreBoundsLocked()
|
|
&& entityElement->GetCullMode() == ElementRenderer::Element::VolumeCullMode
|
|
)
|
|
{
|
|
entityElement->NeedNewBounds();
|
|
NeedMatrixSync();
|
|
}
|
|
|
|
#if defined(HUNT_BUG)
|
|
SPEW((0, "Attaching %s(+", entity->GetClassString()));
|
|
Spew(0, entity->GetReplicatorID());
|
|
SPEW((0, ") to %s(+", GetClassString()));
|
|
Spew(0, GetReplicatorID());
|
|
SPEW((0, ")"));
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::RemoveChild(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
//
|
|
//-----------------------------
|
|
// Unhook the locator hierarchy
|
|
//-----------------------------
|
|
//
|
|
entity->parentEntity = NULL;
|
|
childEntityChain.Remove(entity);
|
|
entity->NeedMatrixSync();
|
|
ElementRenderer::Element *element = entity->GetElement();
|
|
Check_Object(element);
|
|
entityElement->DetachChild(element);
|
|
|
|
#if defined(HUNT_BUG)
|
|
SPEW((0, "Attaching %s(+", entity->GetClassString()));
|
|
Spew(0, entity->GetReplicatorID());
|
|
SPEW((0, ") to %s(+", GetClassString()));
|
|
Spew(0, GetReplicatorID());
|
|
SPEW((0, ")"));
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetNewLocalToParent(const Stuff::LinearMatrix4D &new_local_to_world)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Check_Object(entityElement);
|
|
Check_Object(parentEntity);
|
|
ClearTriedToMoveOffMapThisFrameFlag();
|
|
//
|
|
//-----------------------------------------------------------
|
|
// If our parent isn't the map, set the dirty flag and matrix
|
|
//-----------------------------------------------------------
|
|
//
|
|
if (parentEntity != Map::GetInstance())
|
|
{
|
|
entityElement->SetLocalToParent(new_local_to_world);
|
|
replicatorFlags |= DirtyMatrixFlag;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// If we are parented to the map, the zone is dirty, and then bodge in a
|
|
// check to make sure nothing leaves the map
|
|
//----------------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
Point3D translation(new_local_to_world);
|
|
Check_Object(Map::GetInstance());
|
|
if (Map::GetInstance()->FindZone(translation) == -1)
|
|
{
|
|
LinearMatrix4D adjusted_matrix = new_local_to_world;
|
|
const LinearMatrix4D &old_matrix = GetLocalToWorld();
|
|
adjusted_matrix(3,0) = old_matrix(3,0);
|
|
adjusted_matrix(3,2) = old_matrix(3,2);
|
|
entityElement->SetLocalToParent(adjusted_matrix);
|
|
replicatorFlags |= DirtyMatrixFlag | TriedToMoveOffMapThisFrameFlag;
|
|
}
|
|
else
|
|
{
|
|
entityElement->SetLocalToParent(new_local_to_world);
|
|
replicatorFlags |= DirtyMatrixFlag|DirtyZoneFlag|PostCollisionFlag;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::ChildPreCollisionChanged(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
STOP(("This function should be overridden!"));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::DeleteChildEntities()
|
|
{
|
|
Check_Object(this);
|
|
childEntityChain.DeletePlugs();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SetComponentWeb(
|
|
unsigned renderer_id,
|
|
RendererComponentWeb *web
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
if(componentWebs[renderer_id])
|
|
{
|
|
delete componentWebs[renderer_id];
|
|
}
|
|
componentWebs[renderer_id] = web;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::ExecuteComponentWebs()
|
|
{
|
|
Check_Object(this);
|
|
POSTCOLLISION_LOGIC("Entity::Execute Webs");
|
|
|
|
//
|
|
//----------------------------
|
|
// Execute each registered web
|
|
//----------------------------
|
|
//
|
|
for (unsigned i=1; i<RendererManager::RendererTypeCount; ++i)
|
|
{
|
|
ComponentWeb *web = componentWebs[i];
|
|
if (web)
|
|
{
|
|
Check_Object(web);
|
|
web->ExecuteWatcherComponents();
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::BecomeInteresting(bool render_me)
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//--------------------------------------
|
|
// Tell the renderers we are interesting
|
|
//--------------------------------------
|
|
//
|
|
LOAD_LOGIC("Become Interesting::Entity");
|
|
Start_Timer(Renderer_Loading);
|
|
Check_Object(RendererManager::Instance);
|
|
RendererManager::Instance->EntityIsInteresting(this, render_me);
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// The entity version will just load the solid volumes. Go ahead and load
|
|
// the stream resource that should be indicated in the game model
|
|
//------------------------------------------------------------------------
|
|
//
|
|
if (!solidVolume && !hierarchicalVolume)
|
|
{
|
|
LOAD_LOGIC("Become Interesting::Entity::Load Collision Volumes");
|
|
const GameModel *game_model = GetGameModel();
|
|
Check_Object(game_model);
|
|
|
|
#if defined(LAB_ONLY)
|
|
if (!instanceName)
|
|
g_LastEntity[0] = '\0';
|
|
else
|
|
{
|
|
strncpy(g_LastEntity, instanceName, sizeof(g_LastEntity)-1);
|
|
g_LastEntity[sizeof(g_LastEntity)-1] = '\0';
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//-------------------------------
|
|
// Load in the solid if it exists
|
|
//-------------------------------
|
|
//
|
|
if (game_model->obbStreamResourceID != ResourceID::Null)
|
|
{
|
|
Resource obb_stream(game_model->obbStreamResourceID);
|
|
Verify(obb_stream.DoesResourceExist());
|
|
gos_PushCurrentHeap(s_CollisionHeap);
|
|
solidVolume =
|
|
new CollisionVolume(
|
|
this,
|
|
&obb_stream,
|
|
CollisionVolume::ReadOBBVersion(&obb_stream)
|
|
);
|
|
Check_Object(solidVolume);
|
|
gos_PopCurrentHeap();
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
// Mark our interest level according to the render level
|
|
//------------------------------------------------------
|
|
//
|
|
#if defined ARMOR
|
|
if (render_me)
|
|
Verify(!Application::GetInstance()->m_localMissionParameters.m_runDedicated);
|
|
#endif
|
|
{
|
|
LOAD_LOGIC("Become Interesting::Entity::Set Interest Mask");
|
|
SetInterestMask((render_me) ? RenderingInterestLevel : SimulationInterestLevel);
|
|
#if defined(_ARMOR)
|
|
ElementRenderer::Element *element = GetElement();
|
|
Check_Object(element);
|
|
element = element->GetParentElement();
|
|
if (element)
|
|
{
|
|
if (element->GetClassID() == TileClassID)
|
|
{
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
element = element->GetParentElement();
|
|
Check_Object(element);
|
|
}
|
|
if (element->GetClassID() == ZoneClassID)
|
|
{
|
|
Zone *zone = Cast_Object(Zone*, element);
|
|
Verify(!zone->m_dormant.IsPlugMember(this));
|
|
if (render_me && zone->GetInterestLevel() == RenderingInterestLevel)
|
|
{
|
|
Verify(!zone->m_simulated.IsPlugMember(this));
|
|
Verify(zone->m_rendered.IsPlugMember(this));
|
|
}
|
|
else
|
|
{
|
|
Verify(zone->m_simulated.IsPlugMember(this));
|
|
Verify(!zone->m_rendered.IsPlugMember(this));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
Stop_Timer(Renderer_Loading);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::BecomeUninteresting()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//----------------------------
|
|
// Execute each registered web
|
|
//----------------------------
|
|
//
|
|
for (unsigned i=1; i<RendererManager::RendererTypeCount; ++i)
|
|
{
|
|
RendererComponentWeb *web = componentWebs[i];
|
|
if (web)
|
|
{
|
|
Check_Object(web);
|
|
if (web->ShouldWebBeKilled())
|
|
{
|
|
Check_Object(web);
|
|
delete web;
|
|
componentWebs[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------
|
|
// Delete the solid volume
|
|
//------------------------
|
|
//
|
|
if (solidVolume)
|
|
{
|
|
Check_Object(solidVolume);
|
|
delete solidVolume;
|
|
solidVolume = NULL;
|
|
}
|
|
if (hierarchicalVolume)
|
|
{
|
|
Check_Object(hierarchicalVolume);
|
|
delete hierarchicalVolume;
|
|
hierarchicalVolume = NULL;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const ResourceID&
|
|
Entity::GetRendererDataResourceID(int renderer_type)
|
|
{
|
|
Check_Object(this);
|
|
ResourceID *data_list = Cast_Pointer(ResourceID*, dataListResource.GetPointer());
|
|
Check_Pointer(data_list);
|
|
Check_Object(RendererManager::Instance);
|
|
Verify(
|
|
0 <= renderer_type &&
|
|
renderer_type < RendererManager::Instance->GetModelListSize()
|
|
);
|
|
return data_list[renderer_type];
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
Entity::GetExecutionSlot()
|
|
{
|
|
Check_Object(this);
|
|
return DefaultExecutionSlot;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
Verify(!EntityManager::GetInstance()->isExecutionSuspended);
|
|
Verify(GetInterestLevel() != DormantInterestLevel);
|
|
collisionAllowed=true;
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Check to see if a post collision pass in necessary. If so, attach this
|
|
// entity to the entitymanager post collision chain
|
|
//------------------------------------------------------------------------
|
|
//
|
|
if (IsUsingPostCollision())
|
|
{
|
|
Check_Object(EntityManager::GetInstance());
|
|
EntityManager::GetInstance()->RequestPostCollisionExecution(this);
|
|
}
|
|
else
|
|
{
|
|
lastExecuted = till;
|
|
#if defined(TIME_BUG)
|
|
SPEW((TIME_BUG, "PreCollisionOnly execution of %s(+", GetClassString()));
|
|
Spew(TIME_BUG, GetReplicatorID());
|
|
SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds()));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Entity::CollisionHandler(
|
|
Stuff::LinearMatrix4D *new_position,
|
|
Stuff::DynamicArrayOf<CollisionData> *collisions
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(collisions);
|
|
Verify(GetInterestLevel() != DormantInterestLevel);
|
|
Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));
|
|
|
|
newCollisions = collisions;
|
|
SPEW((0, "%s should override CollisionHandler", (char*)GetClassString() ));
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SyncMatrices(bool update_matrix)
|
|
{
|
|
Check_Object(this);
|
|
SYNC_LOGIC("Entity");
|
|
|
|
#if defined(HUNT_BUG)
|
|
bool old_update=update_matrix;
|
|
if (update_matrix)
|
|
{
|
|
SPEW((0, "Entity::SyncMatrices %s(+", GetClassString()));
|
|
Spew(0, GetReplicatorID());
|
|
SPEW((0, ")"));
|
|
}
|
|
#endif
|
|
Set_Statistic(s_EntitiesSynced, s_EntitiesSynced+1);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// If we have a dirty locator, sync with it
|
|
//-----------------------------------------
|
|
//
|
|
if (IsMatrixDirty())
|
|
{
|
|
if (update_matrix)
|
|
{
|
|
Check_Object(entityElement);
|
|
entityElement->Sync();
|
|
update_matrix = false;
|
|
}
|
|
ClearNeedMatrixSync();
|
|
}
|
|
|
|
//
|
|
//-----------------------------
|
|
// Sync our children's locators
|
|
//-----------------------------
|
|
//
|
|
if (!childEntityChain.IsEmpty())
|
|
{
|
|
ChainIteratorOf<Entity *> children(&childEntityChain);
|
|
Entity *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->SyncMatrices(update_matrix);
|
|
}
|
|
}
|
|
|
|
#if defined(HUNT_BUG)
|
|
if (old_update)
|
|
SPEW((0, ""));
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::SyncMatricesFirstLevelOnly(bool update_matrix)
|
|
{
|
|
Check_Object(this);
|
|
|
|
// DANGER DANGER DANGER!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// THIS IS A NETWORK HACK
|
|
// USE IT AT OWN RISK
|
|
|
|
#if defined(HUNT_BUG)
|
|
bool old_update=update_matrix;
|
|
if (update_matrix)
|
|
{
|
|
SPEW((0, "Entity::SyncMatrices %s(+", GetClassString()));
|
|
Spew(0, GetReplicatorID());
|
|
SPEW((0, ")"));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// If we have a dirty locator, sync with it
|
|
//-----------------------------------------
|
|
//
|
|
if (IsMatrixDirty())
|
|
{
|
|
if (update_matrix)
|
|
{
|
|
Check_Object(entityElement);
|
|
entityElement->Sync();
|
|
update_matrix = false;
|
|
}
|
|
ClearNeedMatrixSync();
|
|
}
|
|
|
|
#if defined(HUNT_BUG)
|
|
if (old_update)
|
|
SPEW((0, ""));
|
|
#endif
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::PostCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
Verify(GetInterestLevel() != DormantInterestLevel);
|
|
POSTCOLLISION_LOGIC("Entity");
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Remove the old collision list if it exists, then swap to the new list
|
|
// for next time
|
|
//----------------------------------------------------------------------
|
|
//
|
|
if (oldCollisions)
|
|
delete oldCollisions;
|
|
oldCollisions = newCollisions;
|
|
newCollisions = NULL;
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// If the zone is dirty, let the map figure out where the entity should
|
|
// live
|
|
//---------------------------------------------------------------------
|
|
//
|
|
if (IsZoneDirty())
|
|
{
|
|
POSTCOLLISION_LOGIC("Entity::UpdateZone");
|
|
Verify(parentEntity == Map::GetInstance());
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->UpdateZone(this);
|
|
Verify(!IsZoneDirty());
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Execute the component webs and update the simulation frame counter
|
|
//-------------------------------------------------------------------
|
|
//
|
|
ExecuteComponentWebs();
|
|
lastExecuted = till;
|
|
#if defined(TIME_BUG)
|
|
SPEW((TIME_BUG, "PostCollision execution of %s(+", GetClassString()));
|
|
Spew(TIME_BUG, GetReplicatorID());
|
|
SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds()));
|
|
#endif
|
|
|
|
if(m_doesNeedToUpdateWebs)
|
|
{
|
|
m_doesNeedToUpdateWebs = false;
|
|
ExecuteChildComponentWebs();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::PlaceOnEntity(
|
|
LinearMatrix4D *position,
|
|
Motion3D *velocity,
|
|
const LinearMatrix4D& initial_offset,
|
|
const Motion3D& initial_velocity
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(position);
|
|
Check_Object(velocity);
|
|
STOP(("Not implemented"));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::FollowAndBillBoard(
|
|
Stuff::LinearMatrix4D *position,
|
|
Stuff::UnitVector3D *direction
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(position);
|
|
Check_Object(direction);
|
|
|
|
LinearMatrix4D new_local_to_parent = *position;
|
|
Point3D new_translation;
|
|
new_translation = *position;
|
|
new_local_to_parent.BuildTranslation(new_translation);
|
|
new_local_to_parent.AlignLocalAxisToWorldVector(*direction, Y_Axis, Z_Axis, X_Axis);
|
|
SetNewLocalToParent(new_local_to_parent);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::EnterNeverExecuteState()
|
|
{
|
|
Check_Object(this);
|
|
Verify(!newCollisions);
|
|
if(parentEntity)
|
|
{
|
|
Check_Object(parentEntity);
|
|
parentEntity->ChildPreCollisionChanged(this);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::LeaveNeverExecuteState()
|
|
{
|
|
Check_Object(this);
|
|
lastExecuted = gos_GetElapsedTime();
|
|
collisionAllowed = false;
|
|
if(parentEntity)
|
|
{
|
|
Check_Object(parentEntity);
|
|
parentEntity->ChildPreCollisionChanged(this);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity*
|
|
Entity::ProjectLine(
|
|
Line3D *line,
|
|
CollisionMask mask,
|
|
Point3D *target_offset,
|
|
Normal3D *normal
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(line);
|
|
Check_Pointer(target_offset);
|
|
Check_Pointer(normal);
|
|
|
|
Check_Object(Map::GetInstance());
|
|
CollisionQuery query(line, normal, mask, this);
|
|
return CollisionGrid::Instance->ProjectLine(&query);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Entity::IsWithin(
|
|
Entity *target,
|
|
Scalar distance,
|
|
bool ignorey
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(target);
|
|
|
|
Vector3D target_line = Vector3D::Identity;
|
|
Point3D our_position;
|
|
Point3D target_position;
|
|
|
|
our_position = GetLocalToWorld();
|
|
target_position = target->GetLocalToWorld();
|
|
if ((our_position.y < -1500) || (target_position.y < -1500)) // units in hell are never near each other
|
|
return false;
|
|
|
|
if (ignorey)
|
|
{
|
|
our_position.y = 0;
|
|
target_position.y = 0;
|
|
}
|
|
|
|
target_line.Subtract(target_position, our_position);
|
|
|
|
return target_line.GetLengthSquared() <= (distance * distance);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Scalar
|
|
Entity::GetDistanceFrom(Entity *target)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(target);
|
|
|
|
Vector3D target_line = Vector3D::Identity;
|
|
Point3D our_position;
|
|
Point3D target_position;
|
|
|
|
our_position = GetLocalToWorld();
|
|
target_position = target->GetLocalToWorld();
|
|
|
|
target_line.Subtract(target_position, our_position);
|
|
|
|
return target_line.GetLength();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Scalar
|
|
Entity::GetDistanceSquaredFrom(Entity *target, bool ignore_y)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(target);
|
|
|
|
Vector3D target_line = Vector3D::Identity;
|
|
Point3D our_position;
|
|
Point3D target_position;
|
|
|
|
our_position = GetLocalToWorld();
|
|
target_position = target->GetLocalToWorld();
|
|
|
|
target_line.Subtract(target_position, our_position);
|
|
if(ignore_y)
|
|
target_line.y = 0.0f;
|
|
|
|
return target_line.GetLengthSquared();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::ExecuteChildComponentWebs()
|
|
{
|
|
Check_Object(this);
|
|
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
while((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->ExecuteChildComponentWebs();
|
|
}
|
|
ExecuteComponentWebs();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::RemoveCollision()
|
|
{
|
|
Check_Object(this);
|
|
SetCollisionMask(NeverCollidesMask);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool
|
|
Entity::IsNeverExecuteState()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Check_Object(executionState);
|
|
if (executionState->GetState() == Entity::ExecutionStateEngine::NeverExecuteState)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Entity::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
|
|
ResourceID *data_list = Cast_Pointer(ResourceID*, dataListResource.GetPointer());
|
|
if (data_list != NULL)
|
|
{
|
|
Check_Object(RendererManager::Instance);
|
|
size_t len = RendererManager::Instance->GetModelListSize();
|
|
for (size_t i = 0; i < len; i++)
|
|
{
|
|
if (data_list[i] != ResourceID::Null)
|
|
{
|
|
Resource resource(data_list[i]);
|
|
Verify(resource.DoesResourceExist());
|
|
}
|
|
}
|
|
}
|
|
}
|