From 310f3466a858b10bbdf47277cc31cbcb903eaca0 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Thu, 3 Jun 2010 01:29:43 +0000 Subject: [PATCH] # Hotloading of actor XML files. Stop ignoring actor XML animation speeds. Add decentralised registration of hotloaders. Move player ID storage into CModel, to simplify CUnit. Remove obsolete unit ID allocation code. Remove some material junk. This was SVN commit r7605. --- source/graphics/GameView.cpp | 2 +- source/graphics/MapReader.cpp | 23 ------ source/graphics/Material.cpp | 59 +------------ source/graphics/Material.h | 36 ++------ source/graphics/MeshManager.cpp | 10 +-- source/graphics/Model.cpp | 24 ++++-- source/graphics/Model.h | 7 +- source/graphics/ObjectBase.cpp | 24 +++--- source/graphics/ObjectBase.h | 22 +++-- source/graphics/ObjectEntry.cpp | 4 +- source/graphics/ObjectManager.cpp | 60 ++++++++------ source/graphics/ObjectManager.h | 24 ++++-- source/graphics/Unit.cpp | 12 +-- source/graphics/Unit.h | 8 -- source/graphics/UnitAnimation.cpp | 4 + source/graphics/UnitManager.cpp | 18 +--- source/graphics/UnitManager.h | 10 +-- source/ps/Filesystem.cpp | 28 +++++-- source/ps/Filesystem.h | 18 +++- source/simulation2/Simulation2.cpp | 12 +++ .../components/CCmpProjectileManager.cpp | 2 +- .../components/CCmpVisualActor.cpp | 71 ++++++++++++---- source/simulation2/components/ICmpVisual.h | 11 ++- .../tools/atlas/GameInterface/ActorViewer.cpp | 2 +- .../GameInterface/Handlers/ObjectHandlers.cpp | 82 +++++++------------ source/tools/atlas/GameInterface/View.cpp | 5 -- source/tools/atlas/GameInterface/View.h | 2 - 27 files changed, 271 insertions(+), 309 deletions(-) diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index fe3ac1c764..de15ba8746 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -76,7 +76,7 @@ public: CGameViewImpl(CGame* game) : Game(game), ColladaManager(), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager), - ObjectManager(MeshManager, SkeletonAnimManager), + ObjectManager(MeshManager, SkeletonAnimManager, *game->GetSimulation2()), ViewCamera(), CullCamera(), LockCullCamera(false), diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index 85df102854..162e7b933a 100644 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -103,10 +103,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_, // delete all remaining non-entity units if (pUnitMan) - { pUnitMan->DeleteAll(); - pUnitMan->SetNextID(0); - } // unpack the data if (!only_xml) @@ -968,26 +965,6 @@ int CXMLReader::ReadOldEntities(XMBElement parent, double end_time) { XMBElementList entities = parent.GetChildNodes(); - // If this is the first time in ReadOldEntities, find the next free ID number - // in case we need to allocate new ones in the future - if (entity_idx == 0) - { - int maxUnitID = -1; - - XERO_ITER_EL(parent, entity) - { - debug_assert(entity.GetNodeName() == el_entity); - - XMBAttributeList attrs = entity.GetAttributes(); - utf16string uid = attrs.GetNamedItem(at_uid); - int unitId = uid.empty() ? -1 : CStr(uid).ToInt(); - maxUnitID = std::max(maxUnitID, unitId); - } - - if (m_MapReader.pUnitMan) - m_MapReader.pUnitMan->SetNextID(maxUnitID + 1); - } - while (entity_idx < entities.Count) { // all new state at this scope and below doesn't need to be diff --git a/source/graphics/Material.cpp b/source/graphics/Material.cpp index 7b07592b90..7bd560843d 100644 --- a/source/graphics/Material.cpp +++ b/source/graphics/Material.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,16 +34,6 @@ static SMaterialColor IdentityEmissive(0.0f, 0.0f, 0.0f, 1.0f); static SMaterialColor BrokenColor(0.3f, 0.3f, 0.3f, 1.0f); -bool SMaterialColor::operator==(const SMaterialColor& color) -{ - return ( - r == color.r && - g == color.g && - b == color.b && - a == color.a - ); -} - CMaterial::CMaterial() : m_Diffuse(IdentityDiffuse), m_Ambient(IdentityAmbient), @@ -54,30 +44,6 @@ CMaterial::CMaterial() m_PlayerID(PLAYER_ID_NONE), m_TextureColor(BrokenColor) { - ComputeHash(); -} - -CMaterial::CMaterial(const CMaterial& material) -{ - (*this) = material; -} - -CMaterial::~CMaterial() -{ -} - -void CMaterial::operator=(const CMaterial& material) -{ - m_Diffuse = material.m_Diffuse; - m_Ambient = material.m_Ambient; - m_Specular = material.m_Specular; - m_Emissive = material.m_Emissive; - - m_SpecularPower = material.m_SpecularPower; - m_Alpha = material.m_Alpha; - m_PlayerID = material.m_PlayerID; - m_TextureColor = material.m_TextureColor; - ComputeHash(); } bool CMaterial::operator==(const CMaterial& material) @@ -163,70 +129,47 @@ void CMaterial::SetPlayerColor(const CColor& colour) m_TextureColor = SMaterialColor(colour.r, colour.g, colour.b, colour.a); } - void CMaterial::SetTexture(const CStr& texture) { m_Texture = texture; - ComputeHash(); } void CMaterial::SetVertexProgram(const CStr& prog) { m_VertexProgram = prog; - ComputeHash(); } void CMaterial::SetFragmentProgram(const CStr& prog) { m_FragmentProgram = prog; - ComputeHash(); } void CMaterial::SetDiffuse(const SMaterialColor& color) { m_Diffuse = color; - ComputeHash(); } void CMaterial::SetAmbient(const SMaterialColor& color) { m_Ambient = color; - ComputeHash(); } void CMaterial::SetSpecular(const SMaterialColor& color) { m_Specular = color; - ComputeHash(); } void CMaterial::SetEmissive(const SMaterialColor& color) { m_Emissive = color; - ComputeHash(); } void CMaterial::SetSpecularPower(float power) { m_SpecularPower = power; - ComputeHash(); } void CMaterial::SetUsesAlpha(bool flag) { m_Alpha = flag; - ComputeHash(); -} - -void CMaterial::ComputeHash() -{ - m_Hash = - m_Diffuse.Sum() + - m_Ambient.Sum() + - m_Specular.Sum() + - m_Emissive.Sum() + - m_SpecularPower + - (float)m_Texture.GetHashCode() + - (float)m_VertexProgram.GetHashCode() + - (float)m_FragmentProgram.GetHashCode(); } diff --git a/source/graphics/Material.h b/source/graphics/Material.h index 0dc424c8e6..679edaa44f 100644 --- a/source/graphics/Material.h +++ b/source/graphics/Material.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -38,26 +38,14 @@ public: b = _b; a = _a; } - SMaterialColor(const SMaterialColor& color) + bool operator==(const SMaterialColor& color) { - r = color.r; - g = color.g; - b = color.b; - a = color.a; - } - - void operator=(const SMaterialColor& color) - { - r = color.r; - g = color.g; - b = color.b; - a = color.a; - } - bool operator==(const SMaterialColor& color); - - float Sum() - { - return (r + g + b + a); + return ( + r == color.r && + g == color.g && + b == color.b && + a == color.a + ); } }; @@ -65,12 +53,9 @@ class CMaterial { public: CMaterial(); - CMaterial(const CMaterial& material); - virtual ~CMaterial(); void Bind(); void Unbind(); - float GetHash() { return m_Hash; } const CStr& GetTexture() { return m_Texture; } const CStr& GetVertexProgram() { return m_VertexProgram; } @@ -105,13 +90,8 @@ public: void SetSpecularPower(float power); void SetUsesAlpha(bool flag); - void operator=(const CMaterial& material); bool operator==(const CMaterial& material); protected: - void ComputeHash(); - - float m_Hash; - // Various reflective color properties SMaterialColor m_Diffuse; SMaterialColor m_Ambient; diff --git a/source/graphics/MeshManager.cpp b/source/graphics/MeshManager.cpp index 67b3a08ddc..d4bee2ae11 100644 --- a/source/graphics/MeshManager.cpp +++ b/source/graphics/MeshManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,8 +25,6 @@ #include "ps/FileIo.h" // to get access to its CError #include "ps/Profile.h" -#define LOG_CATEGORY L"mesh" - // TODO: should this cache models while they're not actively in the game? // (Currently they'll probably be deleted when the reference count drops to 0, // even if it's quite possible that they'll get reloaded very soon.) @@ -49,13 +47,13 @@ CModelDefPtr CMeshManager::GetMesh(const VfsPath& pathname) if (iter != m_MeshMap.end() && !iter->second.expired()) return CModelDefPtr(iter->second); - PROFILE( "load mesh" ); + PROFILE("load mesh"); VfsPath pmdFilename = m_ColladaManager.GetLoadableFilename(name, CColladaManager::PMD); if (pmdFilename.empty()) { - LOG(CLogger::Error, LOG_CATEGORY, L"Could not load mesh '%ls'", pathname.string().c_str()); + LOGERROR(L"Could not load mesh '%ls'", pathname.string().c_str()); return CModelDefPtr(); } @@ -67,7 +65,7 @@ CModelDefPtr CMeshManager::GetMesh(const VfsPath& pathname) } catch (PSERROR_File&) { - LOG(CLogger::Error, LOG_CATEGORY, L"Could not load mesh '%ls'", pathname.string().c_str()); + LOGERROR(L"Could not load mesh '%ls'", pathname.string().c_str()); return CModelDefPtr(); } } diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index f5c8fa800c..bfb1c7332e 100644 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -42,7 +42,7 @@ CModel::CModel(CSkeletonAnimManager& skeletonAnimManager) : m_Parent(NULL), m_Flags(0), m_Anim(NULL), m_AnimTime(0), m_BoneMatrices(NULL), m_InverseBindBoneMatrices(NULL), - m_PositionValid(false), m_ShadingColor(1,1,1,1), + m_PositionValid(false), m_ShadingColor(1,1,1,1), m_PlayerID((size_t)-1), m_SkeletonAnimManager(skeletonAnimManager) { } @@ -238,6 +238,8 @@ void CModel::Update(float time) { if (m_Anim && m_Anim->m_AnimDef && m_BoneMatrices) { + time *= m_Anim->m_Speed; + float oldAnimTime = m_AnimTime; // update animation time, but don't calculate bone matrices - do that (lazily) when @@ -288,7 +290,10 @@ bool CModel::NeedsNewAnim(float time) const if (m_Anim && m_Anim->m_AnimDef && m_BoneMatrices) { + time *= m_Anim->m_Speed; + float duration = m_Anim->m_AnimDef->GetDuration(); + if (m_AnimTime + time > duration) return true; } @@ -300,6 +305,8 @@ void CModel::CheckActionTriggers(float time, bool& action, bool& action2) const { if (m_Anim && m_Anim->m_AnimDef && m_BoneMatrices) { + time *= m_Anim->m_Speed; + if (m_AnimTime <= m_Anim->m_ActionPos && m_AnimTime + time > m_Anim->m_ActionPos) action = true; @@ -498,19 +505,24 @@ void CModel::SetTransform(const CMatrix3D& transform) void CModel::SetMaterial(const CMaterial &material) { m_Material = material; - if(m_Material.GetTexture().Trim(PS_TRIM_BOTH).length() > 0) - { - // [TODO: uh, shouldn't this be doing something?] - } } void CModel::SetPlayerID(size_t id) { - m_Material.SetPlayerColor(id); + m_PlayerID = id; + + if (id != (size_t)-1) + m_Material.SetPlayerColor(id); + for (std::vector::iterator it = m_Props.begin(); it != m_Props.end(); ++it) it->m_Model->SetPlayerID(id); } +size_t CModel::GetPlayerID() +{ + return m_PlayerID; +} + void CModel::SetPlayerColor(const CColor& colour) { m_Material.SetPlayerColor(colour); diff --git a/source/graphics/Model.h b/source/graphics/Model.h index e8c928d3f8..76d2cccda1 100644 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -84,9 +84,10 @@ public: void SetTexture(const CTexture& tex) { m_Texture=tex; } // set the model's material void SetMaterial(const CMaterial &material); - // set the model's player ID, recursively through props. CUnit::SetPlayerID - // should normally be used instead. + // set the model's player ID, recursively through props void SetPlayerID(size_t id); + // get the model's player ID, recursively through props; initial default is (size_t)-1 + size_t GetPlayerID(); // set the model's player colour void SetPlayerColor(const CColor& colour); // set the models mod color @@ -227,6 +228,8 @@ private: // modulating color CColor m_ShadingColor; + size_t m_PlayerID; + // manager object which can load animations for us CSkeletonAnimManager& m_SkeletonAnimManager; }; diff --git a/source/graphics/ObjectBase.cpp b/source/graphics/ObjectBase.cpp index a5464363de..b5440fa096 100644 --- a/source/graphics/ObjectBase.cpp +++ b/source/graphics/ObjectBase.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -39,19 +39,12 @@ CObjectBase::CObjectBase(CObjectManager& objectManager) m_Properties.m_FloatOnWater = false; } -bool CObjectBase::Load(const std::wstring& filename) +bool CObjectBase::Load(const VfsPath& pathname) { - m_VariantGroups.clear(); - - VfsPath pathname(VfsPath(L"art/actors/")/filename); - CXeromyces XeroFile; if (XeroFile.Load(pathname) != PSRETURN_OK) return false; - m_Name = filename; - m_ShortName = fs::basename(pathname); - // Define all the elements used in the XML file #define EL(x) int el_##x = XeroFile.GetElementID(#x) #define AT(x) int at_##x = XeroFile.GetAttributeID(#x) @@ -88,6 +81,12 @@ bool CObjectBase::Load(const std::wstring& filename) } + m_VariantGroups.clear(); + + m_Pathname = pathname; + m_ShortName = fs::basename(pathname); + + // Set up the vector> m_Variants to contain the right number // of elements, to avoid wasteful copying/reallocation later. { @@ -206,7 +205,7 @@ bool CObjectBase::Load(const std::wstring& filename) if (currentGroup->size() == 0) { - LOG(CLogger::Error, LOG_CATEGORY, L"Actor group has zero variants ('%ls')", filename.c_str()); + LOG(CLogger::Error, LOG_CATEGORY, L"Actor group has zero variants ('%ls')", pathname.string().c_str()); } ++currentGroup; @@ -228,6 +227,11 @@ bool CObjectBase::Load(const std::wstring& filename) return true; } +bool CObjectBase::Reload() +{ + return Load(m_Pathname); +} + std::vector CObjectBase::CalculateVariationKey(const std::vector >& selections) { // (TODO: see CObjectManager::FindObjectVariation for an opportunity to diff --git a/source/graphics/ObjectBase.h b/source/graphics/ObjectBase.h index d6c5df19af..9373e31ba3 100644 --- a/source/graphics/ObjectBase.h +++ b/source/graphics/ObjectBase.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -74,8 +74,8 @@ public: VfsPath texture; VfsPath model; CStr color; - std::multimap props; - std::multimap anims; + std::multimap props; + std::multimap anims; }; CObjectBase(CObjectManager& objectManager); @@ -97,10 +97,20 @@ public: // variant names. std::vector > GetVariantGroups() const; - bool Load(const std::wstring& filename); + /** + * Initialise this object by loading from the given file. + * Returns false on error. + */ + bool Load(const VfsPath& pathname); - // object name - CStrW m_Name; + /** + * Reload this object from the file that it was previously loaded from. + * Returns false on error. + */ + bool Reload(); + + // filename that this was loaded from + VfsPath m_Pathname; // short human-readable name CStrW m_ShortName; diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index 5076944b8c..f33362c018 100644 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -175,7 +175,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections m_AmmunitionModel = oe->m_Model; m_AmmunitionPoint = modeldef->FindPropPoint(ppn); if (! m_AmmunitionPoint) - LOG(CLogger::Error, LOG_CATEGORY, L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", ppn.c_str(), m_ModelName.string().c_str(), m_Base->m_Name.c_str()); + LOG(CLogger::Error, LOG_CATEGORY, L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", ppn.c_str(), m_ModelName.string().c_str(), m_Base->m_ShortName.c_str()); } else { @@ -187,7 +187,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections propmodel->SetAnimation(oe->GetRandomAnimation("idle")); } else - LOG(CLogger::Error, LOG_CATEGORY, L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", prop.m_PropPointName.c_str(), m_ModelName.string().c_str(), m_Base->m_Name.c_str()); + LOG(CLogger::Error, LOG_CATEGORY, L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", prop.m_PropPointName.c_str(), m_ModelName.string().c_str(), m_Base->m_ShortName.c_str()); } } diff --git a/source/graphics/ObjectManager.cpp b/source/graphics/ObjectManager.cpp index 8c82fb74d4..27d805d124 100644 --- a/source/graphics/ObjectManager.cpp +++ b/source/graphics/ObjectManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,10 +22,11 @@ #include "graphics/ObjectBase.h" #include "graphics/ObjectEntry.h" #include "ps/CLogger.h" +#include "ps/Game.h" #include "ps/Profile.h" #include "ps/Filesystem.h" - -#define LOG_CATEGORY L"graphics" +#include "simulation2/Simulation2.h" +#include "simulation2/components/ICmpVisual.h" template static void delete_pair_2nd(std::pair v) @@ -51,14 +52,22 @@ bool CObjectManager::ObjectKey::operator< (const CObjectManager::ObjectKey& a) c return ActorVariation < a.ActorVariation; } -CObjectManager::CObjectManager(CMeshManager& meshManager, CSkeletonAnimManager& skeletonAnimManager) -: m_MeshManager(meshManager), m_SkeletonAnimManager(skeletonAnimManager) +static LibError ReloadChangedFileCB(void* param, const VfsPath& path) { + return static_cast(param)->ReloadChangedFile(path); +} + +CObjectManager::CObjectManager(CMeshManager& meshManager, CSkeletonAnimManager& skeletonAnimManager, CSimulation2& simulation) +: m_MeshManager(meshManager), m_SkeletonAnimManager(skeletonAnimManager), m_Simulation(simulation) +{ + RegisterFileReloadFunc(ReloadChangedFileCB, this); } CObjectManager::~CObjectManager() { UnloadObjects(); + + UnregisterFileReloadFunc(ReloadChangedFileCB, this); } @@ -76,7 +85,9 @@ CObjectBase* CObjectManager::FindObjectBase(const wchar_t* objectname) CObjectBase* obj = new CObjectBase(*this); - if (obj->Load(objectname)) + VfsPath pathname(VfsPath(L"art/actors/")/objectname); + + if (obj->Load(pathname)) { m_ObjectBases[objectname] = obj; return obj; @@ -84,7 +95,7 @@ CObjectBase* CObjectManager::FindObjectBase(const wchar_t* objectname) else delete obj; - LOG(CLogger::Error, LOG_CATEGORY, L"CObjectManager::FindObjectBase(): Cannot find object '%ls'", objectname); + LOGERROR(L"CObjectManager::FindObjectBase(): Cannot find object '%ls'", objectname); return 0; } @@ -107,12 +118,12 @@ CObjectEntry* CObjectManager::FindObjectVariation(const wchar_t* objname, const CObjectEntry* CObjectManager::FindObjectVariation(CObjectBase* base, const std::vector >& selections) { - PROFILE( "object variation loading" ); + PROFILE("object variation loading"); // Look to see whether this particular variation has already been loaded std::vector choices = base->CalculateVariationKey(selections); - ObjectKey key (base->m_Name, choices); + ObjectKey key (base->m_Pathname.string(), choices); std::map::iterator it = m_Objects.find(key); if (it != m_Objects.end()) @@ -165,22 +176,23 @@ void CObjectManager::UnloadObjects() m_ObjectBases.clear(); } - - -static LibError GetObjectName_ThunkCb(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), uintptr_t cbData) +LibError CObjectManager::ReloadChangedFile(const VfsPath& path) { - std::vector* names = (std::vector*)cbData; - CStr name(pathname.string()); - names->push_back(name.AfterFirst("actors/")); - return INFO::CB_CONTINUE; -} + for (std::map::iterator it = m_ObjectBases.begin(); it != m_ObjectBases.end(); ++it) + { + if (it->second->m_Pathname == path) + { + it->second->Reload(); -void CObjectManager::GetAllObjectNames(std::vector& names) -{ - (void)fs_util::ForEachFile(g_VFS, L"art/actors/", GetObjectName_ThunkCb, (uintptr_t)&names, L"*.xml", fs_util::DIR_RECURSIVE); -} + // Slightly ugly hack: The graphics system doesn't preserve enough information to regenerate the + // object with all correct variations, and we don't want to waste space storing it just for the + // rare occurrence of hotloading, so we'll tell the component (which does preserve the information) + // to do the reloading itself + const std::map& cmps = m_Simulation.GetEntitiesWithInterface(IID_Visual); + for (std::map::const_iterator eit = cmps.begin(); eit != cmps.end(); ++eit) + static_cast(eit->second)->Hotload(it->first); + } + } -void CObjectManager::GetPropObjectNames(std::vector& names) -{ - (void)fs_util::ForEachFile(g_VFS, L"art/actors/props/", GetObjectName_ThunkCb, (uintptr_t)&names, L"*.xml", fs_util::DIR_RECURSIVE); + return INFO::OK; } diff --git a/source/graphics/ObjectManager.h b/source/graphics/ObjectManager.h index 9c03aade11..0391b061e4 100644 --- a/source/graphics/ObjectManager.h +++ b/source/graphics/ObjectManager.h @@ -21,7 +21,9 @@ #include #include #include + #include "ps/CStr.h" +#include "lib/file/vfs/vfs_path.h" class CEntityTemplate; class CMatrix3D; @@ -29,6 +31,7 @@ class CMeshManager; class CObjectBase; class CObjectEntry; class CSkeletonAnimManager; +class CSimulation2; /////////////////////////////////////////////////////////////////////////////////////////// // CObjectManager: manager class for all possible actor types @@ -36,21 +39,23 @@ class CObjectManager { NONCOPYABLE(CObjectManager); public: + // Unique identifier of an actor variation struct ObjectKey { - ObjectKey(const CStr& name, const std::vector& var) + ObjectKey(const CStrW& name, const std::vector& var) : ActorName(name), ActorVariation(var) {} - CStr ActorName; - std::vector ActorVariation; - bool operator< (const CObjectManager::ObjectKey& a) const; + + private: + CStrW ActorName; + std::vector ActorVariation; }; public: // constructor, destructor - CObjectManager(CMeshManager& meshManager, CSkeletonAnimManager& skeletonAnimManager); + CObjectManager(CMeshManager& meshManager, CSkeletonAnimManager& skeletonAnimManager, CSimulation2& simulation); ~CObjectManager(); // Provide access to the manager classes for meshes and animations - they're @@ -69,13 +74,16 @@ public: CObjectEntry* FindObjectVariation(const wchar_t* objname, const std::vector >& selections); CObjectEntry* FindObjectVariation(CObjectBase* base, const std::vector >& selections); - // Get all names, quite slowly. (Intended only for Atlas.) - static void GetAllObjectNames(std::vector& names); - static void GetPropObjectNames(std::vector& names); + /** + * Reload any scripts that were loaded from the given filename. + * (This is used to implement hotloading.) + */ + LibError ReloadChangedFile(const VfsPath& path); private: CMeshManager& m_MeshManager; CSkeletonAnimManager& m_SkeletonAnimManager; + CSimulation2& m_Simulation; std::map m_Objects; std::map m_ObjectBases; diff --git a/source/graphics/Unit.cpp b/source/graphics/Unit.cpp index 5fdd9c5496..3ab78e7250 100644 --- a/source/graphics/Unit.cpp +++ b/source/graphics/Unit.cpp @@ -32,7 +32,7 @@ CUnit::CUnit(CObjectEntry* object, CEntity* entity, CObjectManager& objectManager, const std::set& actorSelections) : m_Object(object), m_Model(object->m_Model->Clone()), - m_ID(invalidUnitId), m_ActorSelections(actorSelections), m_PlayerID(invalidPlayerId), + m_ID(invalidUnitId), m_ActorSelections(actorSelections), m_ObjectManager(objectManager) { m_Animation = new CUnitAnimation(*this); @@ -174,13 +174,6 @@ void CUnit::UpdateModel(float frameTime) m_Animation->Update(frameTime*1000.0f); } - -void CUnit::SetPlayerID(size_t id) -{ - m_PlayerID = id; - m_Model->SetPlayerID(m_PlayerID); -} - void CUnit::SetEntitySelection(const CStr& selection) { CStr selection_lc = selection.LowerCase(); @@ -218,8 +211,7 @@ void CUnit::ReloadObject() // Copy the old instance-specific settings from the old model to the new instance newModel->SetTransform(m_Model->GetTransform()); - if (m_PlayerID != invalidPlayerId) - newModel->SetPlayerID(m_PlayerID); + newModel->SetPlayerID(m_Model->GetPlayerID()); newModel->CopyAnimationFrom(m_Model); delete m_Model; diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h index ac5c87445d..ab8c3deb9b 100644 --- a/source/graphics/Unit.h +++ b/source/graphics/Unit.h @@ -90,12 +90,6 @@ public: // matching 'name'. bool IsPlayingAnimation(const CStr& name); - // Set player ID of this unit (and the attached entity and actor) - void SetPlayerID(size_t id); - - // Get player ID of this unit - size_t GetPlayerID() { return m_PlayerID; } - // Most units have a hopefully-unique ID number, so they can be referred to // persistently despite saving/loading maps. Default for new units is -1; should // usually be set to CUnitManager::GetNewID() after creation. @@ -111,8 +105,6 @@ private: CObjectEntry* m_Object; // object model representation; never NULL CModel* m_Model; - // player id of this unit (only read for graphical effects), or ~0 if unspecified - size_t m_PlayerID; CUnitAnimation* m_Animation; diff --git a/source/graphics/UnitAnimation.cpp b/source/graphics/UnitAnimation.cpp index 66776239d3..aa0f6f4573 100644 --- a/source/graphics/UnitAnimation.cpp +++ b/source/graphics/UnitAnimation.cpp @@ -75,6 +75,10 @@ void CUnitAnimation::SetAnimationSync(float actionTime, float repeatTime) // Set the speed so it loops once in repeatTime float speed = duration / repeatTime; + // Compensate for the animation's scale factor + if (model.m_Anim->m_Speed) + speed /= model.m_Anim->m_Speed; + // Need to offset so that start+actionTime*speed = ActionPos float start = model.m_Anim->m_ActionPos - actionTime*speed; // Wrap it so that it's within the animation diff --git a/source/graphics/UnitManager.cpp b/source/graphics/UnitManager.cpp index 6ca5e8ab51..3de155fd0f 100644 --- a/source/graphics/UnitManager.cpp +++ b/source/graphics/UnitManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,7 +36,6 @@ /////////////////////////////////////////////////////////////////////////////// // CUnitManager constructor CUnitManager::CUnitManager() -: m_NextID(0) { } @@ -135,18 +134,3 @@ CUnit* CUnitManager::CreateUnit(const CStrW& actorName, CEntity* entity, const s AddUnit(unit); return unit; } - -/////////////////////////////////////////////////////////////////////////////// -// FindByID -// TODO: this is hopelessly inefficient -CUnit* CUnitManager::FindByID(size_t id) const -{ - if (id == invalidUnitId) - return NULL; - - for (size_t i = 0; i < m_Units.size(); ++i) - if (m_Units[i]->GetID() == id) - return m_Units[i]; - - return NULL; -} diff --git a/source/graphics/UnitManager.h b/source/graphics/UnitManager.h index 98e65ba9f1..b0e4f15662 100644 --- a/source/graphics/UnitManager.h +++ b/source/graphics/UnitManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -60,19 +60,11 @@ public: // return the closest unit, or null if everything missed CUnit* PickUnit(const CVector3D& origin, const CVector3D& dir, bool entitiesOnly) const; - CUnit* FindByID(size_t id) const; - - size_t GetNewID() { return m_NextID++; } - - void SetNextID(size_t n) { m_NextID = n; } - void SetObjectManager(CObjectManager& objectManager) { m_ObjectManager = &objectManager; } private: // list of all known units std::vector m_Units; - // next ID number to be assigned to a unit created in the editor - size_t m_NextID; // graphical object manager; may be NULL if not set up CObjectManager* m_ObjectManager; }; diff --git a/source/ps/Filesystem.cpp b/source/ps/Filesystem.cpp index e24003808f..ac62115465 100644 --- a/source/ps/Filesystem.cpp +++ b/source/ps/Filesystem.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,22 +20,29 @@ #include "gui/GUIManager.h" #include "ps/CLogger.h" -#include "ps/Game.h" -#include "simulation2/Simulation2.h" #include "lib/res/h_mgr.h" // h_reload #include "lib/sysdep/dir_watch.h" -#define LOG_CATEGORY L"file" - PIVFS g_VFS; +static std::vector > g_ReloadFuncs; + bool FileExists(const VfsPath& pathname) { return g_VFS->GetFileInfo(pathname, 0) == INFO::OK; } +void RegisterFileReloadFunc(FileReloadFunc func, void* obj) +{ + g_ReloadFuncs.push_back(std::make_pair(func, obj)); +} + +void UnregisterFileReloadFunc(FileReloadFunc func, void* obj) +{ + g_ReloadFuncs.erase(std::remove(g_ReloadFuncs.begin(), g_ReloadFuncs.end(), std::make_pair(func, obj))); +} // try to skip unnecessary work by ignoring uninteresting notifications. static bool CanIgnore(const DirWatchNotification& notification) @@ -69,9 +76,14 @@ LibError ReloadChangedFiles() VfsPath pathname; RETURN_ERR(g_VFS->GetVirtualPath(notifications[i].Pathname(), pathname)); RETURN_ERR(g_VFS->Invalidate(pathname)); + + // Tell each hotloadable system about this file change: + RETURN_ERR(g_GUI->ReloadChangedFiles(pathname)); - if (g_Game && g_Game->GetSimulation2()) - RETURN_ERR(g_Game->GetSimulation2()->ReloadChangedFile(pathname)); + + for (size_t j = 0; j < g_ReloadFuncs.size(); ++j) + g_ReloadFuncs[j].first(g_ReloadFuncs[j].second, pathname); + RETURN_ERR(h_reload(pathname)); } } @@ -99,7 +111,7 @@ PSRETURN CVFSFile::Load(const VfsPath& filename) LibError ret = g_VFS->LoadFile(filename, m_Buffer, m_BufferSize); if (ret != INFO::OK) { - LOG(CLogger::Error, LOG_CATEGORY, L"CVFSFile: file %ls couldn't be opened (vfs_load: %ld)", filename.string().c_str(), ret); + LOGERROR(L"CVFSFile: file %ls couldn't be opened (vfs_load: %ld)", filename.string().c_str(), ret); return PSRETURN_CVFSFile_LoadFailed; } diff --git a/source/ps/Filesystem.h b/source/ps/Filesystem.h index 31a0928e4f..5af1f4b233 100644 --- a/source/ps/Filesystem.h +++ b/source/ps/Filesystem.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,6 +32,22 @@ extern PIVFS g_VFS; extern bool FileExists(const VfsPath& pathname); +/** + * callback function type for file change notifications + */ +typedef LibError (*FileReloadFunc)(void* param, const VfsPath& path); + +/** + * register a callback function to be called by ReloadChangedFiles + */ +void RegisterFileReloadFunc(FileReloadFunc func, void* obj); + +/** + * delete a callback function registered with RegisterFileReloadFunc + * (removes any with the same func and obj) + */ +void UnregisterFileReloadFunc(FileReloadFunc func, void* obj); + /** * poll for directory change notifications and reload all affected files. * must be called regularly (e.g. once a frame), else notifications diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index a7ab135407..85dade6027 100644 --- a/source/simulation2/Simulation2.cpp +++ b/source/simulation2/Simulation2.cpp @@ -52,11 +52,18 @@ public: m_SimContext.m_Terrain = terrain; m_ComponentManager.LoadComponentTypes(); + RegisterFileReloadFunc(ReloadChangedFileCB, this); + // m_EnableOOSLog = true; // TODO: this should be a command-line flag or similar // (can't call ResetState here since the scripts haven't been loaded yet) } + ~CSimulation2Impl() + { + UnregisterFileReloadFunc(ReloadChangedFileCB, this); + } + CParamNode LoadXML(const std::wstring& name) { CParamNode ret; @@ -112,6 +119,11 @@ public: bool LoadScripts(const VfsPath& path); LibError ReloadChangedFile(const VfsPath& path); + static LibError ReloadChangedFileCB(void* param, const VfsPath& path) + { + return static_cast(param)->ReloadChangedFile(path); + } + bool Update(int turnLength, const std::vector& commands); void Interpolate(float frameLength, float frameOffset); diff --git a/source/simulation2/components/CCmpProjectileManager.cpp b/source/simulation2/components/CCmpProjectileManager.cpp index 1b733b4c41..1afb98bebc 100644 --- a/source/simulation2/components/CCmpProjectileManager.cpp +++ b/source/simulation2/components/CCmpProjectileManager.cpp @@ -136,7 +136,7 @@ void CCmpProjectileManager::LaunchProjectile(entity_id_t source, CFixedVector3D std::wstring name = sourceVisual->GetProjectileActor(); if (name.empty()) { - LOGERROR(L"Unit with actor '%ls' launched a projectile but has no actor on 'projectile' attachpoint", sourceVisual->GetActor().c_str()); + LOGERROR(L"Unit with actor '%ls' launched a projectile but has no actor on 'projectile' attachpoint", sourceVisual->GetActorShortName().c_str()); return; } diff --git a/source/simulation2/components/CCmpVisualActor.cpp b/source/simulation2/components/CCmpVisualActor.cpp index a60ed0e232..4b923ae0e9 100644 --- a/source/simulation2/components/CCmpVisualActor.cpp +++ b/source/simulation2/components/CCmpVisualActor.cpp @@ -47,6 +47,7 @@ public: DEFAULT_COMPONENT_ALLOCATOR(VisualActor) + std::wstring m_ActorName; CUnit* m_Unit; // Current animation state @@ -54,6 +55,9 @@ public: bool m_AnimOnce; float m_AnimSpeed; std::wstring m_SoundGroup; + float m_AnimDesync; + + float m_AnimSyncRepeatTime; // 0.0 if not synced CCmpVisualActor() : m_Unit(NULL) @@ -93,23 +97,22 @@ public: // TODO: we should do some fancy animation of under-construction buildings rising from the ground, // but for now we'll just use the foundation actor and ignore the normal one - std::wstring name; if (paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk()) - name = paramNode.GetChild("FoundationActor").ToString(); + m_ActorName = paramNode.GetChild("FoundationActor").ToString(); else - name = paramNode.GetChild("Actor").ToString(); + m_ActorName = paramNode.GetChild("Actor").ToString(); std::set selections; - m_Unit = context.GetUnitManager().CreateUnit(name, NULL, selections); + m_Unit = context.GetUnitManager().CreateUnit(m_ActorName, NULL, selections); if (!m_Unit) { // The error will have already been logged return; } - SelectAnimation("idle", false, 0.f, L""); + m_Unit->SetID(GetEntityId()); - m_Unit->SetID(GetEntityId()); // TODO: is it safe to be using entity IDs for unit IDs? + SelectAnimation("idle", false, 0.f, L""); } virtual void Deinit(const CSimContext& context) @@ -127,10 +130,7 @@ public: if (serialize.IsDebug()) { - if (m_Unit == NULL) - serialize.StringASCII("actor", "[none]", 0, 256); - else - serialize.String("actor", m_Unit->GetObject().m_Base->m_Name, 0, 256); + serialize.String("actor", m_ActorName, 0, 256); } // TODO: store random variation. This ought to be synchronised across saved games @@ -170,7 +170,7 @@ public: { const CMessageOwnershipChanged& msgData = static_cast (msg); if (m_Unit) - m_Unit->SetPlayerID(msgData.to); + m_Unit->GetModel().SetPlayerID(msgData.to); break; } } @@ -190,11 +190,11 @@ public: return m_Unit->GetModel().GetTransform().GetTranslation(); } - virtual std::wstring GetActor() + virtual std::wstring GetActorShortName() { if (!m_Unit) return L""; - return m_Unit->GetObject().m_Base->m_Name; + return m_Unit->GetObject().m_Base->m_ShortName; } virtual std::wstring GetProjectileActor() @@ -212,14 +212,14 @@ public: if (!isfinite(speed) || speed < 0) // JS 'undefined' converts to NaN, which causes Bad Things speed = 1.f; - float desync = 0.05f; // TODO: make this an argument - m_AnimName = name; m_AnimOnce = once; m_AnimSpeed = speed; m_SoundGroup = soundgroup; + m_AnimDesync = 0.05f; // TODO: make this an argument + m_AnimSyncRepeatTime = 0.0f; - m_Unit->SetAnimationState(name, once, speed, desync, false, soundgroup.c_str()); + m_Unit->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, false, m_SoundGroup.c_str()); } virtual void SetAnimationSync(float actiontime, float repeattime) @@ -227,7 +227,9 @@ public: if (!m_Unit) return; - m_Unit->SetAnimationSync(actiontime, repeattime); + m_AnimSyncRepeatTime = repeattime; + + m_Unit->SetAnimationSync(actiontime, m_AnimSyncRepeatTime); } virtual void SetShadingColour(fixed r, fixed g, fixed b, fixed a) @@ -238,6 +240,41 @@ public: m_Unit->GetModel().SetShadingColor(CColor(r.ToFloat(), g.ToFloat(), b.ToFloat(), a.ToFloat())); } + virtual void Hotload(const std::wstring& name) + { + if (!m_Unit) + return; + + if (name != m_ActorName) + return; + + std::set selections; + CUnit* newUnit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, NULL, selections); + + if (!newUnit) + return; + + // Save some data from the old unit + CColor shading = m_Unit->GetModel().GetShadingColor(); + size_t playerID = m_Unit->GetModel().GetPlayerID(); + + // Replace with the new unit + GetSimContext().GetUnitManager().DeleteUnit(m_Unit); + m_Unit = newUnit; + + m_Unit->SetID(GetEntityId()); + + m_Unit->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, false, m_SoundGroup.c_str()); + + // We'll lose the exact synchronisation but we should at least make sure it's going at the correct rate + if (m_AnimSyncRepeatTime != 0.0f) + m_Unit->SetAnimationSync(0.0f, m_AnimSyncRepeatTime); + + m_Unit->GetModel().SetShadingColor(shading); + + m_Unit->GetModel().SetPlayerID(playerID); + } + private: void Interpolate(const CSimContext& context, float frameTime, float frameOffset); void RenderSubmit(const CSimContext& context, SceneCollector& collector, const CFrustum& frustum, bool culling); diff --git a/source/simulation2/components/ICmpVisual.h b/source/simulation2/components/ICmpVisual.h index 3a9c0fc577..e493906fc4 100644 --- a/source/simulation2/components/ICmpVisual.h +++ b/source/simulation2/components/ICmpVisual.h @@ -42,10 +42,10 @@ public: virtual CVector3D GetPosition() = 0; /** - * Return the filename of the actor that's being displayed, or the empty string on error. + * Return the short name of the actor that's being displayed, or the empty string on error. * (Not safe for use in simulation code.) */ - virtual std::wstring GetActor() = 0; + virtual std::wstring GetActorShortName() = 0; /** * Return the filename of the actor to be used for projectiles from this unit, or the empty string if none. @@ -84,6 +84,13 @@ public: */ virtual void SetShadingColour(fixed r, fixed g, fixed b, fixed a) = 0; + /** + * Called when an actor file has been modified and reloaded dynamically. + * If this component uses the named actor file, it should regenerate its actor + * to pick up the new definitions. + */ + virtual void Hotload(const std::wstring& name) = 0; + DECLARE_INTERFACE_TYPE(Visual) }; diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp index d3dc1021d0..6d91c316bb 100644 --- a/source/tools/atlas/GameInterface/ActorViewer.cpp +++ b/source/tools/atlas/GameInterface/ActorViewer.cpp @@ -47,7 +47,7 @@ struct ActorViewerImpl : public Scene public: ActorViewerImpl() : Entity(INVALID_ENTITY), Terrain(), ColladaManager(), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager), - ObjectManager(MeshManager, SkeletonAnimManager), UnitManager(), Simulation2(&UnitManager, &Terrain) + UnitManager(), Simulation2(&UnitManager, &Terrain), ObjectManager(MeshManager, SkeletonAnimManager, Simulation2) { UnitManager.SetObjectManager(ObjectManager); } diff --git a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp index 6f62f8b86c..b44034d8e0 100644 --- a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp @@ -131,32 +131,21 @@ QUERYHANDLER(GetObjectSettings) { View* view = View::GetView(msg->view); CSimulation2* simulation = view->GetSimulation2(); - if (simulation) - { - sObjectSettings settings; - settings.player = 0; - - CmpPtr cmpOwner (*simulation, view->GetEntityId(msg->id)); - if (!cmpOwner.null()) - { - int32_t player = cmpOwner->GetOwner(); - if (player != -1) - settings.player = player; - } - - // TODO: selections - - msg->settings = settings; - - return; - } - - CUnit* unit = view->GetUnit(msg->id); - if (! unit) return; sObjectSettings settings; - settings.player = unit->GetPlayerID(); + settings.player = 0; + CmpPtr cmpOwner (*simulation, view->GetEntityId(msg->id)); + if (!cmpOwner.null()) + { + int32_t player = cmpOwner->GetOwner(); + if (player != -1) + settings.player = player; + } + + // TODO: selections + +/* // Get the unit's possible variants and selected variants std::vector > groups = unit->GetObject().m_Base->GetVariantGroups(); const std::set& selections = unit->GetActorSelections(); @@ -194,6 +183,8 @@ QUERYHANDLER(GetObjectSettings) settings.variantgroups = variantgroups; settings.selections = std::vector (selections_set.begin(), selections_set.end()); // convert set->vector +*/ + msg->settings = settings; } @@ -208,27 +199,19 @@ BEGIN_COMMAND(SetObjectSettings) View* view = View::GetView(msg->view); CSimulation2* simulation = view->GetSimulation2(); - if (simulation) - { - CmpPtr cmpOwner (*simulation, view->GetEntityId(msg->id)); - m_PlayerOld = 0; - if (!cmpOwner.null()) - { - int32_t player = cmpOwner->GetOwner(); - if (player != -1) - m_PlayerOld = player; - } - // TODO: selections - } - else + CmpPtr cmpOwner (*simulation, view->GetEntityId(msg->id)); + m_PlayerOld = 0; + if (!cmpOwner.null()) { - CUnit* unit = view->GetUnit(msg->id); - if (! unit) return; - m_PlayerOld = unit->GetPlayerID(); - m_SelectionsOld = unit->GetActorSelections(); + int32_t player = cmpOwner->GetOwner(); + if (player != -1) + m_PlayerOld = player; } + // TODO: selections +// m_SelectionsOld = unit->GetActorSelections(); + m_PlayerNew = (size_t)settings.player; std::vector selections = *settings.selections; @@ -255,22 +238,13 @@ private: { View* view = View::GetView(msg->view); CSimulation2* simulation = view->GetSimulation2(); - if (simulation) - { - CmpPtr cmpOwner (*simulation, view->GetEntityId(msg->id)); - if (!cmpOwner.null()) - cmpOwner->SetOwner(player); - // TODO: selections - return; - } + CmpPtr cmpOwner (*simulation, view->GetEntityId(msg->id)); + if (!cmpOwner.null()) + cmpOwner->SetOwner(player); - CUnit* unit = view->GetUnit(msg->id); - if (! unit) return; - - unit->SetPlayerID(player); - - unit->SetActorSelections(selections); + // TODO: selections +// unit->SetActorSelections(selections); } }; END_COMMAND(SetObjectSettings); diff --git a/source/tools/atlas/GameInterface/View.cpp b/source/tools/atlas/GameInterface/View.cpp index a159155f8d..4c232d185a 100644 --- a/source/tools/atlas/GameInterface/View.cpp +++ b/source/tools/atlas/GameInterface/View.cpp @@ -261,11 +261,6 @@ CCamera& ViewGame::GetCamera() return *g_Game->GetView()->GetCamera(); } -CUnit* ViewGame::GetUnit(AtlasMessage::ObjectID id) -{ - return g_Game->GetWorld()->GetUnitManager().FindByID(id); -} - bool ViewGame::WantsHighFramerate() { if (g_Game->GetView()->GetCinema()->IsPlaying()) diff --git a/source/tools/atlas/GameInterface/View.h b/source/tools/atlas/GameInterface/View.h index 36517bf1c1..73807f436e 100644 --- a/source/tools/atlas/GameInterface/View.h +++ b/source/tools/atlas/GameInterface/View.h @@ -40,7 +40,6 @@ public: virtual CCamera& GetCamera() = 0; virtual CSimulation2* GetSimulation2() { return NULL; } virtual entity_id_t GetEntityId(AtlasMessage::ObjectID obj) { return (entity_id_t)obj; } - virtual CUnit* GetUnit(AtlasMessage::ObjectID UNUSED(id)) { return NULL; } virtual bool WantsHighFramerate() { return false; } virtual void SetParam(const std::wstring& name, bool value); @@ -77,7 +76,6 @@ public: virtual void Update(float frameLength); virtual void Render(); virtual CCamera& GetCamera(); - virtual CUnit* GetUnit(AtlasMessage::ObjectID id); virtual CSimulation2* GetSimulation2(); virtual bool WantsHighFramerate();