1
0
forked from 0ad/0ad

Added unit IDs, so Atlas can store references to units without just using pointers and without crashing.

This was SVN commit r3214.
This commit is contained in:
Ykkrosh 2005-12-09 03:15:00 +00:00
parent bd2c1d73a3
commit 2eac4af3a4
9 changed files with 116 additions and 79 deletions

View File

@ -50,6 +50,7 @@ void CMapReader::LoadMap(const char* filename, CTerrain *pTerrain_, CUnitManager
g_EntityManager.deleteAll(); g_EntityManager.deleteAll();
// delete all remaining non-entity units // delete all remaining non-entity units
pUnitMan->DeleteAll(); pUnitMan->DeleteAll();
g_UnitMan.SetNextID(0);
// unpack the data // unpack the data
RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1250); RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1250);
@ -437,7 +438,13 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
if (! ent) if (! ent)
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", TemplateName.c_str()); LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", TemplateName.c_str());
else else
{
ent->SetPlayer(g_Game->GetPlayer(PlayerID)); ent->SetPlayer(g_Game->GetPlayer(PlayerID));
// TODO: save object IDs in the map file, and load them again,
// so that triggers have a persistent identifier for objects
ent->m_actor->SetID(g_UnitMan.GetNewID());
}
} }
completed_jobs++; completed_jobs++;
@ -492,7 +499,7 @@ int CXMLReader::ReadNonEntities(XMBElement parent, double end_time)
CUnit* unit = g_UnitMan.CreateUnit(ActorName, NULL); CUnit* unit = g_UnitMan.CreateUnit(ActorName, NULL);
if (unit && unit->GetModel()) if (unit)
{ {
// Copied from CEntity::updateActorTransforms(): // Copied from CEntity::updateActorTransforms():
float s = sin(Orientation); float s = sin(Orientation);
@ -503,6 +510,10 @@ int CXMLReader::ReadNonEntities(XMBElement parent, double end_time)
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = Position.Z; m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = Position.Z;
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f; m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
unit->GetModel()->SetTransform(m); unit->GetModel()->SetTransform(m);
// TODO: save object IDs in the map file, and load them again,
// so that triggers have a persistent identifier for objects
unit->SetID(g_UnitMan.GetNewID());
} }
completed_jobs++; completed_jobs++;

View File

@ -15,10 +15,14 @@ class CUnit
{ {
public: public:
// constructor - unit invalid without a model and object // constructor - unit invalid without a model and object
CUnit(CObjectEntry* object, CModel* model) : m_Object(object), m_Model(model), m_Entity(NULL) { CUnit(CObjectEntry* object, CModel* model)
: m_Object(object), m_Model(model), m_Entity(NULL), m_ID(-1)
{
debug_assert(object && model); debug_assert(object && model);
} }
CUnit(CObjectEntry* object, CModel* model, CEntity* entity) : m_Object(object), m_Model(model), m_Entity(entity) { CUnit(CObjectEntry* object, CModel* model, CEntity* entity)
: m_Object(object), m_Model(model), m_Entity(entity), m_ID(-1)
{
debug_assert(object && model); debug_assert(object && model);
} }
@ -26,11 +30,11 @@ public:
~CUnit(); ~CUnit();
// get unit's template object // get unit's template object; never NULL
CObjectEntry* GetObject() { return m_Object; } CObjectEntry* GetObject() { return m_Object; }
// get unit's model data // get unit's model data; never NULL
CModel* GetModel() { return m_Model; } CModel* GetModel() { return m_Model; }
// get actor's entity // get actor's entity; can be NULL
CEntity* GetEntity() { return m_Entity; } CEntity* GetEntity() { return m_Entity; }
// Put here as it conveniently references both the model and the ObjectEntry // Put here as it conveniently references both the model and the ObjectEntry
@ -49,6 +53,9 @@ public:
// matchin 'name'. // matchin 'name'.
bool IsPlayingAnimation(const CStr8& name); bool IsPlayingAnimation(const CStr8& name);
int GetID() const { return m_ID; }
void SetID(int id) { m_ID = id; }
private: private:
// object from which unit was created // object from which unit was created
CObjectEntry* m_Object; CObjectEntry* m_Object;
@ -56,6 +63,9 @@ private:
CModel* m_Model; CModel* m_Model;
// the entity that this actor represents, if any // the entity that this actor represents, if any
CEntity* m_Entity; CEntity* m_Entity;
// unique (per CGame) ID number for units created in the editor, as a
// permanent way of referencing them. -1 for non-editor units.
int m_ID;
}; };
#endif #endif

