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:
parent
bd2c1d73a3
commit
2eac4af3a4
@ -50,6 +50,7 @@ void CMapReader::LoadMap(const char* filename, CTerrain *pTerrain_, CUnitManager
|
||||
g_EntityManager.deleteAll();
|
||||
// delete all remaining non-entity units
|
||||
pUnitMan->DeleteAll();
|
||||
g_UnitMan.SetNextID(0);
|
||||
|
||||
// unpack the data
|
||||
RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1250);
|
||||
@ -437,7 +438,13 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
if (! ent)
|
||||
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", TemplateName.c_str());
|
||||
else
|
||||
{
|
||||
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++;
|
||||
@ -492,7 +499,7 @@ int CXMLReader::ReadNonEntities(XMBElement parent, double end_time)
|
||||
|
||||
CUnit* unit = g_UnitMan.CreateUnit(ActorName, NULL);
|
||||
|
||||
if (unit && unit->GetModel())
|
||||
if (unit)
|
||||
{
|
||||
// Copied from CEntity::updateActorTransforms():
|
||||
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._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
|
||||
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++;
|
||||
|
@ -15,10 +15,14 @@ class CUnit
|
||||
{
|
||||
public:
|
||||
// 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -26,11 +30,11 @@ public:
|
||||
~CUnit();
|
||||
|
||||
|
||||
// get unit's template object
|
||||
// get unit's template object; never NULL
|
||||
CObjectEntry* GetObject() { return m_Object; }
|
||||
// get unit's model data
|
||||
// get unit's model data; never NULL
|
||||
CModel* GetModel() { return m_Model; }
|
||||
// get actor's entity
|
||||
// get actor's entity; can be NULL
|
||||
CEntity* GetEntity() { return m_Entity; }
|
||||
|
||||
// Put here as it conveniently references both the model and the ObjectEntry
|
||||
@ -49,6 +53,9 @@ public:
|
||||
// matchin 'name'.
|
||||
bool IsPlayingAnimation(const CStr8& name);
|
||||
|
||||
int GetID() const { return m_ID; }
|
||||
void SetID(int id) { m_ID = id; }
|
||||
|
||||
private:
|
||||
// object from which unit was created
|
||||
CObjectEntry* m_Object;
|
||||
@ -56,6 +63,9 @@ private:
|
||||
CModel* m_Model;
|
||||
// the entity that this actor represents, if any
|
||||
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
|
||||
|
@ -24,6 +24,7 @@ extern CConsole* g_Console;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CUnitManager constructor
|
||||
CUnitManager::CUnitManager()
|
||||
: m_NextID(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -77,36 +78,36 @@ void CUnitManager::DeleteAll()
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PickUnit: iterate through units testing given ray against bounds of each
|
||||
// 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();
|
||||
|
||||
// closest object found so far
|
||||
CUnit* hit = 0;
|
||||
// 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)
|
||||
float minrel = 1.0e30f;
|
||||
float minrel = FLT_MAX;
|
||||
|
||||
for (uint i=0;i<m_Units.size();i++) {
|
||||
CUnit* unit=m_Units[i];
|
||||
float tmin,tmax;
|
||||
for (uint i=0; i<m_Units.size(); i++) {
|
||||
CUnit* unit = m_Units[i];
|
||||
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)
|
||||
{
|
||||
// Point of closest approach
|
||||
CVector3D obj;
|
||||
unit->GetModel()->GetBounds().GetCentre( obj );
|
||||
unit->GetModel()->GetBounds().GetCentre(obj);
|
||||
CVector3D delta = obj - origin;
|
||||
float distance = delta.Dot( dir );
|
||||
float distance = delta.Dot(dir);
|
||||
CVector3D closest = origin + dir * distance;
|
||||
CVector3D offset = obj - closest;
|
||||
|
||||
float rel = offset.GetLength();
|
||||
if (!hit || rel < minrel ) {
|
||||
hit=unit;
|
||||
dist=tmin;
|
||||
if (rel < minrel) {
|
||||
hit = unit;
|
||||
dist = tmin;
|
||||
minrel = rel;
|
||||
}
|
||||
}
|
||||
@ -127,3 +128,17 @@ CUnit* CUnitManager::CreateUnit(const CStr& actorName, CEntity* entity)
|
||||
AddUnit(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;
|
||||
}
|
||||
|
@ -47,11 +47,19 @@ public:
|
||||
|
||||
// iterate through units testing given ray against bounds of each unit;
|
||||
// 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:
|
||||
// list of all known units
|
||||
std::vector<CUnit*> m_Units;
|
||||
// next ID number to be assigned to a unit created in the editor
|
||||
int m_NextID;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -391,6 +391,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
|
||||
// Toolbar:
|
||||
|
||||
ToolButtonBar* toolbar = new ToolButtonBar(this, ID_Toolbar);
|
||||
// TODO: configurable small vs large icon images
|
||||
// (button label; tooltip text; image; internal tool name)
|
||||
toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""));
|
||||
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"));
|
||||
|
@ -39,12 +39,15 @@ public:
|
||||
AtlasMessage::qSelectObject qry(Position(evt.GetPosition()));
|
||||
qry.Post();
|
||||
obj->m_Selection.clear();
|
||||
obj->m_Selection.push_back(qry.id);
|
||||
obj->m_dx = qry.offsetx;
|
||||
obj->m_dy = qry.offsety;
|
||||
if (AtlasMessage::ObjectIDIsValid(qry.id))
|
||||
{
|
||||
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));
|
||||
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
||||
SET_STATE(Dragging);
|
||||
return true;
|
||||
}
|
||||
else if (evt.Dragging() && evt.RightIsDown() || evt.RightDown())
|
||||
|
@ -8,6 +8,9 @@ namespace AtlasMessage
|
||||
// (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)
|
||||
|
||||
// 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 std::map<std::string, msgHandler> msgHandlers;
|
||||
extern msgHandlers& GetMsgHandlers();
|
||||
|
@ -39,11 +39,13 @@ void AtlasRenderSelection()
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
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())
|
||||
{
|
||||
unit->GetEntity()->renderSelectionOutline();
|
||||
}
|
||||
else
|
||||
{
|
||||
const CBound& bound = unit->GetModel()->GetBounds();
|
||||
@ -118,7 +120,7 @@ MESSAGEHANDLER(EntityPreview)
|
||||
CBaseEntity* base = g_EntityTemplateCollection.getTemplate(msg->id);
|
||||
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: variations
|
||||
}
|
||||
@ -159,9 +161,9 @@ MESSAGEHANDLER(EntityPreview)
|
||||
|
||||
BEGIN_COMMAND(CreateEntity)
|
||||
|
||||
HEntity m_Entity;
|
||||
CVector3D m_Pos;
|
||||
float m_Angle;
|
||||
int m_ID;
|
||||
|
||||
void Do()
|
||||
{
|
||||
@ -179,6 +181,8 @@ BEGIN_COMMAND(CreateEntity)
|
||||
m_Angle = d->angle;
|
||||
}
|
||||
|
||||
m_ID = g_UnitMan.GetNewID();
|
||||
|
||||
Redo();
|
||||
}
|
||||
|
||||
@ -195,18 +199,19 @@ BEGIN_COMMAND(CreateEntity)
|
||||
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", d->id.c_str());
|
||||
else
|
||||
{
|
||||
// TODO: player ID
|
||||
// TODO: proper player ID
|
||||
ent->SetPlayer(g_Game->GetLocalPlayer());
|
||||
|
||||
m_Entity = ent;
|
||||
ent->m_actor->SetID(m_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Undo()
|
||||
{
|
||||
m_Entity->kill();
|
||||
m_Entity = HEntity();
|
||||
CUnit* unit = g_UnitMan.FindByID(m_ID);
|
||||
if (unit && unit->GetEntity())
|
||||
unit->GetEntity()->kill();
|
||||
}
|
||||
|
||||
END_COMMAND(CreateEntity)
|
||||
@ -222,7 +227,10 @@ QUERYHANDLER(SelectObject)
|
||||
|
||||
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)
|
||||
{
|
||||
@ -246,10 +254,8 @@ BEGIN_COMMAND(MoveObject)
|
||||
|
||||
void Do()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||
if (! unit) return;
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
@ -268,10 +274,8 @@ BEGIN_COMMAND(MoveObject)
|
||||
|
||||
void SetPos(CVector3D& pos)
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||
if (! unit) return;
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
@ -311,10 +315,8 @@ BEGIN_COMMAND(RotateObject)
|
||||
|
||||
void Do()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||
if (! unit) return;
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
@ -365,10 +367,8 @@ BEGIN_COMMAND(RotateObject)
|
||||
|
||||
void SetAngle(float angle, CMatrix3D& transform)
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||
if (! unit) return;
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
@ -402,29 +402,21 @@ END_COMMAND(RotateObject)
|
||||
|
||||
BEGIN_COMMAND(DeleteObject)
|
||||
|
||||
bool m_ObjectAlive;
|
||||
CUnit* m_UnitInLimbo;
|
||||
|
||||
void Construct()
|
||||
{
|
||||
m_ObjectAlive = true;
|
||||
m_UnitInLimbo = NULL;
|
||||
}
|
||||
|
||||
void Destruct()
|
||||
{
|
||||
if (! m_ObjectAlive)
|
||||
if (m_UnitInLimbo)
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
unit->GetEntity()->kill();
|
||||
if (m_UnitInLimbo->GetEntity())
|
||||
m_UnitInLimbo->GetEntity()->kill();
|
||||
else
|
||||
{
|
||||
g_UnitMan.RemoveUnit(unit);
|
||||
delete unit;
|
||||
}
|
||||
delete m_UnitInLimbo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,33 +427,26 @@ BEGIN_COMMAND(DeleteObject)
|
||||
|
||||
void Redo()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||
if (! unit) return;
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
// HACK: I don't know the proper way of undoably deleting entities...
|
||||
unit->GetEntity()->m_destroyed = true;
|
||||
}
|
||||
|
||||
g_UnitMan.RemoveUnit(unit);
|
||||
|
||||
m_ObjectAlive = false;
|
||||
m_UnitInLimbo = unit;
|
||||
}
|
||||
|
||||
void Undo()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
if (m_UnitInLimbo->GetEntity())
|
||||
m_UnitInLimbo->GetEntity()->m_destroyed = false;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
unit->GetEntity()->m_destroyed = false;
|
||||
|
||||
g_UnitMan.AddUnit(unit);
|
||||
|
||||
m_ObjectAlive = true;
|
||||
g_UnitMan.AddUnit(m_UnitInLimbo);
|
||||
m_UnitInLimbo = NULL;
|
||||
}
|
||||
|
||||
END_COMMAND(DeleteObject)
|
||||
|
@ -167,7 +167,8 @@ COMMAND(PaintTerrain, MERGE,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void* ObjectID;
|
||||
typedef int ObjectID;
|
||||
inline bool ObjectIDIsValid(ObjectID id) { return (id >= 0); }
|
||||
|
||||
QUERY(SelectObject,
|
||||
((Position, pos))
|
||||
|
Loading…
Reference in New Issue
Block a user