# Added initial support for players and population counters in new simulation system, plus various infrastructure improvements.
Merge from 22b478ffed8d. Pure scripted interface definitions. Entity creation from scripts. Improved messaging system. Messages on entity deletion. Basic player entities. Player ownership. Bug fixes. This was SVN commit r7281.
This commit is contained in:
parent
33882ab698
commit
4fed9b8242
@ -8,4 +8,4 @@ TestScript2A.prototype.GetX = function() {
|
||||
return this.x;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Test2, "TestScript2A", TestScript2A);
|
||||
Engine.RegisterComponentType(IID_Test2, "TestScript2A", TestScript2A);
|
||||
|
@ -0,0 +1 @@
|
||||
Engine.RegisterInterface("TestScriptIfc");
|
@ -0,0 +1,11 @@
|
||||
function TestScript1_AddEntity() {}
|
||||
|
||||
TestScript1_AddEntity.prototype.GetX = function()
|
||||
{
|
||||
if (Engine.AddEntity("bogus-template-name") !== 0)
|
||||
throw new Error("bogus AddEntity failed");
|
||||
|
||||
return Engine.AddEntity("test1");
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Test1, "TestScript1_AddEntity", TestScript1_AddEntity);
|
@ -0,0 +1,18 @@
|
||||
function TestScript1_Interface() {}
|
||||
|
||||
TestScript1_Interface.prototype.GetX = function()
|
||||
{
|
||||
return IID_TestScriptIfc + Engine.QueryInterface(this.entity, IID_TestScriptIfc).Method();
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Test1, "TestScript1_Interface", TestScript1_Interface);
|
||||
|
||||
|
||||
function TestScript2_Interface() {}
|
||||
|
||||
TestScript2_Interface.prototype.Method = function()
|
||||
{
|
||||
return 1000;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_TestScriptIfc, "TestScript2_Interface", TestScript2_Interface);
|
@ -10,11 +10,29 @@ TestScript1A.prototype.GetX = function() {
|
||||
|
||||
TestScript1A.prototype.OnUpdate = function(msg) {
|
||||
this.x += msg.turnLength;
|
||||
}
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Test1, "TestScript1A", TestScript1A);
|
||||
|
||||
// -------- //
|
||||
|
||||
|
||||
function TestScript1B() {}
|
||||
|
||||
TestScript1B.prototype.Init = function() {
|
||||
this.x = 100;
|
||||
};
|
||||
|
||||
TestScript1B.prototype.GetX = function() {
|
||||
return this.x;
|
||||
};
|
||||
|
||||
TestScript1B.prototype.OnGlobalUpdate = function(msg) {
|
||||
this.x += msg.turnLength;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Test1, "TestScript1B", TestScript1B);
|
||||
|
||||
|
||||
|
||||
function TestScript2A() {}
|
||||
|
||||
|
12
binaries/data/mods/public/simulation/components/Cost.js
Normal file
12
binaries/data/mods/public/simulation/components/Cost.js
Normal file
@ -0,0 +1,12 @@
|
||||
function Cost() {}
|
||||
|
||||
Cost.prototype.Init = function()
|
||||
{
|
||||
};
|
||||
|
||||
Cost.prototype.GetPopCost = function()
|
||||
{
|
||||
return +this.template.Population;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Cost, "Cost", Cost);
|
44
binaries/data/mods/public/simulation/components/Player.js
Normal file
44
binaries/data/mods/public/simulation/components/Player.js
Normal file
@ -0,0 +1,44 @@
|
||||
function Player() {}
|
||||
|
||||
Player.prototype.Init = function()
|
||||
{
|
||||
this.playerID = undefined;
|
||||
this.playerName = "Unknown";
|
||||
this.civ = "celt";
|
||||
this.popCount = 0;
|
||||
this.popLimit = 50;
|
||||
};
|
||||
|
||||
Player.prototype.SetPlayerID = function(id)
|
||||
{
|
||||
this.playerID = id;
|
||||
};
|
||||
|
||||
Player.prototype.GetPopulationCount = function()
|
||||
{
|
||||
return this.popCount;
|
||||
};
|
||||
|
||||
Player.prototype.GetPopulationLimit = function()
|
||||
{
|
||||
return this.popLimit;
|
||||
};
|
||||
|
||||
Player.prototype.OnGlobalOwnershipChanged = function(msg)
|
||||
{
|
||||
if (msg.from == this.playerID)
|
||||
{
|
||||
var cost = Engine.QueryInterface(msg.entity, IID_Cost);
|
||||
if (cost)
|
||||
this.popCount -= cost.GetPopCost();
|
||||
}
|
||||
|
||||
if (msg.to == this.playerID)
|
||||
{
|
||||
var cost = Engine.QueryInterface(msg.entity, IID_Cost);
|
||||
if (cost)
|
||||
this.popCount += cost.GetPopCost();
|
||||
}
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Player, "Player", Player);
|
@ -0,0 +1,27 @@
|
||||
function PlayerManager() {}
|
||||
|
||||
PlayerManager.prototype.Init = function()
|
||||
{
|
||||
this.playerEntities = []; // list of player entity IDs
|
||||
};
|
||||
|
||||
PlayerManager.prototype.AddPlayer = function(ent)
|
||||
{
|
||||
var id = this.playerEntities.length;
|
||||
Engine.QueryInterface(ent, IID_Player).SetPlayerID(id);
|
||||
this.playerEntities.push(ent);
|
||||
return id;
|
||||
};
|
||||
|
||||
PlayerManager.prototype.GetPlayerByID = function(id)
|
||||
{
|
||||
return this.playerEntities[id];
|
||||
// TODO: report error message if invalid id
|
||||
};
|
||||
|
||||
PlayerManager.prototype.GetNumPlayers = function()
|
||||
{
|
||||
return this.playerEntities.length;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_PlayerManager, "PlayerManager", PlayerManager);
|
@ -0,0 +1 @@
|
||||
Engine.RegisterInterface("Cost");
|
@ -1,3 +1,4 @@
|
||||
var g_NewIID = 1000; // some arbitrary not-yet-used number
|
||||
var g_ComponentTypes = {};
|
||||
var g_Components = {};
|
||||
|
||||
@ -7,14 +8,19 @@ Engine.RegisterComponentType = function(iid, name, ctor)
|
||||
{
|
||||
TS_ASSERT(!g_ComponentTypes[name]);
|
||||
g_ComponentTypes[name] = { iid: iid, ctor: ctor };
|
||||
}
|
||||
};
|
||||
|
||||
Engine.RegisterInterface = function(name)
|
||||
{
|
||||
global["IID_"+name] = g_NewIID++;
|
||||
};
|
||||
|
||||
Engine.QueryInterface = function(ent, iid)
|
||||
{
|
||||
if (g_Components[ent] && g_Components[ent][iid])
|
||||
return g_Components[ent][iid];
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO:
|
||||
// Engine.RegisterGlobal
|
||||
@ -26,7 +32,7 @@ global.AddMock = function(ent, iid, mock)
|
||||
if (!g_Components[ent])
|
||||
g_Components[ent] = {};
|
||||
g_Components[ent][iid] = mock;
|
||||
}
|
||||
};
|
||||
|
||||
global.ConstructComponent = function(ent, name, template)
|
||||
{
|
||||
@ -35,4 +41,4 @@ global.ConstructComponent = function(ent, name, template)
|
||||
cmp.template = template;
|
||||
cmp.Init();
|
||||
return cmp;
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,6 @@
|
||||
Engine.LoadComponentScript("Player.js");
|
||||
|
||||
var cmp = ConstructComponent(10, "Player");
|
||||
|
||||
TS_ASSERT_EQUALS(cmp.GetPopulationCount(), 0);
|
||||
TS_ASSERT_EQUALS(cmp.GetPopulationLimit(), 50);
|
8
binaries/data/mods/public/simulation/helpers/InitGame.js
Normal file
8
binaries/data/mods/public/simulation/helpers/InitGame.js
Normal file
@ -0,0 +1,8 @@
|
||||
function InitGame(data)
|
||||
{
|
||||
// This will be called after the map has been loaded, before the simulation has started.
|
||||
// It should initialise the game based on parameters passed from the GUI, e.g. player
|
||||
// names and colours.
|
||||
}
|
||||
|
||||
Engine.RegisterGlobal("InitGame", InitGame);
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity>
|
||||
<Player/>
|
||||
</Entity>
|
@ -5,5 +5,6 @@
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
</Position>
|
||||
<Ownership/>
|
||||
<Selectable/>
|
||||
</Entity>
|
||||
|
@ -5,5 +5,6 @@
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
</Position>
|
||||
<Ownership/>
|
||||
<MotionBallScripted/>
|
||||
</Entity>
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_entity_full">
|
||||
<UnitMotion/>
|
||||
<Cost>
|
||||
<Population>1</Population>
|
||||
</Cost>
|
||||
</Entity>
|
||||
|
@ -45,6 +45,9 @@
|
||||
#include "simulation/EntityTemplate.h"
|
||||
#include "simulation/EntityTemplateCollection.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpOwnership.h"
|
||||
#include "simulation2/components/ICmpPlayer.h"
|
||||
#include "simulation2/components/ICmpPlayerManager.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
|
||||
#define LOG_CATEGORY L"graphics"
|
||||
@ -306,6 +309,34 @@ void CXMLReader::Init(const VfsPath& xml_filename)
|
||||
total_jobs = 0;
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
total_jobs += nodes.Item(i).GetChildNodes().Count;
|
||||
|
||||
if (g_UseSimulation2)
|
||||
{
|
||||
// Find the maximum entity ID, so we can safely allocate new IDs without conflicts
|
||||
|
||||
int max_uid = SYSTEM_ENTITY;
|
||||
|
||||
XMBElement ents = nodes.GetFirstNamedItem(xmb_file.GetElementID("Entities"));
|
||||
XERO_ITER_EL(ents, ent)
|
||||
{
|
||||
utf16string uid = ent.GetAttributes().GetNamedItem(at_uid);
|
||||
max_uid = std::max(max_uid, CStr(uid).ToInt());
|
||||
}
|
||||
|
||||
// Initialise player data
|
||||
|
||||
CmpPtr<ICmpPlayerManager> cmpPlayerMan(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
||||
debug_assert(!cmpPlayerMan.null());
|
||||
|
||||
// TODO: this should be loaded from the XML instead
|
||||
size_t numPlayers = 4;
|
||||
for (size_t i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
int uid = ++max_uid;
|
||||
entity_id_t ent = g_Game->GetSimulation2()->AddEntity(L"special/player", uid);
|
||||
cmpPlayerMan->AddPlayer(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -778,6 +809,7 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
int EntityUid = CStr(uid).ToInt();
|
||||
|
||||
CStrW TemplateName;
|
||||
int PlayerID = 0;
|
||||
CFixedVector3D Position;
|
||||
CFixedVector3D Orientation;
|
||||
|
||||
@ -790,6 +822,11 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
{
|
||||
TemplateName = setting.GetText();
|
||||
}
|
||||
// <player>
|
||||
else if (element_name == el_player)
|
||||
{
|
||||
PlayerID = CStr(setting.GetText()).ToInt();
|
||||
}
|
||||
// <position>
|
||||
else if (element_name == el_position)
|
||||
{
|
||||
@ -826,9 +863,12 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
{
|
||||
cmpPosition->JumpTo(Position.X, Position.Z);
|
||||
cmpPosition->SetYRotation(Orientation.Y);
|
||||
// TODO: other components
|
||||
// TODO: other parts of the position
|
||||
}
|
||||
// TODO: load all the other data too
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwner(sim, ent);
|
||||
if (!cmpOwner.null())
|
||||
cmpOwner->SetOwner(PlayerID);
|
||||
}
|
||||
|
||||
completed_jobs++;
|
||||
@ -949,7 +989,10 @@ int CXMLReader::ReadOldEntities(XMBElement parent, double end_time)
|
||||
cmpPos->JumpTo(x, z);
|
||||
cmpPos->SetYRotation(CFixed_23_8::FromFloat(Orientation));
|
||||
}
|
||||
// TODO: load player ID too
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwner(*g_Game->GetSimulation2(), ent);
|
||||
if (!cmpOwner.null())
|
||||
cmpOwner->SetOwner(PlayerID);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "simulation/TriggerManager.h"
|
||||
#include "simulation/Entity.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpOwnership.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
|
||||
@ -294,12 +295,18 @@ void CMapWriter::WriteXML(const VfsPath& filename,
|
||||
{
|
||||
entity_id_t ent = it->first;
|
||||
|
||||
// Don't save local entities (placement previews etc)
|
||||
if (ENTITY_IS_LOCAL(ent))
|
||||
continue;
|
||||
|
||||
XML_Element("Entity");
|
||||
XML_Attribute("uid", ent);
|
||||
|
||||
XML_Setting("Template", cmpTemplateManager->GetCurrentTemplateName(ent));
|
||||
|
||||
// TODO: player id
|
||||
CmpPtr<ICmpOwnership> cmpOwner(sim, ent);
|
||||
if (!cmpOwner.null())
|
||||
XML_Setting("Player", (int)cmpOwner->GetOwner());
|
||||
|
||||
CmpPtr<ICmpPosition> cmpPosition(sim, ent);
|
||||
if (!cmpPosition.null())
|
||||
|
@ -84,9 +84,13 @@ CGame::CGame():
|
||||
|
||||
if (g_UseSimulation2)
|
||||
{
|
||||
m_Simulation2->LoadScripts(L"simulation/components/interfaces/");
|
||||
m_Simulation2->LoadScripts(L"simulation/helpers/");
|
||||
m_Simulation2->LoadScripts(L"simulation/components/");
|
||||
m_Simulation2->ResetState();
|
||||
|
||||
CScriptVal initData; // TODO: ought to get this from the GUI, somehow
|
||||
m_Simulation2->InitGame(initData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,11 +165,17 @@ std::string XMBFile::GetAttributeString(const int ID) const
|
||||
|
||||
int XMBElement::GetNodeName() const
|
||||
{
|
||||
if (m_Pointer == NULL)
|
||||
return -1;
|
||||
|
||||
return *(int*)(m_Pointer + 4); // == ElementName
|
||||
}
|
||||
|
||||
XMBElementList XMBElement::GetChildNodes() const
|
||||
{
|
||||
if (m_Pointer == NULL)
|
||||
return XMBElementList(NULL, 0);
|
||||
|
||||
return XMBElementList(
|
||||
m_Pointer + 20 + *(int*)(m_Pointer + 16), // == Children[]
|
||||
*(int*)(m_Pointer + 12) // == ChildCount
|
||||
@ -178,6 +184,9 @@ XMBElementList XMBElement::GetChildNodes() const
|
||||
|
||||
XMBAttributeList XMBElement::GetAttributes() const
|
||||
{
|
||||
if (m_Pointer == NULL)
|
||||
return XMBAttributeList(NULL, 0);
|
||||
|
||||
return XMBAttributeList(
|
||||
m_Pointer + 24 + *(int*)(m_Pointer + 20), // == Attributes[]
|
||||
*(int*)(m_Pointer + 8) // == AttributeCount
|
||||
@ -187,7 +196,7 @@ XMBAttributeList XMBElement::GetAttributes() const
|
||||
utf16string XMBElement::GetText() const
|
||||
{
|
||||
// Return empty string if there's no text
|
||||
if (*(int*)(m_Pointer + 20) == 0)
|
||||
if (m_Pointer == NULL || *(int*)(m_Pointer + 20) == 0)
|
||||
return utf16string();
|
||||
else
|
||||
return utf16string((utf16_t*)(m_Pointer + 28));
|
||||
@ -196,12 +205,31 @@ utf16string XMBElement::GetText() const
|
||||
int XMBElement::GetLineNumber() const
|
||||
{
|
||||
// Make sure there actually was some text to record the line of
|
||||
if (*(int*)(m_Pointer + 20) == 0)
|
||||
if (m_Pointer == NULL || *(int*)(m_Pointer + 20) == 0)
|
||||
return -1;
|
||||
else
|
||||
return *(int*)(m_Pointer + 24);
|
||||
}
|
||||
|
||||
XMBElement XMBElementList::GetFirstNamedItem(const int ElementName) const
|
||||
{
|
||||
const char* Pos = m_Pointer;
|
||||
|
||||
// Maybe not the cleverest algorithm, but it should be
|
||||
// fast enough with half a dozen attributes:
|
||||
for (int i = 0; i < Count; ++i)
|
||||
{
|
||||
int Length = *(int*)Pos;
|
||||
int Name = *(int*)(Pos+4);
|
||||
if (Name == ElementName)
|
||||
return XMBElement(Pos);
|
||||
Pos += Length;
|
||||
}
|
||||
|
||||
// Can't find element
|
||||
return XMBElement();
|
||||
}
|
||||
|
||||
XMBElement XMBElementList::Item(const int id)
|
||||
{
|
||||
debug_assert(id >= 0 && id < Count && "Element ID out of range");
|
||||
|
@ -166,7 +166,6 @@ private:
|
||||
class XMBElement
|
||||
{
|
||||
public:
|
||||
// janwas: default ctor needed for ReadXML
|
||||
XMBElement()
|
||||
: m_Pointer(0) {}
|
||||
|
||||
@ -189,7 +188,6 @@ private:
|
||||
class XMBElementList
|
||||
{
|
||||
public:
|
||||
// janwas: default ctor needed for ReadXML
|
||||
XMBElementList()
|
||||
: Count(0), m_Pointer(0), m_LastItemID(-2) {}
|
||||
|
||||
@ -198,6 +196,10 @@ public:
|
||||
m_Pointer(offset),
|
||||
m_LastItemID(-2) {} // use -2 because it isn't x-1 where x is a non-negative integer
|
||||
|
||||
// Get first element in list with the given name.
|
||||
// Performance is linear in the number of elements in the list.
|
||||
XMBElement GetFirstNamedItem(const int ElementName) const;
|
||||
|
||||
XMBElement Item(const int id); // returns Children[id]
|
||||
|
||||
int Count;
|
||||
@ -227,7 +229,7 @@ public:
|
||||
XMBAttributeList(const char* offset, int count)
|
||||
: Count(count), m_Pointer(offset), m_LastItemID(-2) {};
|
||||
|
||||
// Get the attribute value directly (unlike Xerces)
|
||||
// Get the attribute value directly
|
||||
utf16string GetNamedItem(const int AttributeName) const;
|
||||
|
||||
// Returns an attribute by position in the list
|
||||
|
@ -81,6 +81,30 @@ public:
|
||||
TS_ASSERT_EQUALS(CStr(attr.Value), " y ");
|
||||
}
|
||||
|
||||
void test_GetFirstNamedItem()
|
||||
{
|
||||
XMBFile xmb (parse("<test> <x>A</x> <x>B</x> <y>C</y> <z>D</z> </test>"));
|
||||
|
||||
XMBElement root = xmb.GetRoot();
|
||||
TS_ASSERT_EQUALS(root.GetChildNodes().Count, 4);
|
||||
|
||||
XMBElement x = root.GetChildNodes().GetFirstNamedItem(xmb.GetElementID("x"));
|
||||
XMBElement y = root.GetChildNodes().GetFirstNamedItem(xmb.GetElementID("y"));
|
||||
XMBElement w = root.GetChildNodes().GetFirstNamedItem(xmb.GetElementID("w"));
|
||||
|
||||
TS_ASSERT_EQUALS(x.GetNodeName(), xmb.GetElementID("x"));
|
||||
TS_ASSERT_EQUALS(CStr(x.GetText()), "A");
|
||||
|
||||
TS_ASSERT_EQUALS(y.GetNodeName(), xmb.GetElementID("y"));
|
||||
TS_ASSERT_EQUALS(CStr(y.GetText()), "C");
|
||||
|
||||
TS_ASSERT_EQUALS(w.GetNodeName(), -1);
|
||||
TS_ASSERT_EQUALS(CStr(w.GetText()), "");
|
||||
TS_ASSERT_EQUALS(w.GetLineNumber(), -1);
|
||||
TS_ASSERT_EQUALS(w.GetChildNodes().Count, 0);
|
||||
TS_ASSERT_EQUALS(w.GetAttributes().Count, 0);
|
||||
}
|
||||
|
||||
void test_doctype_ignored()
|
||||
{
|
||||
XMBFile xmb (parse("<!DOCTYPE foo SYSTEM \"file:///dev/urandom\"><foo/>"));
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define INCLUDED_MESSAGETYPES
|
||||
|
||||
#include "simulation2/system/Components.h"
|
||||
#include "simulation2/system/Entity.h"
|
||||
#include "simulation2/system/Message.h"
|
||||
|
||||
#include "maths/Fixed.h"
|
||||
@ -26,6 +27,7 @@
|
||||
#define DEFAULT_MESSAGE_IMPL(name) \
|
||||
virtual EMessageTypeId GetType() const { return MT_##name; } \
|
||||
virtual const char* GetScriptHandlerName() const { return "On" #name; } \
|
||||
virtual const char* GetScriptGlobalHandlerName() const { return "OnGlobal" #name; } \
|
||||
virtual jsval ToJSVal(ScriptInterface& scriptInterface) const; \
|
||||
static CMessage* FromJSVal(ScriptInterface&, jsval val);
|
||||
|
||||
@ -83,4 +85,37 @@ public:
|
||||
bool culling;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is sent immediately before a destroyed entity is flushed and really destroyed.
|
||||
* (That is, after CComponentManager::DestroyComponentsSoon and inside FlushDestroyedComponents).
|
||||
* The entity will still exist at the time this message is sent.
|
||||
* It's possible for this message to be sent multiple times for one entity, but all its components
|
||||
* will have been deleted after the first time.
|
||||
*/
|
||||
class CMessageDestroy : public CMessage
|
||||
{
|
||||
public:
|
||||
DEFAULT_MESSAGE_IMPL(Destroy)
|
||||
|
||||
CMessageDestroy()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CMessageOwnershipChanged : public CMessage
|
||||
{
|
||||
public:
|
||||
DEFAULT_MESSAGE_IMPL(OwnershipChanged)
|
||||
|
||||
CMessageOwnershipChanged(entity_id_t entity, int32_t from, int32_t to) :
|
||||
entity(entity), from(from), to(to)
|
||||
{
|
||||
}
|
||||
|
||||
entity_id_t entity;
|
||||
int32_t from;
|
||||
int32_t to;
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_MESSAGETYPES
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
// (can't call ResetState here since the scripts haven't been loaded yet)
|
||||
}
|
||||
|
||||
void ResetState(bool skipGui)
|
||||
void ResetState(bool skipScriptedComponents)
|
||||
{
|
||||
m_ComponentManager.ResetState();
|
||||
|
||||
@ -62,22 +62,24 @@ public:
|
||||
m_ComponentManager.AddComponent(SYSTEM_ENTITY, CID_CommandQueue, noParam);
|
||||
|
||||
// Add scripted system components:
|
||||
if (!skipGui)
|
||||
if (!skipScriptedComponents)
|
||||
{
|
||||
cid = m_ComponentManager.LookupCID("GuiInterface");
|
||||
if (cid == CID__Invalid)
|
||||
LOGERROR(L"Can't find component type GuiInterface");
|
||||
m_ComponentManager.AddComponent(SYSTEM_ENTITY, cid, noParam);
|
||||
#define LOAD_SCRIPTED_COMPONENT(name) \
|
||||
cid = m_ComponentManager.LookupCID(name); \
|
||||
if (cid == CID__Invalid) \
|
||||
LOGERROR(L"Can't find component type " name); \
|
||||
m_ComponentManager.AddComponent(SYSTEM_ENTITY, cid, noParam)
|
||||
|
||||
LOAD_SCRIPTED_COMPONENT("GuiInterface");
|
||||
LOAD_SCRIPTED_COMPONENT("PlayerManager");
|
||||
|
||||
#undef LOAD_SCRIPTED_COMPONENT
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadScripts(const VfsPath& path);
|
||||
LibError ReloadChangedFile(const VfsPath& path);
|
||||
|
||||
void AddComponent(entity_id_t ent, EComponentTypeId cid, const CParamNode& paramNode);
|
||||
|
||||
entity_id_t AddEntity(const std::wstring& templateName, entity_id_t ent);
|
||||
|
||||
void Update(float frameTime);
|
||||
void Interpolate(float frameTime);
|
||||
|
||||
@ -129,49 +131,6 @@ LibError CSimulation2Impl::ReloadChangedFile(const VfsPath& path)
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
void CSimulation2Impl::AddComponent(entity_id_t ent, EComponentTypeId cid, const CParamNode& paramNode)
|
||||
{
|
||||
m_ComponentManager.AddComponent(ent, cid, paramNode);
|
||||
}
|
||||
|
||||
entity_id_t CSimulation2Impl::AddEntity(const std::wstring& templateName, entity_id_t ent)
|
||||
{
|
||||
CmpPtr<ICmpTemplateManager> tempMan(m_SimContext, SYSTEM_ENTITY);
|
||||
debug_assert(!tempMan.null());
|
||||
|
||||
// TODO: should assert that ent doesn't exist
|
||||
|
||||
const CParamNode* tmpl = tempMan->LoadTemplate(ent, templateName, -1);
|
||||
if (!tmpl)
|
||||
return INVALID_ENTITY; // LoadTemplate will have reported the error
|
||||
|
||||
// Construct a component for each child of the root element
|
||||
const CParamNode::ChildrenMap& tmplChilds = tmpl->GetChildren();
|
||||
for (CParamNode::ChildrenMap::const_iterator it = tmplChilds.begin(); it != tmplChilds.end(); ++it)
|
||||
{
|
||||
// Ignore attributes on the root element
|
||||
if (it->first.length() && it->first[0] == '@')
|
||||
continue;
|
||||
|
||||
CComponentManager::ComponentTypeId cid = m_ComponentManager.LookupCID(it->first);
|
||||
if (cid == CID__Invalid)
|
||||
{
|
||||
LOGERROR(L"Unrecognised component type name '%hs' in entity template '%ls'", it->first.c_str(), templateName.c_str());
|
||||
return INVALID_ENTITY;
|
||||
}
|
||||
|
||||
if (!m_ComponentManager.AddComponent(ent, cid, it->second))
|
||||
{
|
||||
LOGERROR(L"Failed to construct component type name '%hs' in entity template '%ls'", it->first.c_str(), templateName.c_str());
|
||||
return INVALID_ENTITY;
|
||||
}
|
||||
|
||||
// TODO: maybe we should delete already-constructed components if one of them fails?
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
void CSimulation2Impl::Update(float frameTime)
|
||||
{
|
||||
// TODO: Use CTurnManager
|
||||
@ -189,6 +148,9 @@ void CSimulation2Impl::Update(float frameTime)
|
||||
cmpCommandQueue->ProcessCommands();
|
||||
|
||||
m_ComponentManager.BroadcastMessage(CMessageUpdate(turnLengthFixed));
|
||||
|
||||
// Clean up any entities destroyed during the simulation update
|
||||
m_ComponentManager.FlushDestroyedComponents();
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,19 +174,21 @@ CSimulation2::~CSimulation2()
|
||||
delete m;
|
||||
}
|
||||
|
||||
// Forward all method calls to the appropriate CSimulation2Impl/CComponentManager methods:
|
||||
|
||||
entity_id_t CSimulation2::AddEntity(const std::wstring& templateName)
|
||||
{
|
||||
return m->AddEntity(templateName, m->m_ComponentManager.AllocateNewEntity());
|
||||
return m->m_ComponentManager.AddEntity(templateName, m->m_ComponentManager.AllocateNewEntity());
|
||||
}
|
||||
|
||||
entity_id_t CSimulation2::AddEntity(const std::wstring& templateName, entity_id_t preferredId)
|
||||
{
|
||||
return m->AddEntity(templateName, m->m_ComponentManager.AllocateNewEntity(preferredId));
|
||||
return m->m_ComponentManager.AddEntity(templateName, m->m_ComponentManager.AllocateNewEntity(preferredId));
|
||||
}
|
||||
|
||||
entity_id_t CSimulation2::AddLocalEntity(const std::wstring& templateName)
|
||||
{
|
||||
return m->AddEntity(templateName, m->m_ComponentManager.AllocateNewLocalEntity());
|
||||
return m->m_ComponentManager.AddEntity(templateName, m->m_ComponentManager.AllocateNewLocalEntity());
|
||||
}
|
||||
|
||||
void CSimulation2::DestroyEntity(entity_id_t ent)
|
||||
@ -267,6 +231,12 @@ ScriptInterface& CSimulation2::GetScriptInterface() const
|
||||
return m->m_ComponentManager.GetScriptInterface();
|
||||
}
|
||||
|
||||
void CSimulation2::InitGame(const CScriptVal& data)
|
||||
{
|
||||
CScriptVal ret; // ignored
|
||||
GetScriptInterface().CallFunction(GetScriptInterface().GetGlobalObject(), "InitGame", data, ret);
|
||||
}
|
||||
|
||||
void CSimulation2::Update(float frameTime)
|
||||
{
|
||||
m->Update(frameTime);
|
||||
|
@ -32,6 +32,7 @@ class CTerrain;
|
||||
class IComponent;
|
||||
class ScriptInterface;
|
||||
class CMessage;
|
||||
class CScriptVal;
|
||||
|
||||
// Hopefully-temporary flag for transition to new simulation system
|
||||
extern bool g_UseSimulation2;
|
||||
@ -64,9 +65,17 @@ public:
|
||||
* Initialise (or re-initialise) the complete simulation state.
|
||||
* Must be called after LoadScripts, and must be called
|
||||
* before any methods that depend on the simulation state.
|
||||
* @param skipGui don't load the GUI interface components (this is intended for use by test cases)
|
||||
* @param skipScriptedComponents don't load the scripted system components
|
||||
* (this is intended for use by test cases that don't mount all of VFS)
|
||||
*/
|
||||
void ResetState(bool skipGui = false);
|
||||
void ResetState(bool skipScriptedComponents = false);
|
||||
|
||||
/**
|
||||
* Initialise a new game, based on some script data.
|
||||
* (This mustn't be used when e.g. loading saved games, only when starting new ones.)
|
||||
* This calls the InitGame function defined in helpers/InitGame.js.
|
||||
*/
|
||||
void InitGame(const CScriptVal& data);
|
||||
|
||||
void Update(float frameTime);
|
||||
void Interpolate(float frameTime);
|
||||
@ -88,7 +97,9 @@ public:
|
||||
|
||||
/**
|
||||
* Does the actual destruction of entities from DestroyEntity.
|
||||
* This should be called at the beginning of each frame or after an Update message.
|
||||
* This is called automatically by Update, but should also be called at other
|
||||
* times when an entity might have been deleted and should be removed from
|
||||
* any further processing (e.g. after editor UI message processing)
|
||||
*/
|
||||
void FlushDestroyedEntities();
|
||||
|
||||
|
@ -34,33 +34,50 @@ MESSAGE(TurnStart)
|
||||
MESSAGE(Update)
|
||||
MESSAGE(Interpolate) // non-deterministic (use with caution)
|
||||
MESSAGE(RenderSubmit) // non-deterministic (use with caution)
|
||||
MESSAGE(Destroy)
|
||||
MESSAGE(OwnershipChanged)
|
||||
|
||||
// TemplateManager must come before all other (non-test) components,
|
||||
// so that it is the first to be (de)serialized
|
||||
INTERFACE(TemplateManager)
|
||||
COMPONENT(TemplateManager)
|
||||
|
||||
// Special component for script component types with no native interface
|
||||
INTERFACE(UnknownScript)
|
||||
COMPONENT(UnknownScript)
|
||||
|
||||
// In alphabetical order:
|
||||
|
||||
INTERFACE(CommandQueue)
|
||||
COMPONENT(CommandQueue)
|
||||
|
||||
INTERFACE(GuiInterface)
|
||||
COMPONENT(GuiInterfaceScripted)
|
||||
|
||||
INTERFACE(Terrain)
|
||||
COMPONENT(Terrain)
|
||||
|
||||
INTERFACE(Position)
|
||||
COMPONENT(Position)
|
||||
|
||||
INTERFACE(Visual)
|
||||
COMPONENT(VisualActor)
|
||||
|
||||
INTERFACE(Motion)
|
||||
COMPONENT(MotionBall)
|
||||
COMPONENT(MotionScripted)
|
||||
|
||||
INTERFACE(UnitMotion)
|
||||
COMPONENT(UnitMotion)
|
||||
INTERFACE(Ownership)
|
||||
COMPONENT(Ownership)
|
||||
|
||||
INTERFACE(Player)
|
||||
COMPONENT(PlayerScripted)
|
||||
|
||||
INTERFACE(PlayerManager)
|
||||
COMPONENT(PlayerManagerScripted)
|
||||
|
||||
INTERFACE(Position)
|
||||
COMPONENT(Position)
|
||||
|
||||
INTERFACE(Selectable)
|
||||
COMPONENT(Selectable)
|
||||
|
||||
INTERFACE(CommandQueue)
|
||||
COMPONENT(CommandQueue)
|
||||
INTERFACE(Terrain)
|
||||
COMPONENT(Terrain)
|
||||
|
||||
INTERFACE(UnitMotion)
|
||||
COMPONENT(UnitMotion)
|
||||
|
||||
INTERFACE(Visual)
|
||||
COMPONENT(VisualActor)
|
||||
|
@ -30,7 +30,7 @@ class CCmpMotionBall : public ICmpMotion
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_MotionBall, MT_Update);
|
||||
componentManager.SubscribeToMessageType(MT_Update);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(MotionBall)
|
||||
@ -61,7 +61,7 @@ public:
|
||||
deserialize.NumberFloat_Unbounded(m_SpeedZ);
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
|
96
source/simulation2/components/CCmpOwnership.cpp
Normal file
96
source/simulation2/components/CCmpOwnership.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "simulation2/system/Component.h"
|
||||
#include "ICmpOwnership.h"
|
||||
|
||||
#include "simulation2/MessageTypes.h"
|
||||
|
||||
/**
|
||||
* Basic ICmpOwnership implementation.
|
||||
*/
|
||||
class CCmpOwnership : public ICmpOwnership
|
||||
{
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(MT_Destroy);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(Ownership)
|
||||
|
||||
const CSimContext* m_Context; // never NULL (after Init/Deserialize)
|
||||
|
||||
int32_t m_Owner;
|
||||
|
||||
virtual void Init(const CSimContext& context, const CParamNode& UNUSED(paramNode))
|
||||
{
|
||||
m_Context = &context;
|
||||
|
||||
m_Owner = -1;
|
||||
}
|
||||
|
||||
virtual void Deinit(const CSimContext& UNUSED(context))
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Serialize(ISerializer& serialize)
|
||||
{
|
||||
serialize.NumberI32_Unbounded("owner", m_Owner);
|
||||
}
|
||||
|
||||
virtual void Deserialize(const CSimContext& context, const CParamNode& UNUSED(paramNode), IDeserializer& deserialize)
|
||||
{
|
||||
m_Context = &context;
|
||||
|
||||
deserialize.NumberI32_Unbounded(m_Owner);
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
case MT_Destroy:
|
||||
{
|
||||
// Reset the owner so this entity is e.g. removed from population counts
|
||||
SetOwner(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual int32_t GetOwner()
|
||||
{
|
||||
return m_Owner;
|
||||
}
|
||||
|
||||
virtual void SetOwner(int32_t playerID)
|
||||
{
|
||||
if (playerID == m_Owner)
|
||||
return;
|
||||
|
||||
int32_t old = m_Owner;
|
||||
m_Owner = playerID;
|
||||
|
||||
CMessageOwnershipChanged msg(GetEntityId(), old, playerID);
|
||||
m_Context->GetComponentManager().PostMessage(GetEntityId(), msg);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT_TYPE(Ownership)
|
@ -37,7 +37,7 @@ class CCmpPosition : public ICmpPosition
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_Position, MT_TurnStart);
|
||||
componentManager.SubscribeToMessageType(MT_TurnStart);
|
||||
|
||||
// TODO: if this component turns out to be a performance issue, it should
|
||||
// be optimised by creating a new PositionStatic component that doesn't subscribe
|
||||
@ -284,7 +284,7 @@ public:
|
||||
return mXZ;
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
|
@ -36,8 +36,8 @@ class CCmpSelectable : public ICmpSelectable
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_Selectable, MT_Interpolate);
|
||||
componentManager.SubscribeToMessageType(CID_Selectable, MT_RenderSubmit);
|
||||
componentManager.SubscribeToMessageType(MT_Interpolate);
|
||||
componentManager.SubscribeToMessageType(MT_RenderSubmit);
|
||||
// TODO: it'd be nice if we didn't get these messages except in the rare
|
||||
// cases where we're actually drawing a selection highlight
|
||||
}
|
||||
@ -67,7 +67,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& UNUSED(context), const CMessage& UNUSED(msg))
|
||||
virtual void HandleMessage(const CSimContext& UNUSED(context), const CMessage& UNUSED(msg), bool UNUSED(global))
|
||||
{
|
||||
// TODO: should listen to entity destruction messages, to clean up m_LatestTemplates
|
||||
}
|
||||
@ -305,6 +305,7 @@ void CCmpTemplateManager::CopyPreviewSubset(CParamNode& out, const CParamNode& i
|
||||
// and safe (i.e. won't do anything that affects the synchronised simulation state), so additions
|
||||
// to this list should be carefully considered
|
||||
std::set<std::string> permittedComponentTypes;
|
||||
permittedComponentTypes.insert("Ownership");
|
||||
permittedComponentTypes.insert("Position");
|
||||
permittedComponentTypes.insert("VisualActor");
|
||||
// (This could be initialised once and reused, but it's not worth the effort)
|
||||
|
@ -28,7 +28,8 @@ class CCmpTest1A : public ICmpTest1
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_Test1A, MT_TurnStart);
|
||||
componentManager.SubscribeToMessageType(MT_TurnStart);
|
||||
componentManager.SubscribeToMessageType(MT_Interpolate);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(Test1A)
|
||||
@ -62,13 +63,16 @@ public:
|
||||
return m_x;
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
case MT_TurnStart:
|
||||
m_x += 1;
|
||||
break;
|
||||
case MT_Interpolate:
|
||||
m_x += 2;
|
||||
break;
|
||||
default:
|
||||
m_x = 0;
|
||||
break;
|
||||
@ -83,7 +87,8 @@ class CCmpTest1B : public ICmpTest1
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_Test1B, MT_Update);
|
||||
componentManager.SubscribeToMessageType(MT_Update);
|
||||
componentManager.SubscribeGloballyToMessageType(MT_Interpolate);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(Test1B)
|
||||
@ -114,13 +119,16 @@ public:
|
||||
return m_x;
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
case MT_Update:
|
||||
m_x += 10;
|
||||
break;
|
||||
case MT_Interpolate:
|
||||
m_x += 20;
|
||||
break;
|
||||
default:
|
||||
m_x = 0;
|
||||
break;
|
||||
@ -135,8 +143,8 @@ class CCmpTest2A : public ICmpTest2
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_Test2A, MT_TurnStart);
|
||||
componentManager.SubscribeToMessageType(CID_Test2A, MT_Update);
|
||||
componentManager.SubscribeToMessageType(MT_TurnStart);
|
||||
componentManager.SubscribeToMessageType(MT_Update);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(Test2A)
|
||||
@ -167,7 +175,7 @@ public:
|
||||
return m_x;
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext&, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ class CCmpUnitMotion : public ICmpUnitMotion
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_UnitMotion, MT_Update);
|
||||
componentManager.SubscribeToMessageType(MT_Update);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(UnitMotion)
|
||||
@ -72,7 +72,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
|
@ -40,8 +40,9 @@ class CCmpVisualActor : public ICmpVisual
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(CID_VisualActor, MT_Interpolate);
|
||||
componentManager.SubscribeToMessageType(CID_VisualActor, MT_RenderSubmit);
|
||||
componentManager.SubscribeToMessageType(MT_Interpolate);
|
||||
componentManager.SubscribeToMessageType(MT_RenderSubmit);
|
||||
componentManager.SubscribeToMessageType(MT_OwnershipChanged);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(VisualActor)
|
||||
@ -99,7 +100,7 @@ public:
|
||||
Init(context, paramNode);
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg)
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
@ -115,6 +116,13 @@ public:
|
||||
RenderSubmit(context, msgData.collector, msgData.frustum, msgData.culling);
|
||||
break;
|
||||
}
|
||||
case MT_OwnershipChanged:
|
||||
{
|
||||
const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg);
|
||||
if (m_Unit)
|
||||
m_Unit->SetPlayerID(msgData.to);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,6 +164,9 @@ void CCmpVisualActor::Interpolate(const CSimContext& context, float frameOffset)
|
||||
|
||||
void CCmpVisualActor::RenderSubmit(const CSimContext& UNUSED(context), SceneCollector& collector, const CFrustum& frustum, bool culling)
|
||||
{
|
||||
if (m_Unit == NULL)
|
||||
return;
|
||||
|
||||
// TODO: need to think about things like LOS here
|
||||
|
||||
CModel* model = m_Unit->GetModel();
|
||||
|
27
source/simulation2/components/ICmpOwnership.cpp
Normal file
27
source/simulation2/components/ICmpOwnership.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ICmpOwnership.h"
|
||||
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(Ownership)
|
||||
DEFINE_INTERFACE_METHOD_0("GetOwner", int32_t, ICmpOwnership, GetOwner)
|
||||
DEFINE_INTERFACE_METHOD_1("SetOwner", void, ICmpOwnership, SetOwner, int32_t)
|
||||
END_INTERFACE_WRAPPER(Ownership)
|
38
source/simulation2/components/ICmpOwnership.h
Normal file
38
source/simulation2/components/ICmpOwnership.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ICMPOWNERSHIP
|
||||
#define INCLUDED_ICMPOWNERSHIP
|
||||
|
||||
#include "simulation2/system/Interface.h"
|
||||
|
||||
/**
|
||||
* Player ownership.
|
||||
* Owner values are either a player ID (if >= 0), or unassigned (-1).
|
||||
* Sends message OwnershipChanged after it changes.
|
||||
*/
|
||||
class ICmpOwnership : public IComponent
|
||||
{
|
||||
public:
|
||||
virtual int32_t GetOwner() = 0;
|
||||
|
||||
virtual void SetOwner(int32_t playerID) = 0;
|
||||
|
||||
DECLARE_INTERFACE_TYPE(Ownership)
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPOWNERSHIP
|
39
source/simulation2/components/ICmpPlayer.cpp
Normal file
39
source/simulation2/components/ICmpPlayer.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ICmpPlayer.h"
|
||||
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
#include "simulation2/scripting/ScriptComponent.h"
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(Player)
|
||||
END_INTERFACE_WRAPPER(Player)
|
||||
|
||||
class CCmpPlayerScripted : public ICmpPlayer
|
||||
{
|
||||
public:
|
||||
DEFAULT_SCRIPT_WRAPPER(PlayerScripted)
|
||||
|
||||
virtual void SetName(const std::wstring& name)
|
||||
{
|
||||
m_Script.CallVoid("SetName", name);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT_SCRIPT_WRAPPER(PlayerScripted)
|
37
source/simulation2/components/ICmpPlayer.h
Normal file
37
source/simulation2/components/ICmpPlayer.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ICMPPLAYER
|
||||
#define INCLUDED_ICMPPLAYER
|
||||
|
||||
#include "simulation2/system/Interface.h"
|
||||
|
||||
/**
|
||||
* Player data.
|
||||
* (This interface only includes the functions needed by native code for loading maps;
|
||||
* most player interaction is handled by scripts instead.)
|
||||
*/
|
||||
class ICmpPlayer : public IComponent
|
||||
{
|
||||
public:
|
||||
virtual void SetName(const std::wstring& name) = 0;
|
||||
// TODO: some more data
|
||||
|
||||
DECLARE_INTERFACE_TYPE(Player)
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPPLAYER
|
39
source/simulation2/components/ICmpPlayerManager.cpp
Normal file
39
source/simulation2/components/ICmpPlayerManager.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ICmpPlayerManager.h"
|
||||
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
#include "simulation2/scripting/ScriptComponent.h"
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(PlayerManager)
|
||||
END_INTERFACE_WRAPPER(PlayerManager)
|
||||
|
||||
class CCmpPlayerManagerScripted : public ICmpPlayerManager
|
||||
{
|
||||
public:
|
||||
DEFAULT_SCRIPT_WRAPPER(PlayerManagerScripted)
|
||||
|
||||
virtual void AddPlayer(entity_id_t ent)
|
||||
{
|
||||
m_Script.CallVoid("AddPlayer", (int)ent);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT_SCRIPT_WRAPPER(PlayerManagerScripted)
|
36
source/simulation2/components/ICmpPlayerManager.h
Normal file
36
source/simulation2/components/ICmpPlayerManager.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ICMPPLAYERMANAGER
|
||||
#define INCLUDED_ICMPPLAYERMANAGER
|
||||
|
||||
#include "simulation2/system/Interface.h"
|
||||
|
||||
/**
|
||||
* Player manager. This maintains the list of players that exist in the game.
|
||||
*/
|
||||
class ICmpPlayerManager : public IComponent
|
||||
{
|
||||
public:
|
||||
virtual void AddPlayer(entity_id_t ent) = 0;
|
||||
|
||||
// Accessors are currently only available to scripts, since no C++ code needed them yet
|
||||
|
||||
DECLARE_INTERFACE_TYPE(PlayerManager)
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPPLAYERMANAGER
|
34
source/simulation2/components/ICmpUnknownScript.cpp
Normal file
34
source/simulation2/components/ICmpUnknownScript.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ICmpUnknownScript.h"
|
||||
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
#include "simulation2/scripting/ScriptComponent.h"
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(UnknownScript)
|
||||
END_INTERFACE_WRAPPER(UnknownScript)
|
||||
|
||||
class CCmpUnknownScript : public ICmpUnknownScript
|
||||
{
|
||||
public:
|
||||
DEFAULT_SCRIPT_WRAPPER(UnknownScript)
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT_SCRIPT_WRAPPER(UnknownScript)
|
32
source/simulation2/components/ICmpUnknownScript.h
Normal file
32
source/simulation2/components/ICmpUnknownScript.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ICMPUNKNOWNSCRIPT
|
||||
#define INCLUDED_ICMPUNKNOWNSCRIPT
|
||||
|
||||
#include "simulation2/system/Interface.h"
|
||||
|
||||
/**
|
||||
* Dummy wrapper class for script components that don't have a native interface.
|
||||
*/
|
||||
class ICmpUnknownScript : public IComponent
|
||||
{
|
||||
public:
|
||||
DECLARE_INTERFACE_TYPE(UnknownScript)
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPUNKNOWNSCRIPT
|
@ -86,7 +86,7 @@ public:
|
||||
TS_ASSERT_EQUALS(cmp->GetInterpolatedTransform(1.0f).GetTranslation(), CVector3D(200, 60, 0));
|
||||
|
||||
// Latch new position for interpolation
|
||||
test.HandleMessage(cmp, CMessageTurnStart());
|
||||
test.HandleMessage(cmp, CMessageTurnStart(), false);
|
||||
|
||||
// Move smoothly to new position
|
||||
cmp->MoveTo(entity_pos_t::FromInt(400), entity_pos_t::FromInt(300));
|
||||
|
@ -106,6 +106,38 @@ CMessage* CMessageRenderSubmit::FromJSVal(ScriptInterface& UNUSED(scriptInterfac
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
jsval CMessageDestroy::ToJSVal(ScriptInterface& UNUSED(scriptInterface)) const
|
||||
{
|
||||
return JSVAL_VOID;
|
||||
}
|
||||
|
||||
CMessage* CMessageDestroy::FromJSVal(ScriptInterface& UNUSED(scriptInterface), jsval UNUSED(val))
|
||||
{
|
||||
return new CMessageDestroy();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
jsval CMessageOwnershipChanged::ToJSVal(ScriptInterface& scriptInterface) const
|
||||
{
|
||||
TOJSVAL_SETUP();
|
||||
SET_MSG_PROPERTY(entity);
|
||||
SET_MSG_PROPERTY(from);
|
||||
SET_MSG_PROPERTY(to);
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
||||
CMessage* CMessageOwnershipChanged::FromJSVal(ScriptInterface& scriptInterface, jsval val)
|
||||
{
|
||||
FROMJSVAL_SETUP();
|
||||
GET_MSG_PROPERTY(entity_id_t, entity);
|
||||
GET_MSG_PROPERTY(int32_t, from);
|
||||
GET_MSG_PROPERTY(int32_t, to);
|
||||
return new CMessageOwnershipChanged(entity, from, to);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
CMessage* CMessageFromJSVal(int mtid, ScriptInterface& scriptingInterface, jsval val)
|
||||
|
@ -46,15 +46,16 @@ void CComponentTypeScript::Deinit(const CSimContext& UNUSED(context))
|
||||
m_ScriptInterface.CallFunctionVoid(m_Instance, "Deinit");
|
||||
}
|
||||
|
||||
void CComponentTypeScript::HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg)
|
||||
void CComponentTypeScript::HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg, bool global)
|
||||
{
|
||||
const char* name = msg.GetScriptHandlerName();
|
||||
const char* name = global ? msg.GetScriptGlobalHandlerName() : msg.GetScriptHandlerName();
|
||||
|
||||
CScriptVal msgVal = msg.ToJSVal(m_ScriptInterface);
|
||||
// TODO: repeated conversions are exceedingly inefficient. Should
|
||||
// cache this once per message (if it's used by >= 1 scripted component)
|
||||
|
||||
m_ScriptInterface.CallFunctionVoid(m_Instance, name, msgVal);
|
||||
if (!m_ScriptInterface.CallFunctionVoid(m_Instance, name, msgVal))
|
||||
LOGERROR(L"Script message handler %hs failed", name);
|
||||
}
|
||||
|
||||
void CComponentTypeScript::Serialize(ISerializer& serialize)
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
|
||||
|
||||
@ -40,7 +41,7 @@ public:
|
||||
|
||||
void Init(const CSimContext& context, const CParamNode& paramNode, entity_id_t ent);
|
||||
void Deinit(const CSimContext& context);
|
||||
void HandleMessage(const CSimContext& context, const CMessage& msg);
|
||||
void HandleMessage(const CSimContext& context, const CMessage& msg, bool global);
|
||||
|
||||
void Serialize(ISerializer& serialize);
|
||||
void Deserialize(const CSimContext& context, const CParamNode& paramNode, IDeserializer& deserialize, entity_id_t ent);
|
||||
@ -49,9 +50,26 @@ public:
|
||||
// template<typename R> R Call(const char* funcname);
|
||||
// template<typename R, typename T0> R Call(const char* funcname, const T0& a0);
|
||||
// ...
|
||||
// void CallVoid(const char* funcname);
|
||||
// template<typename T0> void CallVoid(const char* funcname, const T0& a0);
|
||||
// ...
|
||||
#define OVERLOADS(z, i, data) \
|
||||
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(i, typename T)> \
|
||||
R Call(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a));
|
||||
R Call(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \
|
||||
{ \
|
||||
R ret; \
|
||||
if (m_ScriptInterface.CallFunction(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
|
||||
return ret; \
|
||||
LOGERROR(L"Error calling component script function %hs", funcname); \
|
||||
return R(); \
|
||||
} \
|
||||
BOOST_PP_IF(i, template<, ) BOOST_PP_ENUM_PARAMS(i, typename T) BOOST_PP_IF(i, >, ) \
|
||||
void CallVoid(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \
|
||||
{ \
|
||||
if (m_ScriptInterface.CallFunctionVoid(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \
|
||||
return; \
|
||||
LOGERROR(L"Error calling component script function %hs", funcname); \
|
||||
}
|
||||
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
|
||||
#undef OVERLOADS
|
||||
|
||||
@ -62,17 +80,4 @@ private:
|
||||
NONCOPYABLE(CComponentTypeScript);
|
||||
};
|
||||
|
||||
#define OVERLOADS(z, i, data) \
|
||||
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(i, typename T)> \
|
||||
R CComponentTypeScript::Call(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \
|
||||
{ \
|
||||
R ret; \
|
||||
if (m_ScriptInterface.CallFunction(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
|
||||
return ret; \
|
||||
LOGERROR(L"Error calling component script function %hs", funcname); \
|
||||
return R(); \
|
||||
}
|
||||
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
|
||||
#undef OVERLOADS
|
||||
|
||||
#endif // INCLUDED_SCRIPTCOMPONENT
|
||||
|
@ -64,9 +64,9 @@
|
||||
{ \
|
||||
m_Script.Deinit(context); \
|
||||
} \
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg) \
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool global) \
|
||||
{ \
|
||||
m_Script.HandleMessage(context, msg); \
|
||||
m_Script.HandleMessage(context, msg, global); \
|
||||
} \
|
||||
virtual void Serialize(ISerializer& serialize) \
|
||||
{ \
|
||||
|
@ -20,8 +20,12 @@
|
||||
#include "ComponentManager.h"
|
||||
|
||||
#include "IComponent.h"
|
||||
#include "ParamNode.h"
|
||||
#include "SimContext.h"
|
||||
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
#include "simulation2/MessageTypes.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
|
||||
@ -29,18 +33,25 @@ CComponentManager::CComponentManager(const CSimContext& context, bool skipScript
|
||||
m_NextScriptComponentTypeId(CID__LastNative), m_ScriptInterface("Engine"), m_SimContext(context), m_CurrentlyHotloading(false)
|
||||
{
|
||||
m_ScriptInterface.SetCallbackData(static_cast<void*> (this));
|
||||
|
||||
// For component script tests, the test system sets up its own scripted implementation of
|
||||
// these functions, so we skip registering them here in those cases
|
||||
if (!skipScriptFunctions)
|
||||
{
|
||||
m_ScriptInterface.RegisterFunction<void, int, std::string, CScriptVal, CComponentManager::Script_RegisterComponentType> ("RegisterComponentType");
|
||||
m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterInterface> ("RegisterInterface");
|
||||
m_ScriptInterface.RegisterFunction<void, std::string, CScriptVal, CComponentManager::Script_RegisterGlobal> ("RegisterGlobal");
|
||||
m_ScriptInterface.RegisterFunction<IComponent*, int, int, CComponentManager::Script_QueryInterface> ("QueryInterface");
|
||||
m_ScriptInterface.RegisterFunction<void, int, int, CScriptVal, CComponentManager::Script_PostMessage> ("PostMessage");
|
||||
m_ScriptInterface.RegisterFunction<void, int, CScriptVal, CComponentManager::Script_BroadcastMessage> ("BroadcastMessage");
|
||||
m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddEntity> ("AddEntity");
|
||||
}
|
||||
|
||||
// Define MT_*, IID_* as script globals
|
||||
// Define MT_*, IID_* as script globals, and store their names
|
||||
#define MESSAGE(name) m_ScriptInterface.SetGlobal("MT_" #name, (int)MT_##name);
|
||||
#define INTERFACE(name) m_ScriptInterface.SetGlobal("IID_" #name, (int)IID_##name);
|
||||
#define INTERFACE(name) \
|
||||
m_ScriptInterface.SetGlobal("IID_" #name, (int)IID_##name); \
|
||||
m_InterfaceIdsByName[#name] = IID_##name;
|
||||
#define COMPONENT(name)
|
||||
#include "simulation2/TypeList.h"
|
||||
#undef MESSAGE
|
||||
@ -63,6 +74,8 @@ CComponentManager::~CComponentManager()
|
||||
m_ScriptInterface.RemoveRoot(&it->second.ctor);
|
||||
}
|
||||
|
||||
void CComponentManager::LoadComponentTypes()
|
||||
{
|
||||
#define MESSAGE(name) \
|
||||
RegisterMessageType(MT_##name, #name);
|
||||
#define INTERFACE(name) \
|
||||
@ -73,14 +86,15 @@ CComponentManager::~CComponentManager()
|
||||
m_CurrentComponent = CID_##name; \
|
||||
RegisterComponentType_##name(*this);
|
||||
|
||||
void CComponentManager::LoadComponentTypes()
|
||||
{
|
||||
#include "simulation2/TypeList.h"
|
||||
}
|
||||
|
||||
m_CurrentComponent = CID__Invalid;
|
||||
|
||||
#undef MESSAGE
|
||||
#undef INTERFACE
|
||||
#undef COMPONENT
|
||||
}
|
||||
|
||||
|
||||
bool CComponentManager::LoadScript(const std::wstring& filename, bool hotload)
|
||||
{
|
||||
@ -93,13 +107,6 @@ bool CComponentManager::LoadScript(const std::wstring& filename, bool hotload)
|
||||
return ok;
|
||||
}
|
||||
|
||||
void CComponentManager::Script_RegisterGlobal(void* cbdata, std::string name, CScriptVal value)
|
||||
{
|
||||
CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
|
||||
|
||||
componentManager->m_ScriptInterface.SetGlobal(name.c_str(), value);
|
||||
}
|
||||
|
||||
void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std::string cname, CScriptVal ctor)
|
||||
{
|
||||
CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
|
||||
@ -124,6 +131,8 @@ void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std:
|
||||
}
|
||||
else
|
||||
{
|
||||
// Component type is already loaded, so do hotloading:
|
||||
|
||||
if (!componentManager->m_CurrentlyHotloading)
|
||||
{
|
||||
componentManager->m_ScriptInterface.ReportError("Registering component type with already-registered name"); // TODO: report the actual name
|
||||
@ -158,10 +167,10 @@ void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std:
|
||||
}
|
||||
|
||||
// Construct a new ComponentType, using the wrapper's alloc functions
|
||||
ComponentType ct = { CT_Script, ctWrapper.iid, ctWrapper.alloc, ctWrapper.dealloc, cname, ctor.get() };
|
||||
ComponentType ct = { CT_Script, iid, ctWrapper.alloc, ctWrapper.dealloc, cname, ctor.get() };
|
||||
componentManager->m_ComponentTypesById[cid] = ct;
|
||||
|
||||
componentManager->m_CurrentComponent = cid;
|
||||
componentManager->m_CurrentComponent = cid; // needed by Subscribe
|
||||
|
||||
// Stop the ctor getting GCed
|
||||
componentManager->m_ScriptInterface.AddRoot(&componentManager->m_ComponentTypesById[cid].ctor, "ComponentType ctor");
|
||||
@ -181,15 +190,30 @@ void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std:
|
||||
for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it)
|
||||
{
|
||||
std::string name = (*it).substr(2); // strip the "On" prefix
|
||||
|
||||
// Handle "OnGlobalFoo" functions specially
|
||||
bool isGlobal = false;
|
||||
if (name.substr(0, 6) == "Global")
|
||||
{
|
||||
isGlobal = true;
|
||||
name = name.substr(6);
|
||||
}
|
||||
|
||||
std::map<std::string, MessageTypeId>::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name);
|
||||
if (mit == componentManager->m_MessageTypeIdsByName.end())
|
||||
{
|
||||
componentManager->m_ScriptInterface.ReportError("Registered component has unrecognised 'On...' message handler method"); // TODO: report the actual name
|
||||
return;
|
||||
}
|
||||
componentManager->SubscribeToMessageType(cid, mit->second);
|
||||
|
||||
if (isGlobal)
|
||||
componentManager->SubscribeGloballyToMessageType(mit->second);
|
||||
else
|
||||
componentManager->SubscribeToMessageType(mit->second);
|
||||
}
|
||||
|
||||
componentManager->m_CurrentComponent = CID__Invalid;
|
||||
|
||||
if (mustReloadComponents)
|
||||
{
|
||||
// For every script component with this cid, we need to switch its
|
||||
@ -205,6 +229,30 @@ void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std:
|
||||
}
|
||||
}
|
||||
|
||||
void CComponentManager::Script_RegisterInterface(void* cbdata, std::string name)
|
||||
{
|
||||
CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
|
||||
|
||||
std::map<std::string, InterfaceId>::iterator it = componentManager->m_InterfaceIdsByName.find(name);
|
||||
if (it != componentManager->m_InterfaceIdsByName.end())
|
||||
{
|
||||
componentManager->m_ScriptInterface.ReportError("Registering interface with already-registered name"); // TODO: report the actual name
|
||||
return;
|
||||
}
|
||||
|
||||
// IIDs start at 1, so size+1 is the next unused one
|
||||
size_t id = componentManager->m_InterfaceIdsByName.size() + 1;
|
||||
componentManager->m_InterfaceIdsByName[name] = id;
|
||||
componentManager->m_ScriptInterface.SetGlobal(("IID_" + name).c_str(), (int )id);
|
||||
}
|
||||
|
||||
void CComponentManager::Script_RegisterGlobal(void* cbdata, std::string name, CScriptVal value)
|
||||
{
|
||||
CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
|
||||
|
||||
componentManager->m_ScriptInterface.SetGlobal(name.c_str(), value);
|
||||
}
|
||||
|
||||
IComponent* CComponentManager::Script_QueryInterface(void* cbdata, int ent, int iid)
|
||||
{
|
||||
CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
|
||||
@ -236,6 +284,18 @@ void CComponentManager::Script_BroadcastMessage(void* cbdata, int mtid, CScriptV
|
||||
delete msg;
|
||||
}
|
||||
|
||||
int CComponentManager::Script_AddEntity(void* cbdata, std::string templateName)
|
||||
{
|
||||
CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
|
||||
|
||||
std::wstring name(templateName.begin(), templateName.end());
|
||||
// TODO: should validate the string to make sure it doesn't contain scary characters
|
||||
// that will let it access non-component-template files
|
||||
|
||||
entity_id_t ent = componentManager->AddEntity(name, componentManager->AllocateNewEntity());
|
||||
return (int)ent;
|
||||
}
|
||||
|
||||
void CComponentManager::ResetState()
|
||||
{
|
||||
// Delete all IComponents
|
||||
@ -282,12 +342,21 @@ void CComponentManager::RegisterMessageType(MessageTypeId mtid, const char* name
|
||||
m_MessageTypeIdsByName[name] = mtid;
|
||||
}
|
||||
|
||||
void CComponentManager::SubscribeToMessageType(ComponentTypeId cid, MessageTypeId mtid)
|
||||
void CComponentManager::SubscribeToMessageType(MessageTypeId mtid)
|
||||
{
|
||||
// TODO: verify mtid
|
||||
debug_assert(cid == m_CurrentComponent); // TODO: this should be redundant
|
||||
std::vector<ComponentTypeId>& types = m_ComponentTypeIdsByMessageType[mtid];
|
||||
types.push_back(cid);
|
||||
debug_assert(m_CurrentComponent != CID__Invalid);
|
||||
std::vector<ComponentTypeId>& types = m_LocalMessageSubscriptions[mtid];
|
||||
types.push_back(m_CurrentComponent);
|
||||
std::sort(types.begin(), types.end()); // TODO: just sort once at the end of LoadComponents
|
||||
}
|
||||
|
||||
void CComponentManager::SubscribeGloballyToMessageType(MessageTypeId mtid)
|
||||
{
|
||||
// TODO: verify mtid
|
||||
debug_assert(m_CurrentComponent != CID__Invalid);
|
||||
std::vector<ComponentTypeId>& types = m_GlobalMessageSubscriptions[mtid];
|
||||
types.push_back(m_CurrentComponent);
|
||||
std::sort(types.begin(), types.end()); // TODO: just sort once at the end of LoadComponents
|
||||
}
|
||||
|
||||
@ -309,6 +378,9 @@ std::string CComponentManager::LookupComponentTypeName(ComponentTypeId cid) cons
|
||||
|
||||
CComponentManager::ComponentTypeId CComponentManager::GetScriptWrapper(InterfaceId iid)
|
||||
{
|
||||
if (iid >= IID__LastNative && iid <= (int)m_InterfaceIdsByName.size()) // use <= since IDs start at 1
|
||||
return CID_UnknownScript;
|
||||
|
||||
std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.begin();
|
||||
for (; it != m_ComponentTypesById.end(); ++it)
|
||||
if (it->second.iid == iid && it->second.type == CT_ScriptWrapper)
|
||||
@ -416,6 +488,48 @@ void CComponentManager::AddMockComponent(entity_id_t ent, InterfaceId iid, IComp
|
||||
emap1.insert(std::make_pair(ent, &component));
|
||||
}
|
||||
|
||||
entity_id_t CComponentManager::AddEntity(const std::wstring& templateName, entity_id_t ent)
|
||||
{
|
||||
ICmpTemplateManager *tempMan = static_cast<ICmpTemplateManager*> (QueryInterface(SYSTEM_ENTITY, IID_TemplateManager));
|
||||
if (!tempMan)
|
||||
{
|
||||
debug_warn(L"No ICmpTemplateManager loaded");
|
||||
return INVALID_ENTITY;
|
||||
}
|
||||
|
||||
// TODO: should assert that ent doesn't exist
|
||||
|
||||
const CParamNode* tmpl = tempMan->LoadTemplate(ent, templateName, -1);
|
||||
if (!tmpl)
|
||||
return INVALID_ENTITY; // LoadTemplate will have reported the error
|
||||
|
||||
// Construct a component for each child of the root element
|
||||
const CParamNode::ChildrenMap& tmplChilds = tmpl->GetChildren();
|
||||
for (CParamNode::ChildrenMap::const_iterator it = tmplChilds.begin(); it != tmplChilds.end(); ++it)
|
||||
{
|
||||
// Ignore attributes on the root element
|
||||
if (it->first.length() && it->first[0] == '@')
|
||||
continue;
|
||||
|
||||
CComponentManager::ComponentTypeId cid = LookupCID(it->first);
|
||||
if (cid == CID__Invalid)
|
||||
{
|
||||
LOGERROR(L"Unrecognised component type name '%hs' in entity template '%ls'", it->first.c_str(), templateName.c_str());
|
||||
return INVALID_ENTITY;
|
||||
}
|
||||
|
||||
if (!AddComponent(ent, cid, it->second))
|
||||
{
|
||||
LOGERROR(L"Failed to construct component type name '%hs' in entity template '%ls'", it->first.c_str(), templateName.c_str());
|
||||
return INVALID_ENTITY;
|
||||
}
|
||||
|
||||
// TODO: maybe we should delete already-constructed components if one of them fails?
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
void CComponentManager::DestroyComponentsSoon(entity_id_t ent)
|
||||
{
|
||||
m_DestructionQueue.push_back(ent);
|
||||
@ -423,10 +537,17 @@ void CComponentManager::DestroyComponentsSoon(entity_id_t ent)
|
||||
|
||||
void CComponentManager::FlushDestroyedComponents()
|
||||
{
|
||||
for (std::vector<entity_id_t>::iterator it = m_DestructionQueue.begin(); it != m_DestructionQueue.end(); ++it)
|
||||
// Make a copy of the destruction queue, so that the iterators won't be invalidated if the
|
||||
// CMessageDestroy handlers try to destroy more entities themselves
|
||||
std::vector<entity_id_t> queue;
|
||||
queue.swap(m_DestructionQueue);
|
||||
|
||||
for (std::vector<entity_id_t>::iterator it = queue.begin(); it != queue.end(); ++it)
|
||||
{
|
||||
entity_id_t ent = *it;
|
||||
|
||||
PostMessage(ent, CMessageDestroy());
|
||||
|
||||
// Destroy the components, and remove from m_ComponentsByTypeId:
|
||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::iterator iit = m_ComponentsByTypeId.begin();
|
||||
for (; iit != m_ComponentsByTypeId.end(); ++iit)
|
||||
@ -447,8 +568,6 @@ void CComponentManager::FlushDestroyedComponents()
|
||||
ifcit->second.erase(ent);
|
||||
}
|
||||
}
|
||||
|
||||
m_DestructionQueue.clear();
|
||||
}
|
||||
|
||||
IComponent* CComponentManager::QueryInterface(entity_id_t ent, InterfaceId iid) const
|
||||
@ -485,46 +604,69 @@ const std::map<entity_id_t, IComponent*>& CComponentManager::GetEntitiesWithInte
|
||||
|
||||
void CComponentManager::PostMessage(entity_id_t ent, const CMessage& msg) const
|
||||
{
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it = m_ComponentTypeIdsByMessageType.find(msg.GetType());
|
||||
if (it == m_ComponentTypeIdsByMessageType.end())
|
||||
// Send the message to components of ent, that subscribed locally to this message
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
|
||||
it = m_LocalMessageSubscriptions.find(msg.GetType());
|
||||
if (it != m_LocalMessageSubscriptions.end())
|
||||
{
|
||||
// Nobody subscribed to this message
|
||||
return;
|
||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
|
||||
for (; ctit != it->second.end(); ++ctit)
|
||||
{
|
||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
|
||||
if (emap == m_ComponentsByTypeId.end())
|
||||
continue;
|
||||
|
||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.find(ent);
|
||||
if (eit != emap->second.end())
|
||||
eit->second->HandleMessage(m_SimContext, msg, false);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
|
||||
for (; ctit != it->second.end(); ++ctit)
|
||||
{
|
||||
int cid = *ctit;
|
||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(cid);
|
||||
if (emap == m_ComponentsByTypeId.end())
|
||||
continue;
|
||||
|
||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.find(ent);
|
||||
if (eit != emap->second.end())
|
||||
eit->second->HandleMessage(m_SimContext, msg);
|
||||
}
|
||||
SendGlobalMessage(msg);
|
||||
}
|
||||
|
||||
void CComponentManager::BroadcastMessage(const CMessage& msg) const
|
||||
{
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it = m_ComponentTypeIdsByMessageType.find(msg.GetType());
|
||||
if (it == m_ComponentTypeIdsByMessageType.end())
|
||||
// Send the message to components of all entities that subscribed locally to this message
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
|
||||
it = m_LocalMessageSubscriptions.find(msg.GetType());
|
||||
if (it != m_LocalMessageSubscriptions.end())
|
||||
{
|
||||
// Nobody subscribed to this message
|
||||
return;
|
||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
|
||||
for (; ctit != it->second.end(); ++ctit)
|
||||
{
|
||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
|
||||
if (emap == m_ComponentsByTypeId.end())
|
||||
continue;
|
||||
|
||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin();
|
||||
for (; eit != emap->second.end(); ++eit)
|
||||
eit->second->HandleMessage(m_SimContext, msg, false);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
|
||||
for (; ctit != it->second.end(); ++ctit)
|
||||
{
|
||||
int cid = *ctit;
|
||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(cid);
|
||||
if (emap == m_ComponentsByTypeId.end())
|
||||
continue;
|
||||
SendGlobalMessage(msg);
|
||||
}
|
||||
|
||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin();
|
||||
for (; eit != emap->second.end(); ++eit)
|
||||
eit->second->HandleMessage(m_SimContext, msg);
|
||||
void CComponentManager::SendGlobalMessage(const CMessage& msg) const
|
||||
{
|
||||
// (Common functionality for PostMessage and BroadcastMessage)
|
||||
|
||||
// Send the message to components of all entities that subscribed globally to this message
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
|
||||
it = m_GlobalMessageSubscriptions.find(msg.GetType());
|
||||
if (it != m_GlobalMessageSubscriptions.end())
|
||||
{
|
||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
|
||||
for (; ctit != it->second.end(); ++ctit)
|
||||
{
|
||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
|
||||
if (emap == m_ComponentsByTypeId.end())
|
||||
continue;
|
||||
|
||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin();
|
||||
for (; eit != emap->second.end(); ++eit)
|
||||
eit->second->HandleMessage(m_SimContext, msg, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,8 @@ public:
|
||||
|
||||
void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*);
|
||||
void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*);
|
||||
void SubscribeToMessageType(ComponentTypeId, MessageTypeId);
|
||||
void SubscribeToMessageType(MessageTypeId);
|
||||
void SubscribeGloballyToMessageType(MessageTypeId);
|
||||
|
||||
/**
|
||||
* @param cname Requested component type name (not including any "CID" or "CCmp" prefix)
|
||||
@ -139,6 +140,13 @@ public:
|
||||
*/
|
||||
IComponent* ConstructComponent(entity_id_t ent, ComponentTypeId cid);
|
||||
|
||||
/**
|
||||
* Constructs an entity based on the given template, and adds it the world with
|
||||
* entity ID @p ent. There should not be any existing components with that entity ID.
|
||||
* @return ent, or INVALID_ENTITY on error
|
||||
*/
|
||||
entity_id_t AddEntity(const std::wstring& templateName, entity_id_t ent);
|
||||
|
||||
/**
|
||||
* Destroys all the components belonging to the specified entity when FlushDestroyedComponents is called.
|
||||
* Has no effect if the entity does not exist, or has already been added to the destruction queue.
|
||||
@ -153,9 +161,20 @@ public:
|
||||
void FlushDestroyedComponents();
|
||||
|
||||
IComponent* QueryInterface(entity_id_t ent, InterfaceId iid) const;
|
||||
|
||||
const std::map<entity_id_t, IComponent*>& GetEntitiesWithInterface(InterfaceId iid) const;
|
||||
|
||||
/**
|
||||
* Send a message, targeted at a particular entity. The message will be received by any
|
||||
* components of that entity which subscribed to the message type, and by any other components
|
||||
* that subscribed globally to the message type.
|
||||
*/
|
||||
void PostMessage(entity_id_t ent, const CMessage& msg) const;
|
||||
|
||||
/**
|
||||
* Send a message, not targeted at any particular entity. The message will be received by any
|
||||
* components that subscribed (either globally or not) to the message type.
|
||||
*/
|
||||
void BroadcastMessage(const CMessage& msg) const;
|
||||
|
||||
/**
|
||||
@ -177,26 +196,32 @@ public:
|
||||
private:
|
||||
// Implementations of functions exposed to scripts
|
||||
static void Script_RegisterComponentType(void* cbdata, int iid, std::string cname, CScriptVal ctor);
|
||||
static void Script_RegisterInterface(void* cbdata, std::string name);
|
||||
static void Script_RegisterGlobal(void* cbdata, std::string name, CScriptVal value);
|
||||
static IComponent* Script_QueryInterface(void* cbdata, int ent, int iid);
|
||||
static void Script_PostMessage(void* cbdata, int ent, int mtid, CScriptVal data);
|
||||
static void Script_BroadcastMessage(void* cbdata, int mtid, CScriptVal data);
|
||||
static int Script_AddEntity(void* cbdata, std::string templateName);
|
||||
|
||||
void SendGlobalMessage(const CMessage& msg) const;
|
||||
|
||||
ComponentTypeId GetScriptWrapper(InterfaceId iid);
|
||||
|
||||
ScriptInterface m_ScriptInterface;
|
||||
const CSimContext& m_SimContext;
|
||||
|
||||
ComponentTypeId m_CurrentComponent;
|
||||
ComponentTypeId m_CurrentComponent; // used when loading component types
|
||||
bool m_CurrentlyHotloading;
|
||||
|
||||
// TODO: some of these should be vectors
|
||||
std::map<ComponentTypeId, ComponentType> m_ComponentTypesById;
|
||||
std::map<InterfaceId, std::map<entity_id_t, IComponent*> > m_ComponentsByInterface;
|
||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> > m_ComponentsByTypeId;
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> > m_ComponentTypeIdsByMessageType;
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> > m_LocalMessageSubscriptions;
|
||||
std::map<MessageTypeId, std::vector<ComponentTypeId> > m_GlobalMessageSubscriptions;
|
||||
std::map<std::string, ComponentTypeId> m_ComponentTypeIdsByName;
|
||||
std::map<std::string, MessageTypeId> m_MessageTypeIdsByName;
|
||||
std::map<std::string, InterfaceId> m_InterfaceIdsByName;
|
||||
// TODO: maintaining both ComponentsBy* is nasty; can we get rid of one,
|
||||
// while keeping QueryInterface and PostMessage sufficiently efficient?
|
||||
|
||||
|
@ -86,9 +86,9 @@ public:
|
||||
m_ComponentManager.AddMockComponent(ent, iid, component);
|
||||
}
|
||||
|
||||
void HandleMessage(IComponent* cmp, const CMessage& msg)
|
||||
void HandleMessage(IComponent* cmp, const CMessage& msg, bool global)
|
||||
{
|
||||
cmp->HandleMessage(m_Context, msg);
|
||||
cmp->HandleMessage(m_Context, msg, global);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,7 @@ IComponent::~IComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void IComponent::HandleMessage(const CSimContext& UNUSED(context), const CMessage& UNUSED(msg))
|
||||
void IComponent::HandleMessage(const CSimContext& UNUSED(context), const CMessage& UNUSED(msg), bool UNUSED(global))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
virtual void Init(const CSimContext& context, const CParamNode& paramNode) = 0;
|
||||
virtual void Deinit(const CSimContext& context) = 0;
|
||||
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg);
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool global);
|
||||
|
||||
entity_id_t GetEntityId() const { return m_EntityId; }
|
||||
void SetEntityId(entity_id_t ent) { m_EntityId = ent; }
|
||||
|
@ -28,6 +28,7 @@ protected:
|
||||
public:
|
||||
virtual EMessageTypeId GetType() const = 0;
|
||||
virtual const char* GetScriptHandlerName() const = 0;
|
||||
virtual const char* GetScriptGlobalHandlerName() const = 0;
|
||||
virtual jsval ToJSVal(ScriptInterface&) const = 0;
|
||||
};
|
||||
// TODO: GetType could be replaced with a plain member variable to avoid some
|
||||
|
@ -156,6 +156,7 @@ public:
|
||||
|
||||
CMessageTurnStart msg1;
|
||||
CMessageUpdate msg2(CFixed_23_8::FromInt(100));
|
||||
CMessageInterpolate msg3(0);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 11000);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), 12000);
|
||||
@ -163,6 +164,7 @@ public:
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent4, IID_Test1))->GetX(), 11000);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent4, IID_Test2))->GetX(), 21000);
|
||||
|
||||
// Test_1A subscribed locally to msg1, nothing subscribed globally
|
||||
man.PostMessage(ent1, msg1);
|
||||
man.PostMessage(ent1, msg2);
|
||||
|
||||
@ -180,6 +182,7 @@ public:
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent4, IID_Test1))->GetX(), 11001);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent4, IID_Test2))->GetX(), 21050);
|
||||
|
||||
// Test_1B, Test_2A subscribed locally to msg2, nothing subscribed globally
|
||||
man.BroadcastMessage(msg2);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 11002);
|
||||
@ -187,6 +190,23 @@ public:
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent3, IID_Test2))->GetX(), 21150);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent4, IID_Test1))->GetX(), 11001);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent4, IID_Test2))->GetX(), 21150);
|
||||
|
||||
// Test_1A subscribed locally to msg3, Test_1B subscribed globally
|
||||
man.BroadcastMessage(msg3);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 11004); // local
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), 12030); // global
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent3, IID_Test2))->GetX(), 21150);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent4, IID_Test1))->GetX(), 11003); // local
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent4, IID_Test2))->GetX(), 21150);
|
||||
|
||||
man.PostMessage(ent1, msg3);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 11006); // local
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), 12050); // global
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent3, IID_Test2))->GetX(), 21150);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent4, IID_Test1))->GetX(), 11003); // local - skipped
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent4, IID_Test2))->GetX(), 21150);
|
||||
}
|
||||
|
||||
void test_ParamNode()
|
||||
@ -265,6 +285,23 @@ public:
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 3);
|
||||
}
|
||||
|
||||
void test_script_interface()
|
||||
{
|
||||
CSimContext context;
|
||||
CComponentManager man(context);
|
||||
man.LoadComponentTypes();
|
||||
TS_ASSERT(man.LoadScript(L"simulation/components/interfaces/test-interface.js"));
|
||||
TS_ASSERT(man.LoadScript(L"simulation/components/test-interface.js"));
|
||||
|
||||
entity_id_t ent1 = 1;
|
||||
CParamNode noParam;
|
||||
|
||||
man.AddComponent(ent1, man.LookupCID("TestScript1_Interface"), noParam);
|
||||
man.AddComponent(ent1, man.LookupCID("TestScript2_Interface"), noParam);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 1000 + IID__LastNative);
|
||||
}
|
||||
|
||||
void test_script_errors()
|
||||
{
|
||||
CSimContext context;
|
||||
@ -322,6 +359,37 @@ public:
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), 21000);
|
||||
}
|
||||
|
||||
void test_script_AddEntity()
|
||||
{
|
||||
CSimContext context;
|
||||
CComponentManager man(context);
|
||||
man.LoadComponentTypes();
|
||||
TS_ASSERT(man.LoadScript(L"simulation/components/test-addentity.js"));
|
||||
TS_ASSERT(man.LoadScript(L"simulation/components/addentity/test-addentity.js"));
|
||||
|
||||
entity_id_t ent1 = man.AllocateNewEntity();
|
||||
entity_id_t ent2 = ent1 + 2;
|
||||
CParamNode noParam;
|
||||
|
||||
TS_ASSERT(man.AddComponent(SYSTEM_ENTITY, CID_TemplateManager, noParam));
|
||||
|
||||
TS_ASSERT(man.AddComponent(ent1, man.LookupCID("TestScript1_AddEntity"), noParam));
|
||||
|
||||
TS_ASSERT(man.QueryInterface(ent2, IID_Test1) == NULL);
|
||||
TS_ASSERT(man.QueryInterface(ent2, IID_Test2) == NULL);
|
||||
|
||||
{
|
||||
TestLogger logger; // ignore bogus-template warnings
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), (int)ent2);
|
||||
}
|
||||
|
||||
TS_ASSERT(man.QueryInterface(ent2, IID_Test1) != NULL);
|
||||
TS_ASSERT(man.QueryInterface(ent2, IID_Test2) != NULL);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), 999);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent2, IID_Test2))->GetX(), 12345);
|
||||
}
|
||||
|
||||
void test_script_messages()
|
||||
{
|
||||
CSimContext context;
|
||||
@ -329,24 +397,27 @@ public:
|
||||
man.LoadComponentTypes();
|
||||
TS_ASSERT(man.LoadScript(L"simulation/components/test-msg.js"));
|
||||
|
||||
entity_id_t ent1 = 1, ent2 = 2;
|
||||
entity_id_t ent1 = 1, ent2 = 2, ent3 = 3;
|
||||
CParamNode noParam;
|
||||
|
||||
man.AddComponent(ent1, man.LookupCID("TestScript1A"), noParam);
|
||||
man.AddComponent(ent1, man.LookupCID("TestScript2A"), noParam);
|
||||
man.AddComponent(ent2, man.LookupCID("TestScript1A"), noParam);
|
||||
man.AddComponent(ent2, CID_Test2A, noParam);
|
||||
man.AddComponent(ent3, man.LookupCID("TestScript1B"), noParam);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 100);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), 100);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test2))->GetX(), 21000);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent2, IID_Test2))->GetX(), 21000);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent3, IID_Test1))->GetX(), 100);
|
||||
|
||||
// This GetX broadcasts messages
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test2))->GetX(), 200);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent1, IID_Test2))->GetX(), 200);
|
||||
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 650);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), 5150);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test2))->GetX(), 26050);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest2*> (man.QueryInterface(ent2, IID_Test2))->GetX(), 26050);
|
||||
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent3, IID_Test1))->GetX(), 5650);
|
||||
}
|
||||
|
||||
void test_script_template()
|
||||
|
@ -33,6 +33,10 @@
|
||||
#include "renderer/Renderer.h"
|
||||
#include "simulation/LOSManager.h"
|
||||
#include "simulation/Simulation.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpPlayer.h"
|
||||
#include "simulation2/components/ICmpPlayerManager.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -64,6 +68,22 @@ namespace
|
||||
g_Game = new CGame();
|
||||
}
|
||||
|
||||
void AddDefaultPlayers()
|
||||
{
|
||||
CmpPtr<ICmpPlayerManager> cmpPlayerMan(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
||||
debug_assert(!cmpPlayerMan.null());
|
||||
|
||||
// TODO: pick a sensible number, give them names and colours etc
|
||||
size_t numPlayers = 4;
|
||||
for (size_t i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
entity_id_t ent = g_Game->GetSimulation2()->AddEntity(L"special/player");
|
||||
cmpPlayerMan->AddPlayer(ent);
|
||||
}
|
||||
// Also TODO: Maybe it'd be sensible to load this from a map XML file via CMapReader,
|
||||
// rather than duplicating the creation code here?
|
||||
}
|
||||
|
||||
void StartGame()
|
||||
{
|
||||
PSRETURN ret = g_Game->StartGame(&g_GameAttributes);
|
||||
@ -98,6 +118,8 @@ MESSAGEHANDLER(GenerateMap)
|
||||
|
||||
delete[] heightmap;
|
||||
|
||||
AddDefaultPlayers();
|
||||
|
||||
// Start the game, load data files - this must be done before initialising
|
||||
// the terrain texture below, since the terrains must be loaded before being
|
||||
// used.
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "simulation/EntityManager.h"
|
||||
#include "simulation/TerritoryManager.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpOwnership.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
|
||||
@ -189,6 +190,26 @@ MESSAGEHANDLER(SetSelectionPreview)
|
||||
|
||||
QUERYHANDLER(GetObjectSettings)
|
||||
{
|
||||
if (g_UseSimulation2)
|
||||
{
|
||||
sObjectSettings settings;
|
||||
settings.player = 0;
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), 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::GetView(msg->view)->GetUnit(msg->id);
|
||||
if (! unit) return;
|
||||
|
||||
@ -242,15 +263,30 @@ BEGIN_COMMAND(SetObjectSettings)
|
||||
|
||||
void Do()
|
||||
{
|
||||
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
|
||||
if (! unit) return;
|
||||
|
||||
sObjectSettings settings = msg->settings;
|
||||
|
||||
m_PlayerOld = unit->GetPlayerID();
|
||||
m_PlayerNew = (size_t)settings.player;
|
||||
if (g_UseSimulation2)
|
||||
{
|
||||
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), msg->id);
|
||||
m_PlayerOld = 0;
|
||||
if (!cmpOwner.null())
|
||||
{
|
||||
int32_t player = cmpOwner->GetOwner();
|
||||
if (player != -1)
|
||||
m_PlayerOld = player;
|
||||
}
|
||||
|
||||
m_SelectionsOld = unit->GetActorSelections();
|
||||
// TODO: selections
|
||||
}
|
||||
else
|
||||
{
|
||||
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
|
||||
if (! unit) return;
|
||||
m_PlayerOld = unit->GetPlayerID();
|
||||
m_SelectionsOld = unit->GetActorSelections();
|
||||
}
|
||||
|
||||
m_PlayerNew = (size_t)settings.player;
|
||||
|
||||
std::vector<std::wstring> selections = *settings.selections;
|
||||
for (std::vector<std::wstring>::iterator it = selections.begin(); it != selections.end(); ++it)
|
||||
@ -274,6 +310,16 @@ BEGIN_COMMAND(SetObjectSettings)
|
||||
private:
|
||||
void Set(size_t player, const std::set<CStr>& selections)
|
||||
{
|
||||
if (g_UseSimulation2)
|
||||
{
|
||||
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), msg->id);
|
||||
if (!cmpOwner.null())
|
||||
cmpOwner->SetOwner(player);
|
||||
// TODO: selections
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
|
||||
if (! unit) return;
|
||||
|
||||
@ -356,7 +402,7 @@ MESSAGEHANDLER(ObjectPreview)
|
||||
if ((*msg->id).empty())
|
||||
g_PreviewEntityID = INVALID_ENTITY;
|
||||
else
|
||||
g_PreviewEntityID = g_Game->GetSimulation2()->AddLocalEntity(*msg->id);
|
||||
g_PreviewEntityID = g_Game->GetSimulation2()->AddLocalEntity(L"preview|" + *msg->id);
|
||||
|
||||
g_PreviewUnitName = *msg->id;
|
||||
}
|
||||
@ -387,7 +433,10 @@ MESSAGEHANDLER(ObjectPreview)
|
||||
}
|
||||
|
||||
// TODO: handle random variations somehow
|
||||
// TODO: set player colour
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), g_PreviewEntityID);
|
||||
if (!cmpOwner.null())
|
||||
cmpOwner->SetOwner(msg->settings->player);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -533,8 +582,11 @@ BEGIN_COMMAND(CreateObject)
|
||||
cmpPos->SetYRotation(entity_angle_t::FromFloat(m_Angle));
|
||||
}
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), m_EntityID);
|
||||
if (!cmpOwner.null())
|
||||
cmpOwner->SetOwner(m_Player);
|
||||
|
||||
// TODO: handle random variations somehow
|
||||
// TODO: set player colour
|
||||
|
||||
return;
|
||||
}
|
||||
@ -905,12 +957,21 @@ END_COMMAND(RotateObject)
|
||||
|
||||
BEGIN_COMMAND(DeleteObject)
|
||||
{
|
||||
// These two values are never both non-NULL
|
||||
// Old simulation: These two values are never both non-NULL
|
||||
std::auto_ptr<SimState::Entity> m_FrozenEntity;
|
||||
std::auto_ptr<SimState::Nonentity> m_FrozenNonentity;
|
||||
|
||||
// New simulation:
|
||||
// Saved copy of the important aspects of a unit, to allow undo
|
||||
entity_id_t m_EntityID;
|
||||
std::wstring m_TemplateName;
|
||||
int32_t m_Owner;
|
||||
CFixedVector3D m_Pos;
|
||||
CFixedVector3D m_Rot;
|
||||
// TODO: random selections
|
||||
|
||||
cDeleteObject()
|
||||
: m_FrozenEntity(NULL), m_FrozenNonentity(NULL)
|
||||
: m_FrozenEntity(NULL), m_FrozenNonentity(NULL), m_EntityID(INVALID_ENTITY), m_Owner(-1)
|
||||
{
|
||||
}
|
||||
|
||||
@ -921,6 +982,31 @@ BEGIN_COMMAND(DeleteObject)
|
||||
|
||||
void Redo()
|
||||
{
|
||||
if (g_UseSimulation2)
|
||||
{
|
||||
CSimulation2& sim = *g_Game->GetSimulation2();
|
||||
CmpPtr<ICmpTemplateManager> cmpTemplateManager(sim, SYSTEM_ENTITY);
|
||||
debug_assert(!cmpTemplateManager.null());
|
||||
|
||||
m_EntityID = msg->id;
|
||||
m_TemplateName = cmpTemplateManager->GetCurrentTemplateName(m_EntityID);
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwner(sim, m_EntityID);
|
||||
if (!cmpOwner.null())
|
||||
m_Owner = cmpOwner->GetOwner();
|
||||
|
||||
CmpPtr<ICmpPosition> cmpPosition(sim, m_EntityID);
|
||||
if (!cmpPosition.null())
|
||||
{
|
||||
m_Pos = cmpPosition->GetPosition();
|
||||
m_Rot = cmpPosition->GetRotation();
|
||||
}
|
||||
|
||||
g_Game->GetSimulation2()->DestroyEntity(m_EntityID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CUnit* unit = GetUnitManager().FindByID(msg->id);
|
||||
if (! unit) return;
|
||||
|
||||
@ -943,6 +1029,30 @@ BEGIN_COMMAND(DeleteObject)
|
||||
|
||||
void Undo()
|
||||
{
|
||||
if (g_UseSimulation2)
|
||||
{
|
||||
CSimulation2& sim = *g_Game->GetSimulation2();
|
||||
entity_id_t ent = sim.AddEntity(m_TemplateName, m_EntityID);
|
||||
if (ent == INVALID_ENTITY)
|
||||
LOGERROR(L"Failed to load entity template '%ls'", m_TemplateName.c_str());
|
||||
else
|
||||
{
|
||||
CmpPtr<ICmpPosition> cmpPosition(sim, m_EntityID);
|
||||
if (!cmpPosition.null())
|
||||
{
|
||||
cmpPosition->JumpTo(m_Pos.X, m_Pos.Z);
|
||||
cmpPosition->SetXZRotation(m_Rot.X, m_Rot.Z);
|
||||
cmpPosition->SetYRotation(m_Rot.Y);
|
||||
}
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwner(sim, m_EntityID);
|
||||
if (!cmpOwner.null())
|
||||
cmpOwner->SetOwner(m_Owner);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_FrozenEntity.get())
|
||||
{
|
||||
CEntity* entity = m_FrozenEntity->Thaw();
|
||||
|
@ -188,10 +188,6 @@ void ViewGame::Update(float frameLength)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up any entities destroyed during simulation update
|
||||
if (g_UseSimulation2)
|
||||
g_Game->GetSimulation2()->FlushDestroyedEntities();
|
||||
|
||||
// Interpolate the graphics - we only want to do this once per visual frame,
|
||||
// not in every call to g_Game->Update
|
||||
g_Game->GetSimulation()->Interpolate(actualFrameLength);
|
||||
|
Loading…
Reference in New Issue
Block a user