View File

@ -24,6 +24,7 @@ extern CConsole* g_Console;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// CUnitManager constructor // CUnitManager constructor
CUnitManager::CUnitManager() CUnitManager::CUnitManager()
: m_NextID(0)
{ {
} }
@ -77,36 +78,36 @@ void CUnitManager::DeleteAll()
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// PickUnit: iterate through units testing given ray against bounds of each // PickUnit: iterate through units testing given ray against bounds of each
// unit; return the closest unit, or null if everything missed // unit; return the closest unit, or null if everything missed
CUnit* CUnitManager::PickUnit(const CVector3D& origin,const CVector3D& dir) const CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir) const
{ {
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager(); CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
// closest object found so far // closest object found so far
CUnit* hit = 0; CUnit* hit = 0;
// distance to closest object found so far // distance to closest object found so far
float dist = 1.0e30f; float dist = FLT_MAX;
// closest approach offset (easier to pick small stuff in forests than standard ScEd style selection) // closest approach offset (easier to pick small stuff in forests than standard ScEd style selection)
float minrel = 1.0e30f; float minrel = FLT_MAX;
for (uint i=0;i<m_Units.size();i++) { for (uint i=0; i<m_Units.size(); i++) {
CUnit* unit=m_Units[i]; CUnit* unit = m_Units[i];
float tmin,tmax; float tmin, tmax;
if (unit->GetModel()->GetBounds().RayIntersect(origin,dir,tmin,tmax) if (unit->GetModel()->GetBounds().RayIntersect(origin, dir, tmin, tmax)
&& losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN) && losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
{ {
// Point of closest approach // Point of closest approach
CVector3D obj; CVector3D obj;
unit->GetModel()->GetBounds().GetCentre( obj ); unit->GetModel()->GetBounds().GetCentre(obj);
CVector3D delta = obj - origin; CVector3D delta = obj - origin;
float distance = delta.Dot( dir ); float distance = delta.Dot(dir);
CVector3D closest = origin + dir * distance; CVector3D closest = origin + dir * distance;
CVector3D offset = obj - closest; CVector3D offset = obj - closest;
float rel = offset.GetLength(); float rel = offset.GetLength();
if (!hit || rel < minrel ) { if (rel < minrel) {
hit=unit; hit = unit;
dist=tmin; dist = tmin;
minrel = rel; minrel = rel;
} }
} }
@ -127,3 +128,17 @@ CUnit* CUnitManager::CreateUnit(const CStr& actorName, CEntity* entity)
AddUnit(unit); AddUnit(unit);
return unit; return unit;
} }
///////////////////////////////////////////////////////////////////////////////
// FindByID
CUnit* CUnitManager::FindByID(int id) const
{
if (id < 0)
return NULL;
for (size_t i = 0; i < m_Units.size(); ++i)
if (m_Units[i]->GetID() == id)
return m_Units[i];
return NULL;
}

View File

@ -47,11 +47,19 @@ public:
// iterate through units testing given ray against bounds of each unit; // iterate through units testing given ray against bounds of each unit;
// return the closest unit, or null if everything missed // return the closest unit, or null if everything missed
CUnit* PickUnit(const CVector3D& origin,const CVector3D& dir) const; CUnit* PickUnit(const CVector3D& origin, const CVector3D& dir) const;
CUnit* FindByID(int id) const;
int GetNewID() { return m_NextID++; }
void SetNextID(int n) { m_NextID = n; }
private: private:
// list of all known units // list of all known units
std::vector<CUnit*> m_Units; std::vector<CUnit*> m_Units;
// next ID number to be assigned to a unit created in the editor
int m_NextID;
}; };
#endif #endif

View File

@ -391,6 +391,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
// Toolbar: // Toolbar:
ToolButtonBar* toolbar = new ToolButtonBar(this, ID_Toolbar); ToolButtonBar* toolbar = new ToolButtonBar(this, ID_Toolbar);
// TODO: configurable small vs large icon images
// (button label; tooltip text; image; internal tool name) // (button label; tooltip text; image; internal tool name)
toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T("")); toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""));
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject")); toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"));

View File

