Fixed #186 (problems with entity deletion in Atlas).
Maybe fixed errors from rare Atlas double-shutdown, but I don't know how to reproduce the condition. This was SVN commit r5162.
This commit is contained in:
parent
2045b3c188
commit
69404654bf
@ -21,11 +21,16 @@
|
||||
|
||||
namespace AtlasMessage {
|
||||
|
||||
static bool g_IsInitialised = false;
|
||||
static bool g_DidInitSim;
|
||||
|
||||
MESSAGEHANDLER(Init)
|
||||
{
|
||||
UNUSED2(msg);
|
||||
|
||||
// Don't do anything if we're called multiple times
|
||||
if (g_IsInitialised)
|
||||
return;
|
||||
|
||||
#if OS_LINUX
|
||||
// When using GLX (Linux), SDL has to load the GL library to find
|
||||
@ -61,6 +66,8 @@ MESSAGEHANDLER(Init)
|
||||
if(ogl_HaveExtension("WGL_EXT_swap_control"))
|
||||
pwglSwapIntervalEXT(1);
|
||||
#endif
|
||||
|
||||
g_IsInitialised = true;
|
||||
}
|
||||
|
||||
|
||||
@ -68,6 +75,10 @@ MESSAGEHANDLER(Shutdown)
|
||||
{
|
||||
UNUSED2(msg);
|
||||
|
||||
// Don't do anything if we're called multiple times
|
||||
if (! g_IsInitialised)
|
||||
return;
|
||||
|
||||
// Empty the CommandProc, to get rid of its references to entities before
|
||||
// we kill the EntityManager
|
||||
GetCommandProc().Destroy();
|
||||
@ -79,6 +90,8 @@ MESSAGEHANDLER(Shutdown)
|
||||
if (! g_DidInitSim)
|
||||
flags |= INIT_NO_SIM;
|
||||
Shutdown(flags);
|
||||
|
||||
g_IsInitialised = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "MessageHandler.h"
|
||||
#include "../CommandProc.h"
|
||||
#include "../SimState.h"
|
||||
#include "../View.h"
|
||||
|
||||
#include "graphics/GameView.h"
|
||||
@ -705,28 +706,13 @@ END_COMMAND(RotateObject)
|
||||
|
||||
BEGIN_COMMAND(DeleteObject)
|
||||
{
|
||||
CUnit* m_UnitInLimbo;
|
||||
// These two values are never both non-NULL
|
||||
std::auto_ptr<SimState::Entity> m_FrozenEntity;
|
||||
std::auto_ptr<SimState::Nonentity> m_FrozenNonentity;
|
||||
|
||||
cDeleteObject()
|
||||
: m_FrozenEntity(NULL), m_FrozenNonentity(NULL)
|
||||
{
|
||||
m_UnitInLimbo = NULL;
|
||||
}
|
||||
|
||||
~cDeleteObject()
|
||||
{
|
||||
if (m_UnitInLimbo)
|
||||
{
|
||||
if (m_UnitInLimbo->GetEntity())
|
||||
m_UnitInLimbo->GetEntity()->Kill();
|
||||
else
|
||||
delete m_UnitInLimbo;
|
||||
}
|
||||
|
||||
// TODO (IMPORTANT): this can crash when interacting with simulation
|
||||
// playing/resetting because the entity gets deleted while we still
|
||||
// think we have a reference to it. This system should probably be
|
||||
// replaced by something like SimState::Entity to safely serialise
|
||||
// units while they're in limbo.
|
||||
}
|
||||
|
||||
void Do()
|
||||
@ -741,30 +727,32 @@ BEGIN_COMMAND(DeleteObject)
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
// HACK: I don't know the proper way of undoably deleting entities...
|
||||
unit->GetEntity()->entf_set(ENTF_DESTROYED);
|
||||
|
||||
// TODO: territories don't ignore DESTROYED entities
|
||||
if (unit->GetEntity()->m_base->m_isTerritoryCentre)
|
||||
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
|
||||
m_FrozenEntity.reset(new SimState::Entity( SimState::Entity::Freeze(unit) ));
|
||||
unit->GetEntity()->Kill();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FrozenNonentity.reset(new SimState::Nonentity( SimState::Nonentity::Freeze(unit) ));
|
||||
GetUnitManager().RemoveUnit(unit);
|
||||
}
|
||||
|
||||
GetUnitManager().RemoveUnit(unit);
|
||||
m_UnitInLimbo = unit;
|
||||
}
|
||||
|
||||
void Undo()
|
||||
{
|
||||
if (m_UnitInLimbo->GetEntity())
|
||||
if (m_FrozenEntity.get())
|
||||
{
|
||||
m_UnitInLimbo->GetEntity()->entf_clear(ENTF_DESTROYED);
|
||||
m_FrozenEntity->Thaw();
|
||||
|
||||
// XXXif (m_UnitInLimbo->GetEntity()->m_base->m_isTerritoryCentre)
|
||||
//g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
|
||||
|
||||
if (m_UnitInLimbo->GetEntity()->m_base->m_isTerritoryCentre)
|
||||
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
|
||||
m_FrozenEntity.reset();
|
||||
}
|
||||
else if (m_FrozenNonentity.get())
|
||||
{
|
||||
m_FrozenNonentity->Thaw();
|
||||
m_FrozenNonentity.reset();
|
||||
}
|
||||
|
||||
GetUnitManager().AddUnit(m_UnitInLimbo);
|
||||
m_UnitInLimbo = NULL;
|
||||
}
|
||||
};
|
||||
END_COMMAND(DeleteObject)
|
||||
|
136
source/tools/atlas/GameInterface/SimState.cpp
Normal file
136
source/tools/atlas/GameInterface/SimState.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "SimState.h"
|
||||
|
||||
#include "graphics/Model.h"
|
||||
#include "graphics/ObjectBase.h"
|
||||
#include "graphics/ObjectEntry.h"
|
||||
#include "graphics/Unit.h"
|
||||
#include "graphics/UnitManager.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/Player.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/World.h"
|
||||
#include "simulation/Entity.h"
|
||||
#include "simulation/EntityTemplate.h"
|
||||
#include "simulation/EntityTemplateCollection.h"
|
||||
#include "simulation/EntityManager.h"
|
||||
#include "simulation/Projectile.h"
|
||||
|
||||
SimState::Entity SimState::Entity::Freeze(CUnit* unit)
|
||||
{
|
||||
CEntity* entity = unit->GetEntity();
|
||||
debug_assert(entity);
|
||||
|
||||
Entity e;
|
||||
e.templateName = entity->m_base->m_Tag;
|
||||
e.unitID = unit->GetID();
|
||||
e.selections = unit->GetActorSelections();
|
||||
e.playerID = entity->GetPlayer()->GetPlayerID();
|
||||
e.position = entity->m_position;
|
||||
e.angle = entity->m_orientation.Y;
|
||||
return e;
|
||||
}
|
||||
|
||||
void SimState::Entity::Thaw()
|
||||
{
|
||||
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate(templateName, g_Game->GetPlayer(playerID));
|
||||
if (! base)
|
||||
return;
|
||||
|
||||
HEntity ent = g_EntityManager.Create(base, position, angle, selections);
|
||||
if (! ent)
|
||||
return;
|
||||
|
||||
ent->m_actor->SetPlayerID(playerID);
|
||||
ent->m_actor->SetID(unitID);
|
||||
ent->Initialize();
|
||||
}
|
||||
|
||||
SimState::Nonentity SimState::Nonentity::Freeze(CUnit* unit)
|
||||
{
|
||||
Nonentity n;
|
||||
n.actorName = unit->GetObject()->m_Base->m_Name;
|
||||
n.unitID = unit->GetID();
|
||||
n.selections = unit->GetActorSelections();
|
||||
n.position = unit->GetModel()->GetTransform().GetTranslation();
|
||||
CVector3D orient = unit->GetModel()->GetTransform().GetIn();
|
||||
n.angle = atan2(-orient.X, -orient.Z);
|
||||
return n;
|
||||
}
|
||||
|
||||
void SimState::Nonentity::Thaw()
|
||||
{
|
||||
CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager();
|
||||
CUnit* unit = unitMan.CreateUnit(actorName, NULL, selections);
|
||||
if (! unit)
|
||||
return;
|
||||
CMatrix3D m;
|
||||
m.SetYRotation(angle + PI);
|
||||
m.Translate(position);
|
||||
unit->GetModel()->SetTransform(m);
|
||||
|
||||
unit->SetID(unitID);
|
||||
}
|
||||
|
||||
SimState* SimState::Freeze(bool onlyEntities)
|
||||
{
|
||||
SimState* simState = new SimState();
|
||||
simState->onlyEntities = onlyEntities;
|
||||
|
||||
CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager();
|
||||
const std::vector<CUnit*>& units = unitMan.GetUnits();
|
||||
|
||||
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit)
|
||||
{
|
||||
// Ignore objects that aren't entities
|
||||
if (! (*unit)->GetEntity())
|
||||
continue;
|
||||
|
||||
Entity e = Entity::Freeze(*unit);
|
||||
simState->entities.push_back(e);
|
||||
}
|
||||
|
||||
if (! onlyEntities)
|
||||
{
|
||||
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit)
|
||||
{
|
||||
// Ignore objects that are entities
|
||||
if ((*unit)->GetEntity())
|
||||
continue;
|
||||
|
||||
Nonentity n = Nonentity::Freeze(*unit);
|
||||
simState->nonentities.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
return simState;
|
||||
}
|
||||
|
||||
void SimState::Thaw()
|
||||
{
|
||||
CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager();
|
||||
|
||||
// delete all existing entities
|
||||
g_Game;
|
||||
g_Game->GetWorld();
|
||||
g_Game->GetWorld()->GetProjectileManager();
|
||||
g_Game->GetWorld()->GetProjectileManager().DeleteAll();
|
||||
g_EntityManager.DeleteAll();
|
||||
|
||||
if (! onlyEntities)
|
||||
{
|
||||
// delete all remaining non-entity units
|
||||
unitMan.DeleteAll();
|
||||
// don't reset the unitID counter - there's no need, since it'll work alright anyway
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < entities.size(); ++i)
|
||||
entities[i].Thaw();
|
||||
|
||||
g_EntityManager.InitializeAll();
|
||||
|
||||
if (! onlyEntities)
|
||||
for (size_t i = 0; i < nonentities.size(); ++i)
|
||||
nonentities[i].Thaw();
|
||||
}
|
46
source/tools/atlas/GameInterface/SimState.h
Normal file
46
source/tools/atlas/GameInterface/SimState.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef SIMSTATE_INCLUDED
|
||||
#define SIMSTATE_INCLUDED
|
||||
|
||||
class CUnit;
|
||||
#include "maths/Vector3D.h"
|
||||
|
||||
class SimState
|
||||
{
|
||||
public:
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
static Entity Freeze(CUnit* unit);
|
||||
void Thaw();
|
||||
private:
|
||||
CStrW templateName;
|
||||
int unitID;
|
||||
std::set<CStr> selections;
|
||||
int playerID;
|
||||
CVector3D position;
|
||||
float angle;
|
||||
};
|
||||
|
||||
class Nonentity
|
||||
{
|
||||
public:
|
||||
static Nonentity Freeze(CUnit* unit);
|
||||
void Thaw();
|
||||
private:
|
||||
CStrW actorName;
|
||||
int unitID;
|
||||
std::set<CStr> selections;
|
||||
CVector3D position;
|
||||
float angle;
|
||||
};
|
||||
|
||||
static SimState* Freeze(bool onlyEntities);
|
||||
void Thaw();
|
||||
|
||||
private:
|
||||
bool onlyEntities;
|
||||
std::vector<Entity> entities;
|
||||
std::vector<Nonentity> nonentities;
|
||||
};
|
||||
|
||||
#endif // SIMSTATE_INCLUDED
|
@ -5,26 +5,17 @@
|
||||
#include "ActorViewer.h"
|
||||
#include "GameLoop.h"
|
||||
#include "Messages.h"
|
||||
#include "SimState.h"
|
||||
|
||||
#include "graphics/CinemaTrack.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/Model.h"
|
||||
#include "graphics/ObjectBase.h"
|
||||
#include "graphics/ObjectEntry.h"
|
||||
#include "graphics/SColor.h"
|
||||
#include "graphics/Unit.h"
|
||||
#include "graphics/UnitManager.h"
|
||||
#include "lib/timer.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/Player.h"
|
||||
#include "ps/World.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "simulation/Entity.h"
|
||||
#include "simulation/EntityManager.h"
|
||||
#include "simulation/EntityTemplate.h"
|
||||
#include "simulation/EntityTemplateCollection.h"
|
||||
#include "simulation/Projectile.h"
|
||||
#include "simulation/Simulation.h"
|
||||
|
||||
extern void (*Atlas_GLSwapBuffers)(void* context);
|
||||
@ -128,32 +119,6 @@ namespace AtlasMessage
|
||||
extern void AtlasRenderSelection();
|
||||
}
|
||||
|
||||
struct SimState
|
||||
{
|
||||
struct Entity
|
||||
{
|
||||
CStrW templateName;
|
||||
int unitID;
|
||||
std::set<CStr> selections;
|
||||
int playerID;
|
||||
CVector3D position;
|
||||
float angle;
|
||||
};
|
||||
|
||||
struct Nonentity
|
||||
{
|
||||
CStrW actorName;
|
||||
int unitID;
|
||||
std::set<CStr> selections;
|
||||
CVector3D position;
|
||||
float angle;
|
||||
};
|
||||
|
||||
bool onlyEntities;
|
||||
std::vector<Entity> entities;
|
||||
std::vector<Nonentity> nonentities;
|
||||
};
|
||||
|
||||
template<typename T, typename S>
|
||||
static void delete_pair_2nd(std::pair<T,S> v)
|
||||
{
|
||||
@ -254,53 +219,8 @@ void ViewGame::SetSpeedMultiplier(float speed)
|
||||
|
||||
void ViewGame::SaveState(const std::wstring& label, bool onlyEntities)
|
||||
{
|
||||
SimState* simState = new SimState();
|
||||
simState->onlyEntities = onlyEntities;
|
||||
|
||||
CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager();
|
||||
const std::vector<CUnit*>& units = unitMan.GetUnits();
|
||||
|
||||
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit)
|
||||
{
|
||||
CEntity* entity = (*unit)->GetEntity();
|
||||
|
||||
// Ignore objects that aren't entities
|
||||
if (! entity)
|
||||
continue;
|
||||
|
||||
SimState::Entity e;
|
||||
e.templateName = entity->m_base->m_Tag;
|
||||
e.unitID = (*unit)->GetID();
|
||||
e.selections = (*unit)->GetActorSelections();
|
||||
e.playerID = entity->GetPlayer()->GetPlayerID();
|
||||
e.position = entity->m_position;
|
||||
e.angle = entity->m_orientation.Y;
|
||||
|
||||
simState->entities.push_back(e);
|
||||
}
|
||||
|
||||
if (! onlyEntities)
|
||||
{
|
||||
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit)
|
||||
{
|
||||
// Ignore objects that are entities
|
||||
if ((*unit)->GetEntity())
|
||||
continue;
|
||||
|
||||
SimState::Nonentity n;
|
||||
n.actorName = (*unit)->GetObject()->m_Base->m_Name;
|
||||
n.unitID = (*unit)->GetID();
|
||||
n.selections = (*unit)->GetActorSelections();
|
||||
n.position = (*unit)->GetModel()->GetTransform().GetTranslation();
|
||||
CVector3D orient = (*unit)->GetModel()->GetTransform().GetIn();
|
||||
n.angle = atan2(-orient.X, -orient.Z);
|
||||
|
||||
simState->nonentities.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
delete m_SavedStates[label]; // in case it already exists
|
||||
m_SavedStates[label] = simState;
|
||||
m_SavedStates[label] = SimState::Freeze(onlyEntities);
|
||||
}
|
||||
|
||||
void ViewGame::RestoreState(const std::wstring& label)
|
||||
@ -309,57 +229,7 @@ void ViewGame::RestoreState(const std::wstring& label)
|
||||
if (! simState)
|
||||
return;
|
||||
|
||||
CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager();
|
||||
|
||||
// delete all existing entities
|
||||
g_Game->GetWorld()->GetProjectileManager().DeleteAll();
|
||||
g_EntityManager.DeleteAll();
|
||||
|
||||
if (! simState->onlyEntities)
|
||||
{
|
||||
// delete all remaining non-entity units
|
||||
unitMan.DeleteAll();
|
||||
// don't reset the unitID counter - there's no need, since it'll work alright anyway
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < simState->entities.size(); ++i)
|
||||
{
|
||||
SimState::Entity& e = simState->entities[i];
|
||||
|
||||
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate(e.templateName, g_Game->GetPlayer(e.playerID));
|
||||
if (base)
|
||||
{
|
||||
HEntity ent = g_EntityManager.Create(base, e.position, e.angle, e.selections);
|
||||
|
||||
if (ent)
|
||||
{
|
||||
ent->m_actor->SetPlayerID(e.playerID);
|
||||
ent->m_actor->SetID(e.unitID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_EntityManager.InitializeAll();
|
||||
|
||||
if (! simState->onlyEntities)
|
||||
{
|
||||
for (size_t i = 0; i < simState->nonentities.size(); ++i)
|
||||
{
|
||||
SimState::Nonentity& n = simState->nonentities[i];
|
||||
|
||||
CUnit* unit = unitMan.CreateUnit(n.actorName, NULL, n.selections);
|
||||
|
||||
if (unit)
|
||||
{
|
||||
CMatrix3D m;
|
||||
m.SetYRotation(n.angle + PI);
|
||||
m.Translate(n.position);
|
||||
unit->GetModel()->SetTransform(m);
|
||||
|
||||
unit->SetID(n.unitID);
|
||||
}
|
||||
}
|
||||
}
|
||||
simState->Thaw();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user