@ -39,12 +39,15 @@ public:
AtlasMessage::qSelectObject qry(Position(evt.GetPosition())); AtlasMessage::qSelectObject qry(Position(evt.GetPosition()));
qry.Post(); qry.Post();
obj->m_Selection.clear(); obj->m_Selection.clear();
obj->m_Selection.push_back(qry.id); if (AtlasMessage::ObjectIDIsValid(qry.id))
obj->m_dx = qry.offsetx; {
obj->m_dy = qry.offsety; obj->m_Selection.push_back(qry.id);
obj->m_dx = qry.offsetx;
obj->m_dy = qry.offsety;
SET_STATE(Dragging);
}
POST_MESSAGE(SetSelectionPreview(obj->m_Selection)); POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
ScenarioEditor::GetCommandProc().FinaliseLastCommand(); ScenarioEditor::GetCommandProc().FinaliseLastCommand();
SET_STATE(Dragging);
return true; return true;
} }
else if (evt.Dragging() && evt.RightIsDown() || evt.RightDown()) else if (evt.Dragging() && evt.RightIsDown() || evt.RightDown())

View File

@ -8,6 +8,9 @@ namespace AtlasMessage
// (Random note: Be careful not to give handler .cpp files the same name // (Random note: Be careful not to give handler .cpp files the same name
// as any other file in the project, because it makes everything very confused) // as any other file in the project, because it makes everything very confused)
// TODO: measure how long this static initialisation stuff takes, and if it's
// non-negligible then make it do as little work as possible if Atlas is not run
typedef void (*msgHandler)(IMessage*); typedef void (*msgHandler)(IMessage*);
typedef std::map<std::string, msgHandler> msgHandlers; typedef std::map<std::string, msgHandler> msgHandlers;
extern msgHandlers& GetMsgHandlers(); extern msgHandlers& GetMsgHandlers();

View File

@ -39,11 +39,13 @@ void AtlasRenderSelection()
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
for (size_t i = 0; i < g_Selection.size(); ++i) for (size_t i = 0; i < g_Selection.size(); ++i)
{ {
if (g_Selection[i]) CUnit* unit = g_UnitMan.FindByID(g_Selection[i]);
if (unit)
{ {
CUnit* unit = static_cast<CUnit*>(g_Selection[i]);
if (unit->GetEntity()) if (unit->GetEntity())
{
unit->GetEntity()->renderSelectionOutline(); unit->GetEntity()->renderSelectionOutline();
}
else else
{ {
const CBound& bound = unit->GetModel()->GetBounds(); const CBound& bound = unit->GetModel()->GetBounds();
@ -118,7 +120,7 @@ MESSAGEHANDLER(EntityPreview)
CBaseEntity* base = g_EntityTemplateCollection.getTemplate(msg->id); CBaseEntity* base = g_EntityTemplateCollection.getTemplate(msg->id);
if (base) // (ignore errors) if (base) // (ignore errors)
{ {
g_PreviewUnit = g_UnitMan.CreateUnit(base->m_actorName, 0); g_PreviewUnit = g_UnitMan.CreateUnit(base->m_actorName, NULL);
// TODO: set player (for colour) // TODO: set player (for colour)
// TODO: variations // TODO: variations
} }
@ -159,9 +161,9 @@ MESSAGEHANDLER(EntityPreview)
BEGIN_COMMAND(CreateEntity) BEGIN_COMMAND(CreateEntity)
HEntity m_Entity;
CVector3D m_Pos; CVector3D m_Pos;
float m_Angle; float m_Angle;
int m_ID;
void Do() void Do()
{ {
@ -179,6 +181,8 @@ BEGIN_COMMAND(CreateEntity)
m_Angle = d->angle; m_Angle = d->angle;
} }
m_ID = g_UnitMan.GetNewID();
Redo(); Redo();
} }
@ -195,18 +199,19 @@ BEGIN_COMMAND(CreateEntity)
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", d->id.c_str()); LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", d->id.c_str());
else else
{ {
// TODO: player ID // TODO: proper player ID
ent->SetPlayer(g_Game->GetLocalPlayer()); ent->SetPlayer(g_Game->GetLocalPlayer());
m_Entity = ent; ent->m_actor->SetID(m_ID);
} }
} }
} }
void Undo() void Undo()
{ {
m_Entity->kill(); CUnit* unit = g_UnitMan.FindByID(m_ID);
m_Entity = HEntity(); if (unit && unit->GetEntity())
unit->GetEntity()->kill();
} }
END_COMMAND(CreateEntity) END_COMMAND(CreateEntity)
@ -222,7 +227,10 @@ QUERYHANDLER(SelectObject)
CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir); CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir);
msg->id = static_cast<void*>(target); if (target)
msg->id = target->GetID();
else
msg->id = -1;
if (target) if (target)
{ {
@ -246,10 +254,8 @@ BEGIN_COMMAND(MoveObject)
void Do() void Do()
{ {
if (! d->id) CUnit* unit = g_UnitMan.FindByID(d->id);
return; if (! unit) return;
CUnit* unit = static_cast<CUnit*>(d->id);
if (unit->GetEntity()) if (unit->GetEntity())
{ {
@ -268,10 +274,8 @@ BEGIN_COMMAND(MoveObject)
void SetPos(CVector3D& pos) void SetPos(CVector3D& pos)
{ {
if (! d->id) CUnit* unit = g_UnitMan.FindByID(d->id);
return; if (! unit) return;
CUnit* unit = static_cast<CUnit*>(d->id);
if (unit->GetEntity()) if (unit->GetEntity())
{ {
@ -311,10 +315,8 @@ BEGIN_COMMAND(RotateObject)
void Do() void Do()
{ {
if (! d->id) CUnit* unit = g_UnitMan.FindByID(d->id);
return; if (! unit) return;
CUnit* unit = static_cast<CUnit*>(d->id);
if (unit->GetEntity()) if (unit->GetEntity())
{ {
@ -365,10 +367,8 @@ BEGIN_COMMAND(RotateObject)
void SetAngle(float angle, CMatrix3D& transform) void SetAngle(float angle, CMatrix3D& transform)
{ {
if (! d->id) CUnit* unit = g_UnitMan.FindByID(d->id);
return; if (! unit) return;
CUnit* unit = static_cast<CUnit*>(d->id);
if (unit->GetEntity()) if (unit->GetEntity())
{ {
@ -402,29 +402,21 @@ END_COMMAND(RotateObject)
BEGIN_COMMAND(DeleteObject) BEGIN_COMMAND(DeleteObject)
bool m_ObjectAlive; CUnit* m_UnitInLimbo;
void Construct() void Construct()
{ {
m_ObjectAlive = true; m_UnitInLimbo = NULL;
} }
void Destruct() void Destruct()
{ {
if (! m_ObjectAlive) if (m_UnitInLimbo)
{ {
if (! d->id) if (m_UnitInLimbo->GetEntity())
return; m_UnitInLimbo->GetEntity()->kill();
CUnit* unit = static_cast<CUnit*>(d->id);
if (unit->GetEntity())
unit->GetEntity()->kill();
else else
{ delete m_UnitInLimbo;
g_UnitMan.RemoveUnit(unit);
delete unit;
}
} }
} }
@ -435,33 +427,26 @@ BEGIN_COMMAND(DeleteObject)
void Redo() void Redo()
{ {
if (! d->id) CUnit* unit = g_UnitMan.FindByID(d->id);
return; if (! unit) return;
CUnit* unit = static_cast<CUnit*>(d->id);
if (unit->GetEntity()) if (unit->GetEntity())
{
// HACK: I don't know the proper way of undoably deleting entities... // HACK: I don't know the proper way of undoably deleting entities...
unit->GetEntity()->m_destroyed = true; unit->GetEntity()->m_destroyed = true;
}
g_UnitMan.RemoveUnit(unit); g_UnitMan.RemoveUnit(unit);
m_UnitInLimbo = unit;
m_ObjectAlive = false;
} }
void Undo() void Undo()
{ {
if (! d->id) if (m_UnitInLimbo->GetEntity())
return; m_UnitInLimbo->GetEntity()->m_destroyed = false;
CUnit* unit = static_cast<CUnit*>(d->id); g_UnitMan.AddUnit(m_UnitInLimbo);
m_UnitInLimbo = NULL;
if (unit->GetEntity())
unit->GetEntity()->m_destroyed = false;
g_UnitMan.AddUnit(unit);
m_ObjectAlive = true;
} }
END_COMMAND(DeleteObject) END_COMMAND(DeleteObject)

View File

@ -167,7 +167,8 @@ COMMAND(PaintTerrain, MERGE,
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
typedef void* ObjectID; typedef int ObjectID;
inline bool ObjectIDIsValid(ObjectID id) { return (id >= 0); }
QUERY(SelectObject, QUERY(SelectObject,
((Position, pos)) ((Position, pos))