Set svn:eol-style=native
This was SVN commit r6816.
This commit is contained in:
parent
ce3994fc7a
commit
1e3cd00c72
@ -1,172 +1,172 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "XMLFix.h"
|
||||
|
||||
#include "CommonConvert.h"
|
||||
|
||||
#include "FUtils/FUXmlParser.h"
|
||||
|
||||
/*
|
||||
|
||||
Things that are fixed here:
|
||||
|
||||
----
|
||||
|
||||
3ds Max "file://" image URLs
|
||||
|
||||
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
|
||||
|
||||
Problem: /COLLADA/library_images/image/init_from = "file://" which crashes some versions of FCollada
|
||||
|
||||
Fix: Delete the whole library_images subtree, since we never use it anyway.
|
||||
Then delete library_effects and library_materials too, to avoid broken references.
|
||||
|
||||
----
|
||||
|
||||
3ds Max broken material references
|
||||
|
||||
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
|
||||
|
||||
Problem: /COLLADA/library_visual_scenes/.../instance_material/@target sometimes
|
||||
refers to non-existent material IDs.
|
||||
|
||||
Fix: Delete the whole bind_material subtree, since we never use it anyway.
|
||||
|
||||
----
|
||||
|
||||
*/
|
||||
|
||||
static xmlNode* findChildElement(xmlNode* node, const char* name)
|
||||
{
|
||||
for (xmlNode* child = node->children; child; child = child->next)
|
||||
{
|
||||
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, name) == 0)
|
||||
return child;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool applyFBXFixesNode(xmlNode* node)
|
||||
{
|
||||
bool changed = false;
|
||||
for (xmlNode* child = node->children; child; child = child->next)
|
||||
{
|
||||
if (child->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((const char*)child->name, "node") == 0)
|
||||
{
|
||||
if (applyFBXFixesNode(child))
|
||||
changed = true;
|
||||
}
|
||||
else if (strcmp((const char*)child->name, "instance_geometry") == 0)
|
||||
{
|
||||
xmlNode* bind_material = findChildElement(child, "bind_material");
|
||||
if (! bind_material) continue;
|
||||
Log(LOG_INFO, "Found a bind_material to delete");
|
||||
xmlUnlinkNode(bind_material);
|
||||
xmlFreeNode(bind_material);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool applyFBXFixes(xmlNode* root)
|
||||
{
|
||||
Log(LOG_INFO, "Applying fixes for 3ds Max exporter");
|
||||
|
||||
bool changed = false;
|
||||
|
||||
xmlNode* library_images = findChildElement(root, "library_images");
|
||||
if (library_images)
|
||||
{
|
||||
Log(LOG_INFO, "Found library_images to delete");
|
||||
xmlUnlinkNode(library_images);
|
||||
xmlFreeNode(library_images);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
xmlNode* library_materials = findChildElement(root, "library_materials");
|
||||
if (library_materials)
|
||||
{
|
||||
Log(LOG_INFO, "Found library_materials to delete");
|
||||
xmlUnlinkNode(library_materials);
|
||||
xmlFreeNode(library_materials);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
xmlNode* library_effects = findChildElement(root, "library_effects");
|
||||
if (library_effects)
|
||||
{
|
||||
Log(LOG_INFO, "Found library_effects to delete");
|
||||
xmlUnlinkNode(library_effects);
|
||||
xmlFreeNode(library_effects);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
xmlNode* library_visual_scenes = findChildElement(root, "library_visual_scenes");
|
||||
if (library_visual_scenes) // (Assume there's only one of these)
|
||||
{
|
||||
xmlNode* visual_scene = findChildElement(library_visual_scenes, "visual_scene");
|
||||
if (visual_scene) // (Assume there's only one of these)
|
||||
{
|
||||
for (xmlNode* child = visual_scene->children; child; child = child->next)
|
||||
{
|
||||
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, "node") == 0)
|
||||
if (applyFBXFixesNode(child))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool processDocument(xmlNode* root)
|
||||
{
|
||||
xmlNode* asset = findChildElement(root, "asset");
|
||||
if (! asset) return false;
|
||||
xmlNode* contributor = findChildElement(asset, "contributor");
|
||||
if (! contributor) return false;
|
||||
xmlNode* authoring_tool = findChildElement(contributor, "authoring_tool");
|
||||
if (! authoring_tool) return false;
|
||||
|
||||
xmlNode* authoring_tool_text = authoring_tool->children;
|
||||
if (! authoring_tool_text) return false;
|
||||
if (authoring_tool_text->type != XML_TEXT_NODE) return false;
|
||||
xmlChar* toolname = authoring_tool_text->content;
|
||||
Log(LOG_INFO, "Authoring tool: %s", toolname);
|
||||
if (strcmp((const char*)toolname, "FBX COLLADA exporter") == 0)
|
||||
return applyFBXFixes(root);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void FixBrokenXML(const char* text, const char** out, size_t* outSize)
|
||||
{
|
||||
Log(LOG_INFO, "Running FixBrokenXML");
|
||||
|
||||
size_t textSize = strlen(text);
|
||||
xmlDocPtr doc = xmlParseMemory(text, textSize);
|
||||
|
||||
xmlNode* root = xmlDocGetRootElement(doc);
|
||||
if (root && processDocument(root))
|
||||
{
|
||||
// Reserialising the document, then parsing it again inside FCollada, is a bit ugly;
|
||||
// but it's the only way I can see to make it work through FCollada's public API
|
||||
xmlChar* mem = NULL;
|
||||
int size = -1;
|
||||
xmlDocDumpFormatMemory(doc, &mem, &size, 0);
|
||||
*out = (const char*)mem;
|
||||
*outSize = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = text;
|
||||
*outSize = textSize;
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "XMLFix.h"
|
||||
|
||||
#include "CommonConvert.h"
|
||||
|
||||
#include "FUtils/FUXmlParser.h"
|
||||
|
||||
/*
|
||||
|
||||
Things that are fixed here:
|
||||
|
||||
----
|
||||
|
||||
3ds Max "file://" image URLs
|
||||
|
||||
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
|
||||
|
||||
Problem: /COLLADA/library_images/image/init_from = "file://" which crashes some versions of FCollada
|
||||
|
||||
Fix: Delete the whole library_images subtree, since we never use it anyway.
|
||||
Then delete library_effects and library_materials too, to avoid broken references.
|
||||
|
||||
----
|
||||
|
||||
3ds Max broken material references
|
||||
|
||||
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
|
||||
|
||||
Problem: /COLLADA/library_visual_scenes/.../instance_material/@target sometimes
|
||||
refers to non-existent material IDs.
|
||||
|
||||
Fix: Delete the whole bind_material subtree, since we never use it anyway.
|
||||
|
||||
----
|
||||
|
||||
*/
|
||||
|
||||
static xmlNode* findChildElement(xmlNode* node, const char* name)
|
||||
{
|
||||
for (xmlNode* child = node->children; child; child = child->next)
|
||||
{
|
||||
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, name) == 0)
|
||||
return child;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool applyFBXFixesNode(xmlNode* node)
|
||||
{
|
||||
bool changed = false;
|
||||
for (xmlNode* child = node->children; child; child = child->next)
|
||||
{
|
||||
if (child->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((const char*)child->name, "node") == 0)
|
||||
{
|
||||
if (applyFBXFixesNode(child))
|
||||
changed = true;
|
||||
}
|
||||
else if (strcmp((const char*)child->name, "instance_geometry") == 0)
|
||||
{
|
||||
xmlNode* bind_material = findChildElement(child, "bind_material");
|
||||
if (! bind_material) continue;
|
||||
Log(LOG_INFO, "Found a bind_material to delete");
|
||||
xmlUnlinkNode(bind_material);
|
||||
xmlFreeNode(bind_material);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool applyFBXFixes(xmlNode* root)
|
||||
{
|
||||
Log(LOG_INFO, "Applying fixes for 3ds Max exporter");
|
||||
|
||||
bool changed = false;
|
||||
|
||||
xmlNode* library_images = findChildElement(root, "library_images");
|
||||
if (library_images)
|
||||
{
|
||||
Log(LOG_INFO, "Found library_images to delete");
|
||||
xmlUnlinkNode(library_images);
|
||||
xmlFreeNode(library_images);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
xmlNode* library_materials = findChildElement(root, "library_materials");
|
||||
if (library_materials)
|
||||
{
|
||||
Log(LOG_INFO, "Found library_materials to delete");
|
||||
xmlUnlinkNode(library_materials);
|
||||
xmlFreeNode(library_materials);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
xmlNode* library_effects = findChildElement(root, "library_effects");
|
||||
if (library_effects)
|
||||
{
|
||||
Log(LOG_INFO, "Found library_effects to delete");
|
||||
xmlUnlinkNode(library_effects);
|
||||
xmlFreeNode(library_effects);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
xmlNode* library_visual_scenes = findChildElement(root, "library_visual_scenes");
|
||||
if (library_visual_scenes) // (Assume there's only one of these)
|
||||
{
|
||||
xmlNode* visual_scene = findChildElement(library_visual_scenes, "visual_scene");
|
||||
if (visual_scene) // (Assume there's only one of these)
|
||||
{
|
||||
for (xmlNode* child = visual_scene->children; child; child = child->next)
|
||||
{
|
||||
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, "node") == 0)
|
||||
if (applyFBXFixesNode(child))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool processDocument(xmlNode* root)
|
||||
{
|
||||
xmlNode* asset = findChildElement(root, "asset");
|
||||
if (! asset) return false;
|
||||
xmlNode* contributor = findChildElement(asset, "contributor");
|
||||
if (! contributor) return false;
|
||||
xmlNode* authoring_tool = findChildElement(contributor, "authoring_tool");
|
||||
if (! authoring_tool) return false;
|
||||
|
||||
xmlNode* authoring_tool_text = authoring_tool->children;
|
||||
if (! authoring_tool_text) return false;
|
||||
if (authoring_tool_text->type != XML_TEXT_NODE) return false;
|
||||
xmlChar* toolname = authoring_tool_text->content;
|
||||
Log(LOG_INFO, "Authoring tool: %s", toolname);
|
||||
if (strcmp((const char*)toolname, "FBX COLLADA exporter") == 0)
|
||||
return applyFBXFixes(root);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void FixBrokenXML(const char* text, const char** out, size_t* outSize)
|
||||
{
|
||||
Log(LOG_INFO, "Running FixBrokenXML");
|
||||
|
||||
size_t textSize = strlen(text);
|
||||
xmlDocPtr doc = xmlParseMemory(text, textSize);
|
||||
|
||||
xmlNode* root = xmlDocGetRootElement(doc);
|
||||
if (root && processDocument(root))
|
||||
{
|
||||
// Reserialising the document, then parsing it again inside FCollada, is a bit ugly;
|
||||
// but it's the only way I can see to make it work through FCollada's public API
|
||||
xmlChar* mem = NULL;
|
||||
int size = -1;
|
||||
xmlDocDumpFormatMemory(doc, &mem, &size, 0);
|
||||
*out = (const char*)mem;
|
||||
*outSize = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = text;
|
||||
*outSize = textSize;
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
#ifndef XMLFIX_INCLUDED
|
||||
#define XMLFIX_INCLUDED
|
||||
|
||||
/**
|
||||
* Fixes some errors in COLLADA XML files that would otherwise prevent
|
||||
* FCollada from loading them successfully.
|
||||
* 'out' is either a new XML document, which must be freed with xmlFree;
|
||||
* otherwise it is equal to 'text' if no changes were made.
|
||||
*/
|
||||
void FixBrokenXML(const char* text, const char** out, size_t* outSize);
|
||||
|
||||
#endif // XMLFIX_INCLUDED
|
||||
#ifndef XMLFIX_INCLUDED
|
||||
#define XMLFIX_INCLUDED
|
||||
|
||||
/**
|
||||
* Fixes some errors in COLLADA XML files that would otherwise prevent
|
||||
* FCollada from loading them successfully.
|
||||
* 'out' is either a new XML document, which must be freed with xmlFree;
|
||||
* otherwise it is equal to 'text' if no changes were made.
|
||||
*/
|
||||
void FixBrokenXML(const char* text, const char** out, size_t* outSize);
|
||||
|
||||
#endif // XMLFIX_INCLUDED
|
||||
|
@ -1,53 +1,53 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : Noise.h
|
||||
* Project : 0 A.D.
|
||||
* Description : 2D and 3D seamless Perlin noise
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html
|
||||
// and http://mrl.nyu.edu/~perlin/paper445.pdf.
|
||||
// Not optimized for speed yet.
|
||||
|
||||
#ifndef INCLUDED_NOISE
|
||||
#define INCLUDED_NOISE
|
||||
|
||||
#include "Vector2D.h"
|
||||
#include "Vector3D.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
class Noise2D
|
||||
{
|
||||
/// Frequency in X and Y
|
||||
int freq;
|
||||
|
||||
/// freq*freq random gradient vectors in the unit cube
|
||||
CVector2D_Maths** grads;
|
||||
public:
|
||||
Noise2D(int freq);
|
||||
~Noise2D();
|
||||
|
||||
/// Evaluate the noise function at a given point
|
||||
float operator() (float x, float y);
|
||||
};
|
||||
|
||||
class Noise3D
|
||||
{
|
||||
/// Frequency in X and Y
|
||||
int freq;
|
||||
|
||||
/// Frequency in Z (vertical frequency)
|
||||
int vfreq;
|
||||
|
||||
/// freq*freq*vfreq random gradient vectors in the unit cube
|
||||
CVector3D*** grads;
|
||||
public:
|
||||
Noise3D(int freq, int vfreq);
|
||||
~Noise3D();
|
||||
|
||||
/// Evaluate the noise function at a given point
|
||||
float operator() (float x, float y, float z);
|
||||
};
|
||||
|
||||
#endif
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : Noise.h
|
||||
* Project : 0 A.D.
|
||||
* Description : 2D and 3D seamless Perlin noise
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html
|
||||
// and http://mrl.nyu.edu/~perlin/paper445.pdf.
|
||||
// Not optimized for speed yet.
|
||||
|
||||
#ifndef INCLUDED_NOISE
|
||||
#define INCLUDED_NOISE
|
||||
|
||||
#include "Vector2D.h"
|
||||
#include "Vector3D.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
class Noise2D
|
||||
{
|
||||
/// Frequency in X and Y
|
||||
int freq;
|
||||
|
||||
/// freq*freq random gradient vectors in the unit cube
|
||||
CVector2D_Maths** grads;
|
||||
public:
|
||||
Noise2D(int freq);
|
||||
~Noise2D();
|
||||
|
||||
/// Evaluate the noise function at a given point
|
||||
float operator() (float x, float y);
|
||||
};
|
||||
|
||||
class Noise3D
|
||||
{
|
||||
/// Frequency in X and Y
|
||||
int freq;
|
||||
|
||||
/// Frequency in Z (vertical frequency)
|
||||
int vfreq;
|
||||
|
||||
/// freq*freq*vfreq random gradient vectors in the unit cube
|
||||
CVector3D*** grads;
|
||||
public:
|
||||
Noise3D(int freq, int vfreq);
|
||||
~Noise3D();
|
||||
|
||||
/// Evaluate the noise function at a given point
|
||||
float operator() (float x, float y, float z);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,68 +1,68 @@
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "maths/Quaternion.h"
|
||||
|
||||
class TestMatrix : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_inverse()
|
||||
{
|
||||
CMatrix3D m;
|
||||
srand(0);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX);
|
||||
}
|
||||
CMatrix3D n;
|
||||
m.GetInverse(n);
|
||||
m *= n;
|
||||
// verify identity has 1s on diagonal and 0 otherwise
|
||||
for (int x = 0; x < 4; ++x)
|
||||
{
|
||||
for (int y = 0; y < 4; ++y)
|
||||
{
|
||||
const float expected = (x==y)? 1.0f : 0.0f;
|
||||
TS_ASSERT_DELTA(m(x,y), expected, 0.0001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_quats()
|
||||
{
|
||||
srand(0);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
CQuaternion q;
|
||||
q.FromEulerAngles(
|
||||
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
|
||||
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
|
||||
-6.28f + 12.56f*(rand()/(float)RAND_MAX)
|
||||
);
|
||||
CMatrix3D m;
|
||||
q.ToMatrix(m);
|
||||
CQuaternion q2 = m.GetRotation();
|
||||
|
||||
// Quaternions (x,y,z,w) and (-x,-y,-z,-w) are equivalent when
|
||||
// interpreted as rotations, so it doesn't matter which we get
|
||||
const bool ok_oneway =
|
||||
feq(q2.m_W, q.m_W) &&
|
||||
feq(q2.m_V.X, q.m_V.X) &&
|
||||
feq(q2.m_V.Y, q.m_V.Y) &&
|
||||
feq(q2.m_V.Z, q.m_V.Z);
|
||||
const bool ok_otherway =
|
||||
feq(q2.m_W, -q.m_W) &&
|
||||
feq(q2.m_V.X, -q.m_V.X) &&
|
||||
feq(q2.m_V.Y, -q.m_V.Y) &&
|
||||
feq(q2.m_V.Z, -q.m_V.Z);
|
||||
TS_ASSERT(ok_oneway ^ ok_otherway);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "maths/Quaternion.h"
|
||||
|
||||
class TestMatrix : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_inverse()
|
||||
{
|
||||
CMatrix3D m;
|
||||
srand(0);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX);
|
||||
}
|
||||
CMatrix3D n;
|
||||
m.GetInverse(n);
|
||||
m *= n;
|
||||
// verify identity has 1s on diagonal and 0 otherwise
|
||||
for (int x = 0; x < 4; ++x)
|
||||
{
|
||||
for (int y = 0; y < 4; ++y)
|
||||
{
|
||||
const float expected = (x==y)? 1.0f : 0.0f;
|
||||
TS_ASSERT_DELTA(m(x,y), expected, 0.0001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_quats()
|
||||
{
|
||||
srand(0);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
CQuaternion q;
|
||||
q.FromEulerAngles(
|
||||
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
|
||||
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
|
||||
-6.28f + 12.56f*(rand()/(float)RAND_MAX)
|
||||
);
|
||||
CMatrix3D m;
|
||||
q.ToMatrix(m);
|
||||
CQuaternion q2 = m.GetRotation();
|
||||
|
||||
// Quaternions (x,y,z,w) and (-x,-y,-z,-w) are equivalent when
|
||||
// interpreted as rotations, so it doesn't matter which we get
|
||||
const bool ok_oneway =
|
||||
feq(q2.m_W, q.m_W) &&
|
||||
feq(q2.m_V.X, q.m_V.X) &&
|
||||
feq(q2.m_V.Y, q.m_V.Y) &&
|
||||
feq(q2.m_V.Z, q.m_V.Z);
|
||||
const bool ok_otherway =
|
||||
feq(q2.m_W, -q.m_W) &&
|
||||
feq(q2.m_V.X, -q.m_V.X) &&
|
||||
feq(q2.m_V.Y, -q.m_V.Y) &&
|
||||
feq(q2.m_V.Z, -q.m_V.Z);
|
||||
TS_ASSERT(ok_oneway ^ ok_otherway);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,161 +1,161 @@
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetClient.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network client class interface file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETCLIENT_H
|
||||
#define NETCLIENT_H
|
||||
|
||||
// INCLUDES
|
||||
#include "NetSession.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "simulation/TurnManager.h"
|
||||
#include "simulation/ScriptObject.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "ps/scripting/JSMap.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
// DECLARATIONS
|
||||
enum
|
||||
{
|
||||
NCS_CONNECT = 200,
|
||||
NCS_HANDSHAKE = 300,
|
||||
NCS_AUTHENTICATE = 400,
|
||||
NCS_PREGAME = 500,
|
||||
NCS_INGAME = 600
|
||||
};
|
||||
|
||||
class CPlayerSlot;
|
||||
class CPlayer;
|
||||
class CGame;
|
||||
class CGameAttributes;
|
||||
class CServerPlayer;
|
||||
|
||||
//typedef std::map< uint, CStr > PlayerMap;
|
||||
typedef std::map< uint, CServerPlayer* > PlayerMap;
|
||||
|
||||
/*
|
||||
CLASS : CServerPlayer
|
||||
DESCRIPTION :
|
||||
NOTES :
|
||||
*/
|
||||
class CServerPlayer : public CJSObject< CServerPlayer >
|
||||
{
|
||||
public:
|
||||
|
||||
CServerPlayer( uint sessionID, const CStr& nickname );
|
||||
~CServerPlayer( void );
|
||||
|
||||
static void ScriptingInit( void );
|
||||
uint GetSessionID( void ) const { return m_SessionID; }
|
||||
const CStr GetNickname( void ) const { return m_Nickname; }
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
CServerPlayer( const CServerPlayer& );
|
||||
CServerPlayer& operator=( const CServerPlayer& );
|
||||
|
||||
uint m_SessionID; // Player session ID
|
||||
CStr m_Nickname; // Player nickname
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetClient
|
||||
DESCRIPTION :
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetClient: public CNetHost,
|
||||
public CJSObject<CNetClient>,
|
||||
protected CTurnManager
|
||||
{
|
||||
public:
|
||||
|
||||
CNetClient( CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
~CNetClient( void );
|
||||
|
||||
bool CreateSession ( void );
|
||||
void OnPlayer ( uint ID, const CStr& name );
|
||||
void OnPlayerLeave ( uint ID );
|
||||
|
||||
/**
|
||||
* Returns true indicating the host acts as a client
|
||||
*
|
||||
* @return Always true
|
||||
*/
|
||||
virtual bool IsClient( void ) const { return true; }
|
||||
|
||||
// Get a pointer to our player
|
||||
CPlayer* GetLocalPlayer();
|
||||
|
||||
CJSMap< PlayerMap > m_JsPlayers;
|
||||
|
||||
CStr m_Nickname;
|
||||
CStr m_Password;
|
||||
//int m_SessionID;
|
||||
|
||||
CPlayerSlot *m_pLocalPlayerSlot;
|
||||
CGame *m_pGame;
|
||||
CGameAttributes *m_pGameAttributes;
|
||||
|
||||
// Are we currently in a locally-yet-unsimulated turn?
|
||||
// This is set to true when we receive a command batch and cleared in NewTurn().
|
||||
// The server also ensures that it does not send a new turn until we ack one.
|
||||
bool m_TurnPending;
|
||||
|
||||
// Mutex for accessing batches
|
||||
CMutex m_Mutex;
|
||||
|
||||
// JS event scripts
|
||||
CScriptObject m_OnStartGame;
|
||||
CScriptObject m_OnChat;
|
||||
CScriptObject m_OnConnectComplete;
|
||||
CScriptObject m_OnDisconnect;
|
||||
CScriptObject m_OnPlayerJoin;
|
||||
CScriptObject m_OnPlayerLeave;
|
||||
|
||||
static void ScriptingInit( void );
|
||||
int StartGame( void );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool SetupSession ( CNetSession* pSession );
|
||||
virtual bool HandleConnect ( CNetSession* pSession );
|
||||
virtual bool HandleDisconnect ( CNetSession *pSession );
|
||||
|
||||
virtual void NewTurn ( void );
|
||||
virtual bool NewTurnReady ( void ) { return m_TurnPending; }
|
||||
virtual void QueueLocalCommand ( CNetMessage* pMessage );
|
||||
void QueueIncomingMessage ( CNetMessage* pMessage );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetClient( const CNetClient& );
|
||||
CNetClient& operator=( const CNetClient& );
|
||||
|
||||
static bool OnError ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnStartGame ( void* pContext, CFsmEvent* pEvent );
|
||||
|
||||
|
||||
bool SetupConnection( JSContext *cx, uintN argc, jsval *argv );
|
||||
|
||||
//CNetSession* m_Session; // Server session
|
||||
PlayerMap m_Players; // List of online players
|
||||
};
|
||||
|
||||
extern CNetClient *g_NetClient;
|
||||
|
||||
#endif // NETCLIENT_H
|
||||
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetClient.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network client class interface file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETCLIENT_H
|
||||
#define NETCLIENT_H
|
||||
|
||||
// INCLUDES
|
||||
#include "NetSession.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "simulation/TurnManager.h"
|
||||
#include "simulation/ScriptObject.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "ps/scripting/JSMap.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
// DECLARATIONS
|
||||
enum
|
||||
{
|
||||
NCS_CONNECT = 200,
|
||||
NCS_HANDSHAKE = 300,
|
||||
NCS_AUTHENTICATE = 400,
|
||||
NCS_PREGAME = 500,
|
||||
NCS_INGAME = 600
|
||||
};
|
||||
|
||||
class CPlayerSlot;
|
||||
class CPlayer;
|
||||
class CGame;
|
||||
class CGameAttributes;
|
||||
class CServerPlayer;
|
||||
|
||||
//typedef std::map< uint, CStr > PlayerMap;
|
||||
typedef std::map< uint, CServerPlayer* > PlayerMap;
|
||||
|
||||
/*
|
||||
CLASS : CServerPlayer
|
||||
DESCRIPTION :
|
||||
NOTES :
|
||||
*/
|
||||
class CServerPlayer : public CJSObject< CServerPlayer >
|
||||
{
|
||||
public:
|
||||
|
||||
CServerPlayer( uint sessionID, const CStr& nickname );
|
||||
~CServerPlayer( void );
|
||||
|
||||
static void ScriptingInit( void );
|
||||
uint GetSessionID( void ) const { return m_SessionID; }
|
||||
const CStr GetNickname( void ) const { return m_Nickname; }
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
CServerPlayer( const CServerPlayer& );
|
||||
CServerPlayer& operator=( const CServerPlayer& );
|
||||
|
||||
uint m_SessionID; // Player session ID
|
||||
CStr m_Nickname; // Player nickname
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetClient
|
||||
DESCRIPTION :
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetClient: public CNetHost,
|
||||
public CJSObject<CNetClient>,
|
||||
protected CTurnManager
|
||||
{
|
||||
public:
|
||||
|
||||
CNetClient( CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
~CNetClient( void );
|
||||
|
||||
bool CreateSession ( void );
|
||||
void OnPlayer ( uint ID, const CStr& name );
|
||||
void OnPlayerLeave ( uint ID );
|
||||
|
||||
/**
|
||||
* Returns true indicating the host acts as a client
|
||||
*
|
||||
* @return Always true
|
||||
*/
|
||||
virtual bool IsClient( void ) const { return true; }
|
||||
|
||||
// Get a pointer to our player
|
||||
CPlayer* GetLocalPlayer();
|
||||
|
||||
CJSMap< PlayerMap > m_JsPlayers;
|
||||
|
||||
CStr m_Nickname;
|
||||
CStr m_Password;
|
||||
//int m_SessionID;
|
||||
|
||||
CPlayerSlot *m_pLocalPlayerSlot;
|
||||
CGame *m_pGame;
|
||||
CGameAttributes *m_pGameAttributes;
|
||||
|
||||
// Are we currently in a locally-yet-unsimulated turn?
|
||||
// This is set to true when we receive a command batch and cleared in NewTurn().
|
||||
// The server also ensures that it does not send a new turn until we ack one.
|
||||
bool m_TurnPending;
|
||||
|
||||
// Mutex for accessing batches
|
||||
CMutex m_Mutex;
|
||||
|
||||
// JS event scripts
|
||||
CScriptObject m_OnStartGame;
|
||||
CScriptObject m_OnChat;
|
||||
CScriptObject m_OnConnectComplete;
|
||||
CScriptObject m_OnDisconnect;
|
||||
CScriptObject m_OnPlayerJoin;
|
||||
CScriptObject m_OnPlayerLeave;
|
||||
|
||||
static void ScriptingInit( void );
|
||||
int StartGame( void );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool SetupSession ( CNetSession* pSession );
|
||||
virtual bool HandleConnect ( CNetSession* pSession );
|
||||
virtual bool HandleDisconnect ( CNetSession *pSession );
|
||||
|
||||
virtual void NewTurn ( void );
|
||||
virtual bool NewTurnReady ( void ) { return m_TurnPending; }
|
||||
virtual void QueueLocalCommand ( CNetMessage* pMessage );
|
||||
void QueueIncomingMessage ( CNetMessage* pMessage );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetClient( const CNetClient& );
|
||||
CNetClient& operator=( const CNetClient& );
|
||||
|
||||
static bool OnError ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnStartGame ( void* pContext, CFsmEvent* pEvent );
|
||||
|
||||
|
||||
bool SetupConnection( JSContext *cx, uintN argc, jsval *argv );
|
||||
|
||||
//CNetSession* m_Session; // Server session
|
||||
PlayerMap m_Players; // List of online players
|
||||
};
|
||||
|
||||
extern CNetClient *g_NetClient;
|
||||
|
||||
#endif // NETCLIENT_H
|
||||
|
||||
|
@ -1,147 +1,147 @@
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetJsEvents.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Definitions for JavaScript events used by the network
|
||||
* system
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETJSEVENTS_H
|
||||
#define NETJSEVENTS_H
|
||||
|
||||
// INCLUDES
|
||||
#include "NetSession.h"
|
||||
#include "scripting/DOMEvent.h"
|
||||
|
||||
// DEFINES
|
||||
enum NetJsEvents
|
||||
{
|
||||
JS_EVENT_CLIENT_CONNECT,
|
||||
JS_EVENT_CONNECT_COMPLETE,
|
||||
JS_EVENT_CLIENT_DISCONNECT,
|
||||
JS_EVENT_DISCONNECT,
|
||||
JS_EVENT_START_GAME,
|
||||
JS_EVENT_CHAT,
|
||||
JS_EVENT_LAST
|
||||
};
|
||||
|
||||
class CStartGameEvent: public CScriptEvent
|
||||
{
|
||||
public:
|
||||
CStartGameEvent():
|
||||
CScriptEvent(L"startGame", JS_EVENT_START_GAME, false)
|
||||
{}
|
||||
};
|
||||
|
||||
class CChatEvent: public CScriptEvent
|
||||
{
|
||||
CStr m_Sender;
|
||||
CStr m_Message;
|
||||
|
||||
public:
|
||||
CChatEvent(const CStr& sender, const CStr& message):
|
||||
CScriptEvent(L"chat", JS_EVENT_CHAT, false ),
|
||||
m_Sender(sender),
|
||||
m_Message(message)
|
||||
{
|
||||
AddLocalProperty(L"sender", &m_Sender, true);
|
||||
AddLocalProperty(L"message", &m_Message, true);
|
||||
}
|
||||
};
|
||||
|
||||
class CConnectCompleteEvent: public CScriptEvent
|
||||
{
|
||||
CStr m_Message;
|
||||
bool m_Success;
|
||||
|
||||
public:
|
||||
CConnectCompleteEvent(const CStr& message, bool success):
|
||||
CScriptEvent(L"connectComplete", JS_EVENT_CONNECT_COMPLETE, false),
|
||||
m_Message(message),
|
||||
m_Success(success)
|
||||
{
|
||||
AddLocalProperty(L"message", &m_Message, true);
|
||||
AddLocalProperty(L"success", &m_Success, true);
|
||||
}
|
||||
};
|
||||
|
||||
class CDisconnectEvent: public CScriptEvent
|
||||
{
|
||||
CStrW m_Message;
|
||||
|
||||
public:
|
||||
CDisconnectEvent(const CStr& message):
|
||||
CScriptEvent(L"disconnect", JS_EVENT_DISCONNECT, false),
|
||||
m_Message(message)
|
||||
{
|
||||
AddLocalProperty(L"message", &m_Message, true);
|
||||
}
|
||||
};
|
||||
|
||||
class CClientConnectDisconnectCommon: public CScriptEvent
|
||||
{
|
||||
uint m_SessionID;
|
||||
CStr m_Name;
|
||||
CNetSession *m_Session;
|
||||
|
||||
public:
|
||||
|
||||
CClientConnectDisconnectCommon(const wchar_t* UNUSED(eventName), int UNUSED(eventType),
|
||||
int sessionID, const CStr& name, CNetSession* pSession)
|
||||
: CScriptEvent(L"clientConnect", JS_EVENT_CLIENT_CONNECT, false),
|
||||
m_SessionID(sessionID),
|
||||
m_Name(name),
|
||||
m_Session(pSession)
|
||||
{
|
||||
AddLocalProperty(L"id", &m_SessionID, true);
|
||||
AddLocalProperty(L"name", &m_Name, true);
|
||||
if (m_Session)
|
||||
AddLocalProperty(L"session", &m_Session, true);
|
||||
}
|
||||
};
|
||||
|
||||
struct CClientConnectEvent: public CClientConnectDisconnectCommon
|
||||
{
|
||||
CClientConnectEvent(int sessionID, const CStr& name):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientConnect",
|
||||
JS_EVENT_CLIENT_CONNECT,
|
||||
sessionID,
|
||||
name,
|
||||
NULL)
|
||||
{}
|
||||
|
||||
CClientConnectEvent(CNetSession *pSession):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientConnect",
|
||||
JS_EVENT_CLIENT_CONNECT,
|
||||
pSession->GetID(),
|
||||
pSession->GetName(),
|
||||
pSession)
|
||||
{}
|
||||
};
|
||||
|
||||
struct CClientDisconnectEvent: public CClientConnectDisconnectCommon
|
||||
{
|
||||
CClientDisconnectEvent(int sessionID, const CStr& name):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientDisconnect",
|
||||
JS_EVENT_CLIENT_DISCONNECT,
|
||||
sessionID,
|
||||
name,
|
||||
NULL)
|
||||
{}
|
||||
|
||||
CClientDisconnectEvent(CNetSession *pSession):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientDisconnect",
|
||||
JS_EVENT_CLIENT_DISCONNECT,
|
||||
pSession->GetID(),
|
||||
pSession->GetName(),
|
||||
pSession)
|
||||
{}
|
||||
};
|
||||
|
||||
#endif // NETJSEVENTS_H
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetJsEvents.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Definitions for JavaScript events used by the network
|
||||
* system
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETJSEVENTS_H
|
||||
#define NETJSEVENTS_H
|
||||
|
||||
// INCLUDES
|
||||
#include "NetSession.h"
|
||||
#include "scripting/DOMEvent.h"
|
||||
|
||||
// DEFINES
|
||||
enum NetJsEvents
|
||||
{
|
||||
JS_EVENT_CLIENT_CONNECT,
|
||||
JS_EVENT_CONNECT_COMPLETE,
|
||||
JS_EVENT_CLIENT_DISCONNECT,
|
||||
JS_EVENT_DISCONNECT,
|
||||
JS_EVENT_START_GAME,
|
||||
JS_EVENT_CHAT,
|
||||
JS_EVENT_LAST
|
||||
};
|
||||
|
||||
class CStartGameEvent: public CScriptEvent
|
||||
{
|
||||
public:
|
||||
CStartGameEvent():
|
||||
CScriptEvent(L"startGame", JS_EVENT_START_GAME, false)
|
||||
{}
|
||||
};
|
||||
|
||||
class CChatEvent: public CScriptEvent
|
||||
{
|
||||
CStr m_Sender;
|
||||
CStr m_Message;
|
||||
|
||||
public:
|
||||
CChatEvent(const CStr& sender, const CStr& message):
|
||||
CScriptEvent(L"chat", JS_EVENT_CHAT, false ),
|
||||
m_Sender(sender),
|
||||
m_Message(message)
|
||||
{
|
||||
AddLocalProperty(L"sender", &m_Sender, true);
|
||||
AddLocalProperty(L"message", &m_Message, true);
|
||||
}
|
||||
};
|
||||
|
||||
class CConnectCompleteEvent: public CScriptEvent
|
||||
{
|
||||
CStr m_Message;
|
||||
bool m_Success;
|
||||
|
||||
public:
|
||||
CConnectCompleteEvent(const CStr& message, bool success):
|
||||
CScriptEvent(L"connectComplete", JS_EVENT_CONNECT_COMPLETE, false),
|
||||
m_Message(message),
|
||||
m_Success(success)
|
||||
{
|
||||
AddLocalProperty(L"message", &m_Message, true);
|
||||
AddLocalProperty(L"success", &m_Success, true);
|
||||
}
|
||||
};
|
||||
|
||||
class CDisconnectEvent: public CScriptEvent
|
||||
{
|
||||
CStrW m_Message;
|
||||
|
||||
public:
|
||||
CDisconnectEvent(const CStr& message):
|
||||
CScriptEvent(L"disconnect", JS_EVENT_DISCONNECT, false),
|
||||
m_Message(message)
|
||||
{
|
||||
AddLocalProperty(L"message", &m_Message, true);
|
||||
}
|
||||
};
|
||||
|
||||
class CClientConnectDisconnectCommon: public CScriptEvent
|
||||
{
|
||||
uint m_SessionID;
|
||||
CStr m_Name;
|
||||
CNetSession *m_Session;
|
||||
|
||||
public:
|
||||
|
||||
CClientConnectDisconnectCommon(const wchar_t* UNUSED(eventName), int UNUSED(eventType),
|
||||
int sessionID, const CStr& name, CNetSession* pSession)
|
||||
: CScriptEvent(L"clientConnect", JS_EVENT_CLIENT_CONNECT, false),
|
||||
m_SessionID(sessionID),
|
||||
m_Name(name),
|
||||
m_Session(pSession)
|
||||
{
|
||||
AddLocalProperty(L"id", &m_SessionID, true);
|
||||
AddLocalProperty(L"name", &m_Name, true);
|
||||
if (m_Session)
|
||||
AddLocalProperty(L"session", &m_Session, true);
|
||||
}
|
||||
};
|
||||
|
||||
struct CClientConnectEvent: public CClientConnectDisconnectCommon
|
||||
{
|
||||
CClientConnectEvent(int sessionID, const CStr& name):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientConnect",
|
||||
JS_EVENT_CLIENT_CONNECT,
|
||||
sessionID,
|
||||
name,
|
||||
NULL)
|
||||
{}
|
||||
|
||||
CClientConnectEvent(CNetSession *pSession):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientConnect",
|
||||
JS_EVENT_CLIENT_CONNECT,
|
||||
pSession->GetID(),
|
||||
pSession->GetName(),
|
||||
pSession)
|
||||
{}
|
||||
};
|
||||
|
||||
struct CClientDisconnectEvent: public CClientConnectDisconnectCommon
|
||||
{
|
||||
CClientDisconnectEvent(int sessionID, const CStr& name):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientDisconnect",
|
||||
JS_EVENT_CLIENT_DISCONNECT,
|
||||
sessionID,
|
||||
name,
|
||||
NULL)
|
||||
{}
|
||||
|
||||
CClientDisconnectEvent(CNetSession *pSession):
|
||||
CClientConnectDisconnectCommon(
|
||||
L"clientDisconnect",
|
||||
JS_EVENT_CLIENT_DISCONNECT,
|
||||
pSession->GetID(),
|
||||
pSession->GetName(),
|
||||
pSession)
|
||||
{}
|
||||
};
|
||||
|
||||
#endif // NETJSEVENTS_H
|
||||
|
||||
|
@ -1,263 +1,263 @@
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetMessages.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : The list of messages used by the network subsystem
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETMESSAGES_H
|
||||
#define NETMESSAGES_H
|
||||
|
||||
// INCLUDES
|
||||
#include "ps/CStr.h"
|
||||
#include "scripting/JSSerialization.h"
|
||||
#include "simulation/EntityHandles.h"
|
||||
|
||||
// DEFINES
|
||||
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
|
||||
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
|
||||
#define PS_PROTOCOL_VERSION 0x01010002 // Arbitrary protocol
|
||||
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
|
||||
|
||||
// Defines the list of message types. The order of the list must not change
|
||||
// The message types having a negative value are used internally and not sent
|
||||
// over the network. The message types used for network communication have
|
||||
// positive values.
|
||||
enum NetMessageType
|
||||
{
|
||||
NMT_ERROR = -256, // Delivery of error states
|
||||
NMT_CONNECT_COMPLETE, // Connection is complete
|
||||
NMT_CLOSE_REQUEST, // Close connection request
|
||||
NMT_INVALID = 0, // Invalid message
|
||||
NMT_SERVER_HANDSHAKE, // Handshake stage
|
||||
NMT_CLIENT_HANDSHAKE,
|
||||
NMT_SERVER_HANDSHAKE_RESPONSE,
|
||||
NMT_AUTHENTICATE, // Authentication stage
|
||||
NMT_AUTHENTICATE_RESULT,
|
||||
NMT_CHAT, // Common chat message
|
||||
NMT_PLAYER_JOIN, // Pre-game stage
|
||||
NMT_PLAYER_LEAVE,
|
||||
NMT_GAME_SETUP,
|
||||
NMT_ASSIGN_PLAYER_SLOT,
|
||||
NMT_PLAYER_CONFIG,
|
||||
NMT_FILES_REQUIRED,
|
||||
NMT_FILE_REQUEST,
|
||||
NMT_FILE_CHUNK,
|
||||
NMT_FILE_CHUNK_ACK,
|
||||
NMT_FILE_PROGRESS,
|
||||
NMT_GAME_START,
|
||||
NMT_END_COMMAND_BATCH, // In-game stage
|
||||
NMT_GOTO,
|
||||
NMT_COMMAND_FIRST = NMT_GOTO,
|
||||
NMT_PATROL,
|
||||
NMT_ADD_WAYPOINT,
|
||||
NMT_CONTACT_ACTION,
|
||||
NMT_PRODUCE,
|
||||
NMT_PLACE_OBJECT,
|
||||
NMT_REMOVE_OBJECT,
|
||||
NMT_RUN,
|
||||
NMT_SET_RALLY_POINT,
|
||||
NMT_SET_STANCE,
|
||||
NMT_NOTIFY_REQUEST,
|
||||
NMT_FORMATION_GOTO,
|
||||
NMT_FORMATION_CONTACT_ACTION,
|
||||
NMT_COMMAND_LAST,
|
||||
NMT_LAST // Last message in the list
|
||||
};
|
||||
|
||||
// Authentication result codes
|
||||
enum AuthenticateResultCode
|
||||
{
|
||||
ARC_OK,
|
||||
ARC_PASSWORD_INVALID,
|
||||
ARC_NICK_TAKEN,
|
||||
ARC_NICK_INVALID,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHAT_RECIPIENT_FIRST = 0xFFFD,
|
||||
CHAT_RECIPIENT_ENEMIES = 0xFFFD,
|
||||
CHAT_RECIPIENT_ALLIES = 0xFFFE,
|
||||
CHAT_RECIPIENT_ALL = 0xFFFF
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ASSIGN_OPEN,
|
||||
ASSIGN_CLOSED,
|
||||
ASSIGN_AI,
|
||||
ASSIGN_SESSION
|
||||
};
|
||||
|
||||
#endif // NETMESSAGES_H
|
||||
|
||||
#ifdef CREATING_NMT
|
||||
|
||||
#define ALLNETMSGS_DONT_CREATE_NMTS
|
||||
#define START_NMT_CLASS_(_nm, _message) START_NMT_CLASS(C##_nm##Message, _message)
|
||||
#define DERIVE_NMT_CLASS_(_base, _nm, _message) START_NMT_CLASS_DERIVED(C ## _base ## Message, C ## _nm ## Message, _message)
|
||||
|
||||
START_NMTS()
|
||||
|
||||
START_NMT_CLASS_(SrvHandshake, NMT_SERVER_HANDSHAKE)
|
||||
NMT_FIELD_INT(m_Magic, u32, 4)
|
||||
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
|
||||
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(CliHandshake,NMT_CLIENT_HANDSHAKE)
|
||||
NMT_FIELD_INT(m_MagicResponse, u32, 4)
|
||||
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
|
||||
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(SrvHandshakeResponse, NMT_SERVER_HANDSHAKE_RESPONSE)
|
||||
NMT_FIELD_INT(m_UseProtocolVersion, u32, 4)
|
||||
NMT_FIELD_INT(m_Flags, u32, 4)
|
||||
NMT_FIELD(CStrW, m_Message)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Authenticate, NMT_AUTHENTICATE)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
//NMT_FIELD(CPasswordHash, m_Password)
|
||||
NMT_FIELD(CStrW, m_Password)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(AuthenticateResult, NMT_AUTHENTICATE_RESULT)
|
||||
NMT_FIELD_INT(m_Code, u32, 4)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2)
|
||||
NMT_FIELD(CStrW, m_Message)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Chat, NMT_CHAT)
|
||||
NMT_FIELD(CStrW, m_Sender)
|
||||
NMT_FIELD_INT(m_Recipient, u32, 2)
|
||||
NMT_FIELD(CStrW, m_Message)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(PlayerJoin, NMT_PLAYER_JOIN)
|
||||
NMT_START_ARRAY(m_Clients)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2)
|
||||
NMT_FIELD(CStr, m_Name)
|
||||
NMT_END_ARRAY()
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(PlayerLeave, NMT_PLAYER_LEAVE)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(GameSetup, NMT_GAME_SETUP)
|
||||
NMT_START_ARRAY(m_Values)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
NMT_FIELD(CStrW, m_Value)
|
||||
NMT_END_ARRAY()
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(AssignPlayerSlot, NMT_ASSIGN_PLAYER_SLOT)
|
||||
NMT_FIELD_INT(m_SlotID, u32, 2)
|
||||
NMT_FIELD_INT(m_Assignment, u32, 1)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2) // Only applicable for PS_ASSIGN_SESSION
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(PlayerConfig, NMT_PLAYER_CONFIG)
|
||||
NMT_FIELD_INT(m_PlayerID, u32, 2)
|
||||
NMT_START_ARRAY(m_Values)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
NMT_FIELD(CStrW, m_Value)
|
||||
NMT_END_ARRAY()
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(GameStart, NMT_GAME_START)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH)
|
||||
NMT_FIELD_INT(m_TurnLength, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Command, NMT_INVALID)
|
||||
NMT_FIELD(CEntityList, m_Entities)
|
||||
NMT_FIELD_INT(m_IsQueued, u32, 1)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Goto, NMT_GOTO)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Run, NMT_RUN)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Patrol, NMT_PATROL)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, AddWaypoint, NMT_ADD_WAYPOINT)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, SetRallyPoint, NMT_SET_RALLY_POINT)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, SetStance, NMT_SET_STANCE)
|
||||
NMT_FIELD(CStrW, m_Stance)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, ContactAction, NMT_CONTACT_ACTION)
|
||||
NMT_FIELD(HEntity, m_Target)
|
||||
NMT_FIELD_INT(m_Action, u32, 4)
|
||||
NMT_FIELD_INT(m_Run, u32, 1)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Produce, NMT_PRODUCE)
|
||||
NMT_FIELD_INT(m_Type, u32, 4)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, PlaceObject, NMT_PLACE_OBJECT)
|
||||
NMT_FIELD(CStrW, m_Template)
|
||||
NMT_FIELD_INT(m_X, u32, 4)
|
||||
NMT_FIELD_INT(m_Y, u32, 4)
|
||||
NMT_FIELD_INT(m_Z, u32, 4)
|
||||
NMT_FIELD_INT(m_Angle, u32, 4) // Orientation angle
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, RemoveObject, NMT_REMOVE_OBJECT)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, NotifyRequest, NMT_NOTIFY_REQUEST)
|
||||
NMT_FIELD(HEntity, m_Target)
|
||||
NMT_FIELD_INT(m_Action, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, FormationGoto, NMT_FORMATION_GOTO)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, FormationContactAction, NMT_FORMATION_CONTACT_ACTION)
|
||||
NMT_FIELD(HEntity, m_Target)
|
||||
NMT_FIELD_INT(m_Action, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
END_NMTS()
|
||||
|
||||
#else
|
||||
#ifndef ALLNETMSGS_DONT_CREATE_NMTS
|
||||
|
||||
# ifdef ALLNETMSGS_IMPLEMENT
|
||||
# define NMT_CREATOR_IMPLEMENT
|
||||
# endif
|
||||
|
||||
# define NMT_CREATE_HEADER_NAME "NetMessages.h"
|
||||
# include "NMTCreator.h"
|
||||
|
||||
#endif // #ifndef ALLNETMSGS_DONT_CREATE_NMTS
|
||||
#endif // #ifdef CREATING_NMT
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetMessages.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : The list of messages used by the network subsystem
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETMESSAGES_H
|
||||
#define NETMESSAGES_H
|
||||
|
||||
// INCLUDES
|
||||
#include "ps/CStr.h"
|
||||
#include "scripting/JSSerialization.h"
|
||||
#include "simulation/EntityHandles.h"
|
||||
|
||||
// DEFINES
|
||||
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
|
||||
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
|
||||
#define PS_PROTOCOL_VERSION 0x01010002 // Arbitrary protocol
|
||||
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
|
||||
|
||||
// Defines the list of message types. The order of the list must not change
|
||||
// The message types having a negative value are used internally and not sent
|
||||
// over the network. The message types used for network communication have
|
||||
// positive values.
|
||||
enum NetMessageType
|
||||
{
|
||||
NMT_ERROR = -256, // Delivery of error states
|
||||
NMT_CONNECT_COMPLETE, // Connection is complete
|
||||
NMT_CLOSE_REQUEST, // Close connection request
|
||||
NMT_INVALID = 0, // Invalid message
|
||||
NMT_SERVER_HANDSHAKE, // Handshake stage
|
||||
NMT_CLIENT_HANDSHAKE,
|
||||
NMT_SERVER_HANDSHAKE_RESPONSE,
|
||||
NMT_AUTHENTICATE, // Authentication stage
|
||||
NMT_AUTHENTICATE_RESULT,
|
||||
NMT_CHAT, // Common chat message
|
||||
NMT_PLAYER_JOIN, // Pre-game stage
|
||||
NMT_PLAYER_LEAVE,
|
||||
NMT_GAME_SETUP,
|
||||
NMT_ASSIGN_PLAYER_SLOT,
|
||||
NMT_PLAYER_CONFIG,
|
||||
NMT_FILES_REQUIRED,
|
||||
NMT_FILE_REQUEST,
|
||||
NMT_FILE_CHUNK,
|
||||
NMT_FILE_CHUNK_ACK,
|
||||
NMT_FILE_PROGRESS,
|
||||
NMT_GAME_START,
|
||||
NMT_END_COMMAND_BATCH, // In-game stage
|
||||
NMT_GOTO,
|
||||
NMT_COMMAND_FIRST = NMT_GOTO,
|
||||
NMT_PATROL,
|
||||
NMT_ADD_WAYPOINT,
|
||||
NMT_CONTACT_ACTION,
|
||||
NMT_PRODUCE,
|
||||
NMT_PLACE_OBJECT,
|
||||
NMT_REMOVE_OBJECT,
|
||||
NMT_RUN,
|
||||
NMT_SET_RALLY_POINT,
|
||||
NMT_SET_STANCE,
|
||||
NMT_NOTIFY_REQUEST,
|
||||
NMT_FORMATION_GOTO,
|
||||
NMT_FORMATION_CONTACT_ACTION,
|
||||
NMT_COMMAND_LAST,
|
||||
NMT_LAST // Last message in the list
|
||||
};
|
||||
|
||||
// Authentication result codes
|
||||
enum AuthenticateResultCode
|
||||
{
|
||||
ARC_OK,
|
||||
ARC_PASSWORD_INVALID,
|
||||
ARC_NICK_TAKEN,
|
||||
ARC_NICK_INVALID,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHAT_RECIPIENT_FIRST = 0xFFFD,
|
||||
CHAT_RECIPIENT_ENEMIES = 0xFFFD,
|
||||
CHAT_RECIPIENT_ALLIES = 0xFFFE,
|
||||
CHAT_RECIPIENT_ALL = 0xFFFF
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ASSIGN_OPEN,
|
||||
ASSIGN_CLOSED,
|
||||
ASSIGN_AI,
|
||||
ASSIGN_SESSION
|
||||
};
|
||||
|
||||
#endif // NETMESSAGES_H
|
||||
|
||||
#ifdef CREATING_NMT
|
||||
|
||||
#define ALLNETMSGS_DONT_CREATE_NMTS
|
||||
#define START_NMT_CLASS_(_nm, _message) START_NMT_CLASS(C##_nm##Message, _message)
|
||||
#define DERIVE_NMT_CLASS_(_base, _nm, _message) START_NMT_CLASS_DERIVED(C ## _base ## Message, C ## _nm ## Message, _message)
|
||||
|
||||
START_NMTS()
|
||||
|
||||
START_NMT_CLASS_(SrvHandshake, NMT_SERVER_HANDSHAKE)
|
||||
NMT_FIELD_INT(m_Magic, u32, 4)
|
||||
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
|
||||
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(CliHandshake,NMT_CLIENT_HANDSHAKE)
|
||||
NMT_FIELD_INT(m_MagicResponse, u32, 4)
|
||||
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
|
||||
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(SrvHandshakeResponse, NMT_SERVER_HANDSHAKE_RESPONSE)
|
||||
NMT_FIELD_INT(m_UseProtocolVersion, u32, 4)
|
||||
NMT_FIELD_INT(m_Flags, u32, 4)
|
||||
NMT_FIELD(CStrW, m_Message)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Authenticate, NMT_AUTHENTICATE)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
//NMT_FIELD(CPasswordHash, m_Password)
|
||||
NMT_FIELD(CStrW, m_Password)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(AuthenticateResult, NMT_AUTHENTICATE_RESULT)
|
||||
NMT_FIELD_INT(m_Code, u32, 4)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2)
|
||||
NMT_FIELD(CStrW, m_Message)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Chat, NMT_CHAT)
|
||||
NMT_FIELD(CStrW, m_Sender)
|
||||
NMT_FIELD_INT(m_Recipient, u32, 2)
|
||||
NMT_FIELD(CStrW, m_Message)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(PlayerJoin, NMT_PLAYER_JOIN)
|
||||
NMT_START_ARRAY(m_Clients)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2)
|
||||
NMT_FIELD(CStr, m_Name)
|
||||
NMT_END_ARRAY()
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(PlayerLeave, NMT_PLAYER_LEAVE)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(GameSetup, NMT_GAME_SETUP)
|
||||
NMT_START_ARRAY(m_Values)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
NMT_FIELD(CStrW, m_Value)
|
||||
NMT_END_ARRAY()
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(AssignPlayerSlot, NMT_ASSIGN_PLAYER_SLOT)
|
||||
NMT_FIELD_INT(m_SlotID, u32, 2)
|
||||
NMT_FIELD_INT(m_Assignment, u32, 1)
|
||||
NMT_FIELD_INT(m_SessionID, u32, 2) // Only applicable for PS_ASSIGN_SESSION
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(PlayerConfig, NMT_PLAYER_CONFIG)
|
||||
NMT_FIELD_INT(m_PlayerID, u32, 2)
|
||||
NMT_START_ARRAY(m_Values)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
NMT_FIELD(CStrW, m_Value)
|
||||
NMT_END_ARRAY()
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(GameStart, NMT_GAME_START)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH)
|
||||
NMT_FIELD_INT(m_TurnLength, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Command, NMT_INVALID)
|
||||
NMT_FIELD(CEntityList, m_Entities)
|
||||
NMT_FIELD_INT(m_IsQueued, u32, 1)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Goto, NMT_GOTO)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Run, NMT_RUN)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Patrol, NMT_PATROL)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, AddWaypoint, NMT_ADD_WAYPOINT)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, SetRallyPoint, NMT_SET_RALLY_POINT)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, SetStance, NMT_SET_STANCE)
|
||||
NMT_FIELD(CStrW, m_Stance)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, ContactAction, NMT_CONTACT_ACTION)
|
||||
NMT_FIELD(HEntity, m_Target)
|
||||
NMT_FIELD_INT(m_Action, u32, 4)
|
||||
NMT_FIELD_INT(m_Run, u32, 1)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, Produce, NMT_PRODUCE)
|
||||
NMT_FIELD_INT(m_Type, u32, 4)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, PlaceObject, NMT_PLACE_OBJECT)
|
||||
NMT_FIELD(CStrW, m_Template)
|
||||
NMT_FIELD_INT(m_X, u32, 4)
|
||||
NMT_FIELD_INT(m_Y, u32, 4)
|
||||
NMT_FIELD_INT(m_Z, u32, 4)
|
||||
NMT_FIELD_INT(m_Angle, u32, 4) // Orientation angle
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, RemoveObject, NMT_REMOVE_OBJECT)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, NotifyRequest, NMT_NOTIFY_REQUEST)
|
||||
NMT_FIELD(HEntity, m_Target)
|
||||
NMT_FIELD_INT(m_Action, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, FormationGoto, NMT_FORMATION_GOTO)
|
||||
NMT_FIELD_INT(m_TargetX, u32, 2)
|
||||
NMT_FIELD_INT(m_TargetY, u32, 2)
|
||||
END_NMT_CLASS()
|
||||
|
||||
DERIVE_NMT_CLASS_(Command, FormationContactAction, NMT_FORMATION_CONTACT_ACTION)
|
||||
NMT_FIELD(HEntity, m_Target)
|
||||
NMT_FIELD_INT(m_Action, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
||||
END_NMTS()
|
||||
|
||||
#else
|
||||
#ifndef ALLNETMSGS_DONT_CREATE_NMTS
|
||||
|
||||
# ifdef ALLNETMSGS_IMPLEMENT
|
||||
# define NMT_CREATOR_IMPLEMENT
|
||||
# endif
|
||||
|
||||
# define NMT_CREATE_HEADER_NAME "NetMessages.h"
|
||||
# include "NMTCreator.h"
|
||||
|
||||
#endif // #ifndef ALLNETMSGS_DONT_CREATE_NMTS
|
||||
#endif // #ifdef CREATING_NMT
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,345 +1,345 @@
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetServer.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network server class interface file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETSERVER_H
|
||||
#define NETSERVER_H
|
||||
|
||||
// INCLUDES
|
||||
#include "Network.h"
|
||||
#include "NetSession.h"
|
||||
#include "simulation/TurnManager.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/scripting/JSMap.h"
|
||||
#include "ps/Player.h"
|
||||
#include "ps/Game.h"
|
||||
#include "simulation/ScriptObject.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
// DECLARATIONS
|
||||
#define SERVER_SESSIONID 1
|
||||
#define CLIENT_MIN_SESSIONID 100
|
||||
#define MAX_CLIENTS 8
|
||||
#define MAX_OBSERVERS 5
|
||||
#define DEFAULT_SERVER_SESSION_ID 1
|
||||
#define DEFAULT_SERVER_NAME L"Noname Server"
|
||||
#define DEFAULT_PLAYER_NAME L"Noname Player"
|
||||
#define DEFAULT_WELCOME_MESSAGE L"Noname Server Welcome Message"
|
||||
#define DEFAULT_HOST_PORT 0x5073
|
||||
|
||||
enum NetServerState
|
||||
{
|
||||
// We haven't opened the port yet, we're just setting some stuff up.
|
||||
// This is probably equivalent to the first "Start Network Game" screen
|
||||
SERVER_STATE_PREBIND,
|
||||
|
||||
// The server is open and accepting connections. This is the screen where
|
||||
// rules are set up by the operator and where players join and select civs
|
||||
// and stuff.
|
||||
SERVER_STATE_PREGAME,
|
||||
|
||||
// The one with all the killing ;-)
|
||||
SERVER_STATE_INGAME,
|
||||
|
||||
// The game is over and someone has won. Players might linger to chat or
|
||||
// download the replay log.
|
||||
SERVER_STATE_POSTGAME
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NSS_HANDSHAKE = 1300,
|
||||
NSS_AUTHENTICATE = 1400,
|
||||
NSS_PREGAME = 1500,
|
||||
NSS_INGAME = 1600
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NMT_APP_PLAYER_LEAVE = NMT_LAST + 100,
|
||||
NMT_APP_PREGAME = NMT_LAST + 200,
|
||||
NMT_APP_OBSERVER = NMT_LAST + 300
|
||||
};
|
||||
|
||||
typedef std::map< uint, CNetSession* > IDSessionMap;
|
||||
typedef std::vector< CNetSession* > SessionList;
|
||||
|
||||
/*
|
||||
CLASS : CNetServer
|
||||
DESCRIPTION : CNetServer implements a network server for the game.
|
||||
It receives data and connection requests from clients.
|
||||
Under the hood, it uses ENet library to manage connected
|
||||
peers and bandwidth among these.
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetServer : public CNetHost,
|
||||
public CJSObject<CNetServer>,
|
||||
public CTurnManager
|
||||
{
|
||||
public:
|
||||
|
||||
CNetServer( CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
virtual ~CNetServer( void );
|
||||
|
||||
bool Start ( JSContext *pContext, uintN argc, jsval *argv );
|
||||
// void Shutdown ( void );
|
||||
|
||||
/**
|
||||
* Returns true indicating the host acts as a server
|
||||
*
|
||||
* @return Always true
|
||||
*/
|
||||
virtual bool IsServer( void ) const { return true; }
|
||||
|
||||
/**
|
||||
* Adds a new session to the list of sessions
|
||||
*
|
||||
* @param pSession New session to add
|
||||
*/
|
||||
void AddSession( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Removes the specified session from the list of sessions. If the session
|
||||
* isn't found it returns NULL otherwise it returns the session object found.
|
||||
*
|
||||
* @param pSession Session to remove
|
||||
* @return The session object if found, NULL otherwise
|
||||
*/
|
||||
CNetSession* RemoveSession( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Removes all the sessions managed by the network server
|
||||
*
|
||||
*/
|
||||
//void RemoveAllSessions( void );
|
||||
|
||||
/**
|
||||
* Returns the number of session the server manages
|
||||
*
|
||||
* @return The number of sessions
|
||||
*/
|
||||
//uint GetSessionCount( void ) const;
|
||||
|
||||
/**
|
||||
* Returns the session object for the specified ID
|
||||
*
|
||||
* @param sessionID The session ID
|
||||
* @return A pointer to session for the specified ID or
|
||||
* NULL if not found
|
||||
*/
|
||||
CNetSession* GetSessionByID( uint sessionID );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool SetupSession ( CNetSession* pSession );
|
||||
virtual bool HandleConnect ( CNetSession* pSession );
|
||||
virtual bool HandleDisconnect ( CNetSession *pSession );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetServer( const CNetServer& );
|
||||
CNetServer& operator=( const CNetServer& );
|
||||
|
||||
//void ClientConnect ( ENetPeer* pPeer );
|
||||
//void ClientDisconnect ( ENetPeer* pPeer );
|
||||
//void ClientReceive ( ENetPeer* pPeer, ENetPacket* pPacket );
|
||||
|
||||
/**
|
||||
* Returns the session associated with the specified ENet peer
|
||||
*
|
||||
* @param pPeer ENet peer
|
||||
* @return The session object if found or NULL
|
||||
*/
|
||||
//CNetSession* GetSessionByPeer( const ENetPeer* pPeer );
|
||||
|
||||
/**
|
||||
* Setup client game by sending the apropiate network messages. It also
|
||||
* inform the client about the other connected clients as well as player
|
||||
* slot assignment and attributes.
|
||||
*
|
||||
*/
|
||||
//void SetupNewSession( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Loads the player properties into the specified message
|
||||
*
|
||||
* @param pMessage Message where to load player properties
|
||||
* @param pPlayer Player for which we load the properties
|
||||
*/
|
||||
void BuildPlayerConfigMessage(
|
||||
CPlayerConfigMessage* pMessage,
|
||||
CPlayer* pPlayer );
|
||||
|
||||
/**
|
||||
* Callback function used by the BuildPlayerSetupMessage to iterate over
|
||||
* the player properties. It will be called for each property of the player
|
||||
*
|
||||
* @param name Property name
|
||||
* @param pProperty Pointer to player property
|
||||
* @param pData Context pointer passed on iteration startup
|
||||
*/
|
||||
static void PlayerConfigMessageCallback(
|
||||
const CStrW& name,
|
||||
ISynchedJSProperty* pProperty,
|
||||
void* pData );
|
||||
|
||||
/**
|
||||
* Loads game properties into the specified message
|
||||
*
|
||||
* @param pMessage Message where to load game properties
|
||||
*/
|
||||
void BuildGameSetupMessage( CGameSetupMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Loads player slot properties into the specified message
|
||||
*
|
||||
* @param pMessage Message where to load player properties
|
||||
* @param pPlayerSlot Player slot properties
|
||||
*/
|
||||
void BuildPlayerSlotAssignmentMessage(
|
||||
CAssignPlayerSlotMessage* pMessage,
|
||||
CPlayerSlot* pPlayerSlot );
|
||||
|
||||
/**
|
||||
* Callback function used by the BuildGameSetupMessage to iterate over the
|
||||
* game properties. It will be called for each property of the game
|
||||
*
|
||||
* @param name Property name
|
||||
* @param pProperty Pointer to game property
|
||||
* @param pData Context pointer passed on iteration startup
|
||||
*/
|
||||
// IterateCB GameSetupMessageCallbak;
|
||||
static void GameSetupMessageCallback(
|
||||
const CStrW& name,
|
||||
ISynchedJSProperty *pProperty,
|
||||
void *pData );
|
||||
|
||||
/**
|
||||
* Retrieves a free session ID from the recycled sessions list
|
||||
*
|
||||
* @return Free session ID
|
||||
*/
|
||||
uint GetFreeSessionID( void ) const;
|
||||
|
||||
IDSessionMap m_IDSessions; // List of connected ID and session pairs
|
||||
//CScriptObject m_ScriptConnect; // Script client connect dispatch
|
||||
//CScriptObject m_ScriptDisconnect; // Script client disconnect dispatch
|
||||
//CScriptObject m_ScriptChat; // Script client chat dispatch
|
||||
CPlayer* m_Player; // Server player
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param addr Address where to bind
|
||||
* @return PS_OK if bind successfully, error code otherwise
|
||||
*/
|
||||
//PS_RESULT Bind( const CSocketAddress& addr );
|
||||
void SetPlayerPassword ( const CStr& password );
|
||||
CStrW GetPlayerName ( void ) const { return m_PlayerName; }
|
||||
NetServerState GetState ( void ) const { return m_State; }
|
||||
int StartGame ( void );
|
||||
static void ScriptingInit ( void );
|
||||
|
||||
protected:
|
||||
|
||||
// Assign a session ID to the session. Do this just before calling AddSession
|
||||
void AssignSessionID( CNetSession* pSession );
|
||||
|
||||
// Add the session. This will be called after the session passes the
|
||||
// handshake and authentication stages. AssignSessionID should've been called
|
||||
// on the session prior to calling this method.
|
||||
//void AddSession( CNetServerSession* pSession );
|
||||
|
||||
// Remove the session from the server
|
||||
//void RemoveSession( CNetServerSession* pSession );
|
||||
|
||||
// Queue a command coming in from the wire. The command has been validated
|
||||
// by the caller.
|
||||
void QueueIncomingCommand( CNetMessage* pMessage );
|
||||
|
||||
// Call the JS callback for incoming events
|
||||
void OnPlayerChat ( const CStrW& from, const CStrW& message );
|
||||
void OnPlayerJoin ( CNetSession* pSession );
|
||||
void OnPlayerLeave ( CNetSession* pSession );
|
||||
void SetupPlayer ( CNetSession* pSession );
|
||||
|
||||
//static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnError ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
|
||||
|
||||
// OVERRIDES FROM CServerSocket
|
||||
//virtual void OnAccept( const CSocketAddress& address );
|
||||
|
||||
// OVERRIDES FROM CTurnManager
|
||||
virtual void NewTurn( void );
|
||||
virtual bool NewTurnReady( void );
|
||||
virtual void QueueLocalCommand( CNetMessage* pMessage );
|
||||
|
||||
// Will only be called from the Network Thread, by the OnAccept handler
|
||||
//virtual CNetServerSession* CreateSession( CSocketInternal* pSocketInternal);
|
||||
|
||||
// Ask the server if the session is allowed to start observing.
|
||||
//
|
||||
// Returns:
|
||||
// true if the session should be made an observer
|
||||
// false otherwise
|
||||
virtual bool AllowObserver( CNetSession* pSession );
|
||||
|
||||
private:
|
||||
|
||||
CGameAttributes* m_GameAttributes; // Stores game attributes
|
||||
//int m_LastSessionID; // Stores the last session ID
|
||||
//SessionMap m_Sessions; // Managed sessions
|
||||
CJSMap< IDSessionMap > m_JsSessions;
|
||||
CMutex m_Mutex; // Synchronization object for batches
|
||||
|
||||
/*
|
||||
All sessions that have observer status (observer as in watcher - simple
|
||||
chatters don't have an entry here, only in m_Sessions).
|
||||
Sessions are added here after they have successfully requested observer
|
||||
status.
|
||||
*/
|
||||
SessionList m_Observers;
|
||||
uint m_MaxObservers; // Maximum number of observers
|
||||
CGame* m_Game; // Pointer to actual game
|
||||
NetServerState m_State; // Holds server state
|
||||
CStrW m_Name; // Server name
|
||||
CStrW m_WelcomeMessage; // Nice welcome message
|
||||
//CPlayer* m_Player; // Pointer to 'server' player
|
||||
CStrW m_PlayerName; // Player name
|
||||
CStrW m_PlayerPassword; // Player password
|
||||
int m_Port; // The listening port
|
||||
CScriptObject m_OnChat;
|
||||
CScriptObject m_OnClientConnect;
|
||||
CScriptObject m_OnClientDisconnect;
|
||||
|
||||
// static CGameAttributes::UpdateCallback AttributeUpdate;
|
||||
// static CPlayer::UpdateCallback PlayerAttributeUpdate;
|
||||
// static PlayerSlotAssignmentCB PlayerSlotAssignmentCallback;
|
||||
|
||||
static void AttributeUpdate ( const CStrW& name, const CStrW& newValue, void* pData);
|
||||
static void PlayerAttributeUpdate ( const CStrW& name, const CStrW& value, CPlayer* pPlayer, void* pData );
|
||||
static void PlayerSlotAssignment ( void* pData, CPlayerSlot* pPlayerSlot );
|
||||
};
|
||||
|
||||
extern CNetServer *g_NetServer;
|
||||
|
||||
#endif // NETSERVER_H
|
||||
|
||||
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetServer.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network server class interface file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETSERVER_H
|
||||
#define NETSERVER_H
|
||||
|
||||
// INCLUDES
|
||||
#include "Network.h"
|
||||
#include "NetSession.h"
|
||||
#include "simulation/TurnManager.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/scripting/JSMap.h"
|
||||
#include "ps/Player.h"
|
||||
#include "ps/Game.h"
|
||||
#include "simulation/ScriptObject.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
// DECLARATIONS
|
||||
#define SERVER_SESSIONID 1
|
||||
#define CLIENT_MIN_SESSIONID 100
|
||||
#define MAX_CLIENTS 8
|
||||
#define MAX_OBSERVERS 5
|
||||
#define DEFAULT_SERVER_SESSION_ID 1
|
||||
#define DEFAULT_SERVER_NAME L"Noname Server"
|
||||
#define DEFAULT_PLAYER_NAME L"Noname Player"
|
||||
#define DEFAULT_WELCOME_MESSAGE L"Noname Server Welcome Message"
|
||||
#define DEFAULT_HOST_PORT 0x5073
|
||||
|
||||
enum NetServerState
|
||||
{
|
||||
// We haven't opened the port yet, we're just setting some stuff up.
|
||||
// This is probably equivalent to the first "Start Network Game" screen
|
||||
SERVER_STATE_PREBIND,
|
||||
|
||||
// The server is open and accepting connections. This is the screen where
|
||||
// rules are set up by the operator and where players join and select civs
|
||||
// and stuff.
|
||||
SERVER_STATE_PREGAME,
|
||||
|
||||
// The one with all the killing ;-)
|
||||
SERVER_STATE_INGAME,
|
||||
|
||||
// The game is over and someone has won. Players might linger to chat or
|
||||
// download the replay log.
|
||||
SERVER_STATE_POSTGAME
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NSS_HANDSHAKE = 1300,
|
||||
NSS_AUTHENTICATE = 1400,
|
||||
NSS_PREGAME = 1500,
|
||||
NSS_INGAME = 1600
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NMT_APP_PLAYER_LEAVE = NMT_LAST + 100,
|
||||
NMT_APP_PREGAME = NMT_LAST + 200,
|
||||
NMT_APP_OBSERVER = NMT_LAST + 300
|
||||
};
|
||||
|
||||
typedef std::map< uint, CNetSession* > IDSessionMap;
|
||||
typedef std::vector< CNetSession* > SessionList;
|
||||
|
||||
/*
|
||||
CLASS : CNetServer
|
||||
DESCRIPTION : CNetServer implements a network server for the game.
|
||||
It receives data and connection requests from clients.
|
||||
Under the hood, it uses ENet library to manage connected
|
||||
peers and bandwidth among these.
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetServer : public CNetHost,
|
||||
public CJSObject<CNetServer>,
|
||||
public CTurnManager
|
||||
{
|
||||
public:
|
||||
|
||||
CNetServer( CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
virtual ~CNetServer( void );
|
||||
|
||||
bool Start ( JSContext *pContext, uintN argc, jsval *argv );
|
||||
// void Shutdown ( void );
|
||||
|
||||
/**
|
||||
* Returns true indicating the host acts as a server
|
||||
*
|
||||
* @return Always true
|
||||
*/
|
||||
virtual bool IsServer( void ) const { return true; }
|
||||
|
||||
/**
|
||||
* Adds a new session to the list of sessions
|
||||
*
|
||||
* @param pSession New session to add
|
||||
*/
|
||||
void AddSession( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Removes the specified session from the list of sessions. If the session
|
||||
* isn't found it returns NULL otherwise it returns the session object found.
|
||||
*
|
||||
* @param pSession Session to remove
|
||||
* @return The session object if found, NULL otherwise
|
||||
*/
|
||||
CNetSession* RemoveSession( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Removes all the sessions managed by the network server
|
||||
*
|
||||
*/
|
||||
//void RemoveAllSessions( void );
|
||||
|
||||
/**
|
||||
* Returns the number of session the server manages
|
||||
*
|
||||
* @return The number of sessions
|
||||
*/
|
||||
//uint GetSessionCount( void ) const;
|
||||
|
||||
/**
|
||||
* Returns the session object for the specified ID
|
||||
*
|
||||
* @param sessionID The session ID
|
||||
* @return A pointer to session for the specified ID or
|
||||
* NULL if not found
|
||||
*/
|
||||
CNetSession* GetSessionByID( uint sessionID );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool SetupSession ( CNetSession* pSession );
|
||||
virtual bool HandleConnect ( CNetSession* pSession );
|
||||
virtual bool HandleDisconnect ( CNetSession *pSession );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetServer( const CNetServer& );
|
||||
CNetServer& operator=( const CNetServer& );
|
||||
|
||||
//void ClientConnect ( ENetPeer* pPeer );
|
||||
//void ClientDisconnect ( ENetPeer* pPeer );
|
||||
//void ClientReceive ( ENetPeer* pPeer, ENetPacket* pPacket );
|
||||
|
||||
/**
|
||||
* Returns the session associated with the specified ENet peer
|
||||
*
|
||||
* @param pPeer ENet peer
|
||||
* @return The session object if found or NULL
|
||||
*/
|
||||
//CNetSession* GetSessionByPeer( const ENetPeer* pPeer );
|
||||
|
||||
/**
|
||||
* Setup client game by sending the apropiate network messages. It also
|
||||
* inform the client about the other connected clients as well as player
|
||||
* slot assignment and attributes.
|
||||
*
|
||||
*/
|
||||
//void SetupNewSession( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Loads the player properties into the specified message
|
||||
*
|
||||
* @param pMessage Message where to load player properties
|
||||
* @param pPlayer Player for which we load the properties
|
||||
*/
|
||||
void BuildPlayerConfigMessage(
|
||||
CPlayerConfigMessage* pMessage,
|
||||
CPlayer* pPlayer );
|
||||
|
||||
/**
|
||||
* Callback function used by the BuildPlayerSetupMessage to iterate over
|
||||
* the player properties. It will be called for each property of the player
|
||||
*
|
||||
* @param name Property name
|
||||
* @param pProperty Pointer to player property
|
||||
* @param pData Context pointer passed on iteration startup
|
||||
*/
|
||||
static void PlayerConfigMessageCallback(
|
||||
const CStrW& name,
|
||||
ISynchedJSProperty* pProperty,
|
||||
void* pData );
|
||||
|
||||
/**
|
||||
* Loads game properties into the specified message
|
||||
*
|
||||
* @param pMessage Message where to load game properties
|
||||
*/
|
||||
void BuildGameSetupMessage( CGameSetupMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Loads player slot properties into the specified message
|
||||
*
|
||||
* @param pMessage Message where to load player properties
|
||||
* @param pPlayerSlot Player slot properties
|
||||
*/
|
||||
void BuildPlayerSlotAssignmentMessage(
|
||||
CAssignPlayerSlotMessage* pMessage,
|
||||
CPlayerSlot* pPlayerSlot );
|
||||
|
||||
/**
|
||||
* Callback function used by the BuildGameSetupMessage to iterate over the
|
||||
* game properties. It will be called for each property of the game
|
||||
*
|
||||
* @param name Property name
|
||||
* @param pProperty Pointer to game property
|
||||
* @param pData Context pointer passed on iteration startup
|
||||
*/
|
||||
// IterateCB GameSetupMessageCallbak;
|
||||
static void GameSetupMessageCallback(
|
||||
const CStrW& name,
|
||||
ISynchedJSProperty *pProperty,
|
||||
void *pData );
|
||||
|
||||
/**
|
||||
* Retrieves a free session ID from the recycled sessions list
|
||||
*
|
||||
* @return Free session ID
|
||||
*/
|
||||
uint GetFreeSessionID( void ) const;
|
||||
|
||||
IDSessionMap m_IDSessions; // List of connected ID and session pairs
|
||||
//CScriptObject m_ScriptConnect; // Script client connect dispatch
|
||||
//CScriptObject m_ScriptDisconnect; // Script client disconnect dispatch
|
||||
//CScriptObject m_ScriptChat; // Script client chat dispatch
|
||||
CPlayer* m_Player; // Server player
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param addr Address where to bind
|
||||
* @return PS_OK if bind successfully, error code otherwise
|
||||
*/
|
||||
//PS_RESULT Bind( const CSocketAddress& addr );
|
||||
void SetPlayerPassword ( const CStr& password );
|
||||
CStrW GetPlayerName ( void ) const { return m_PlayerName; }
|
||||
NetServerState GetState ( void ) const { return m_State; }
|
||||
int StartGame ( void );
|
||||
static void ScriptingInit ( void );
|
||||
|
||||
protected:
|
||||
|
||||
// Assign a session ID to the session. Do this just before calling AddSession
|
||||
void AssignSessionID( CNetSession* pSession );
|
||||
|
||||
// Add the session. This will be called after the session passes the
|
||||
// handshake and authentication stages. AssignSessionID should've been called
|
||||
// on the session prior to calling this method.
|
||||
//void AddSession( CNetServerSession* pSession );
|
||||
|
||||
// Remove the session from the server
|
||||
//void RemoveSession( CNetServerSession* pSession );
|
||||
|
||||
// Queue a command coming in from the wire. The command has been validated
|
||||
// by the caller.
|
||||
void QueueIncomingCommand( CNetMessage* pMessage );
|
||||
|
||||
// Call the JS callback for incoming events
|
||||
void OnPlayerChat ( const CStrW& from, const CStrW& message );
|
||||
void OnPlayerJoin ( CNetSession* pSession );
|
||||
void OnPlayerLeave ( CNetSession* pSession );
|
||||
void SetupPlayer ( CNetSession* pSession );
|
||||
|
||||
//static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnError ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
|
||||
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
|
||||
|
||||
// OVERRIDES FROM CServerSocket
|
||||
//virtual void OnAccept( const CSocketAddress& address );
|
||||
|
||||
// OVERRIDES FROM CTurnManager
|
||||
virtual void NewTurn( void );
|
||||
virtual bool NewTurnReady( void );
|
||||
virtual void QueueLocalCommand( CNetMessage* pMessage );
|
||||
|
||||
// Will only be called from the Network Thread, by the OnAccept handler
|
||||
//virtual CNetServerSession* CreateSession( CSocketInternal* pSocketInternal);
|
||||
|
||||
// Ask the server if the session is allowed to start observing.
|
||||
//
|
||||
// Returns:
|
||||
// true if the session should be made an observer
|
||||
// false otherwise
|
||||
virtual bool AllowObserver( CNetSession* pSession );
|
||||
|
||||
private:
|
||||
|
||||
CGameAttributes* m_GameAttributes; // Stores game attributes
|
||||
//int m_LastSessionID; // Stores the last session ID
|
||||
//SessionMap m_Sessions; // Managed sessions
|
||||
CJSMap< IDSessionMap > m_JsSessions;
|
||||
CMutex m_Mutex; // Synchronization object for batches
|
||||
|
||||
/*
|
||||
All sessions that have observer status (observer as in watcher - simple
|
||||
chatters don't have an entry here, only in m_Sessions).
|
||||
Sessions are added here after they have successfully requested observer
|
||||
status.
|
||||
*/
|
||||
SessionList m_Observers;
|
||||
uint m_MaxObservers; // Maximum number of observers
|
||||
CGame* m_Game; // Pointer to actual game
|
||||
NetServerState m_State; // Holds server state
|
||||
CStrW m_Name; // Server name
|
||||
CStrW m_WelcomeMessage; // Nice welcome message
|
||||
//CPlayer* m_Player; // Pointer to 'server' player
|
||||
CStrW m_PlayerName; // Player name
|
||||
CStrW m_PlayerPassword; // Player password
|
||||
int m_Port; // The listening port
|
||||
CScriptObject m_OnChat;
|
||||
CScriptObject m_OnClientConnect;
|
||||
CScriptObject m_OnClientDisconnect;
|
||||
|
||||
// static CGameAttributes::UpdateCallback AttributeUpdate;
|
||||
// static CPlayer::UpdateCallback PlayerAttributeUpdate;
|
||||
// static PlayerSlotAssignmentCB PlayerSlotAssignmentCallback;
|
||||
|
||||
static void AttributeUpdate ( const CStrW& name, const CStrW& newValue, void* pData);
|
||||
static void PlayerAttributeUpdate ( const CStrW& name, const CStrW& value, CPlayer* pPlayer, void* pData );
|
||||
static void PlayerSlotAssignment ( void* pData, CPlayerSlot* pPlayerSlot );
|
||||
};
|
||||
|
||||
extern CNetServer *g_NetServer;
|
||||
|
||||
#endif // NETSERVER_H
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,341 +1,341 @@
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetSession.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network session class interface file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETSESSION_H
|
||||
#define NETSESSION_H
|
||||
|
||||
// INCLUDES
|
||||
#include "Network.h"
|
||||
#include "ps/Singleton.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/Player.h"
|
||||
#include "fsm.h"
|
||||
#include <enet/enet.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// DECLARATIONS
|
||||
#define INVALID_SESSION 0
|
||||
#define ENET_DEFAULT_CHANNEL 0
|
||||
|
||||
class CNetSession;
|
||||
class CNetHost;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ENetPeer* pPeer;
|
||||
CNetSession* pSession;
|
||||
|
||||
} PeerSession;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CNetHost* pHost;
|
||||
CNetSession* pSession;
|
||||
|
||||
} FsmActionCtx;
|
||||
|
||||
typedef std::vector< PeerSession > PeerSessionList;
|
||||
|
||||
/*
|
||||
CLASS : CNetHost
|
||||
DESCRIPTION : CNetHost is a wrapper around ENet host conecept
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetHost : public Singleton< CNetHost >
|
||||
{
|
||||
public:
|
||||
|
||||
CNetHost( void );
|
||||
virtual ~CNetHost( void );
|
||||
|
||||
bool Create( void );
|
||||
bool Create( uint port, uint maxPeers );
|
||||
void Shutdown( void );
|
||||
|
||||
/**
|
||||
* Indicates whether the host is currently a server
|
||||
*
|
||||
* @return Boolean indicating whether the host is a server
|
||||
*/
|
||||
virtual bool IsServer( void ) const { return false; }
|
||||
|
||||
/**
|
||||
* Indicates whether the host is currently a client
|
||||
*
|
||||
* @return Boolean indicating whether the host is a client
|
||||
*/
|
||||
virtual bool IsClient( void ) const { return false; }
|
||||
|
||||
/**
|
||||
* Returns the number of sessions for the host
|
||||
*
|
||||
* @return The number of sessions
|
||||
*/
|
||||
uint GetSessionCount( void ) const;
|
||||
|
||||
/**
|
||||
* Returns the session object for the specified index
|
||||
*
|
||||
* @param index Index for session
|
||||
* @return Session object for index or NULL if not found
|
||||
*/
|
||||
CNetSession* GetSession( uint index );
|
||||
|
||||
/**
|
||||
* Connects to foreign host
|
||||
*
|
||||
* @param host Foreign host name
|
||||
* @param port Port on which the foreign host listens
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool Connect( const CStr& host, uint port );
|
||||
|
||||
/**
|
||||
* Disconnects session from host
|
||||
*
|
||||
* @param pSession Session representing peer
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool Disconnect( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Listens for incoming connections and dispatches host events
|
||||
*
|
||||
* @return true on exit, false dispatch failure
|
||||
*/
|
||||
//bool Run( void );
|
||||
bool Poll( void );
|
||||
|
||||
/**
|
||||
* Broadcast the specified message to connected clients
|
||||
*
|
||||
* @param pMessage Message to broadcast
|
||||
*/
|
||||
void Broadcast( const CNetMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Send the specified message to client
|
||||
*
|
||||
* @param pMessage The message to send
|
||||
*/
|
||||
virtual bool SendMessage(
|
||||
const CNetSession* pSession,
|
||||
const CNetMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Receive a message from client if available
|
||||
*
|
||||
*/
|
||||
virtual CNetMessage* ReceiveMessage( const CNetSession* pSession );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Attempts to resize the internal buffer to the size indicated by the
|
||||
* passed parameter.
|
||||
*
|
||||
* @param size The new size for the buffer
|
||||
*/
|
||||
void ResizeBuffer( size_t size );
|
||||
|
||||
// Allow application to handle new client connect
|
||||
virtual bool SetupSession ( CNetSession* pSession );
|
||||
virtual bool HandleConnect ( CNetSession* pSession );
|
||||
virtual bool HandleDisconnect ( CNetSession* pSession );
|
||||
virtual bool HandleMessageReceive (
|
||||
CNetMessage* pMessage,
|
||||
CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Worker thread function
|
||||
*
|
||||
* @pData Argument specified on thread creation
|
||||
* @return NULL
|
||||
*/
|
||||
//static void* WorkerFunc( void* pData );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetHost( const CNetHost& );
|
||||
CNetHost& operator=( const CNetHost& );
|
||||
|
||||
u8* m_Buffer; // Serialize out messages buffer
|
||||
size_t m_BufferSize; // Output buffer size
|
||||
ENetHost* m_Host; // Represents this host
|
||||
PeerSessionList m_PeerSessions; // Session list of connected peers
|
||||
//pthread_t m_WorkerID; // Worker thread
|
||||
//sem_t* m_StopWorker; // Worker thread stop semaphore
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetSession
|
||||
DESCRIPTION : CNetSession is a wrapper class around ENet peer concept
|
||||
which represents a peer from a network connection. A
|
||||
network session is spawned by CNetServer each time a
|
||||
client connects and destroyed when it disconnects. When a
|
||||
new message is received fom a client, its representing
|
||||
session object's message handler is called for processing
|
||||
that message.
|
||||
CNetSession is also a state machine. All client requests
|
||||
are delegated to the current state. The current
|
||||
CNetSessionState object's methods will change the current
|
||||
state as appropriate.
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetSession : public CFsm,
|
||||
public CJSObject< CNetSession >,
|
||||
public IMessagePipeEnd
|
||||
{
|
||||
friend class CNetHost;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~CNetSession( void );
|
||||
|
||||
/**
|
||||
* Retrieves the name of the session
|
||||
*
|
||||
* @return Session name
|
||||
*/
|
||||
const CStrW& GetName( void ) const { return m_Name; }
|
||||
|
||||
/**
|
||||
* Set the new name for the session
|
||||
*
|
||||
* @param name The session new name
|
||||
*/
|
||||
void SetName( const CStr& name );
|
||||
|
||||
/**
|
||||
* Retrieves the ID of the session
|
||||
*
|
||||
* @return Session ID
|
||||
*/
|
||||
uint GetID( void ) const { return m_ID; }
|
||||
|
||||
/**
|
||||
* Set the ID for this session
|
||||
*
|
||||
* @param New session ID
|
||||
*/
|
||||
void SetID( uint ID );
|
||||
|
||||
/**
|
||||
* Allows both client and server to set a callback handler
|
||||
*
|
||||
* @param pCallbackHandler Callback handler
|
||||
*/
|
||||
//void SetCallbackHandler( ISessionCallback* pCallbackHandler );
|
||||
|
||||
/**
|
||||
* Disconnects the client from remote host
|
||||
*
|
||||
*/
|
||||
void Reset( void );
|
||||
|
||||
void SetPlayer( CPlayer* pPlayer );
|
||||
CPlayer* GetPlayer( void ) { return m_Player; }
|
||||
void SetPlayerSlot( CPlayerSlot* pPlayerSlot );
|
||||
CPlayerSlot* GetPlayerSlot( void ) { return m_PlayerSlot; }
|
||||
void StartGame( void );
|
||||
virtual void Push( CNetMessage* pMessage );
|
||||
virtual CNetMessage* TryPop( void );
|
||||
bool IsReadyForTurn( void ) const { return m_ReadyForTurn; }
|
||||
void SetReadyForTurn( bool newValue ) { m_ReadyForTurn = newValue; }
|
||||
bool JSI_Close( JSContext *cx, uintN argc, jsval *argv );
|
||||
static void ScriptingInit( void );
|
||||
|
||||
//bool HandleMessage( CNetMessage* pMessage );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Process the message passed as parameter
|
||||
*
|
||||
* @param message The message to process
|
||||
* @return true if the message was handler
|
||||
* successufully, false otherwise
|
||||
*/
|
||||
//bool ProcessMessage( const CNetMessage& message );
|
||||
|
||||
private:
|
||||
|
||||
// Only the hosts can create sessions
|
||||
CNetSession( CNetHost* pHost, ENetPeer* pPeer );
|
||||
|
||||
// Not implemented
|
||||
CNetSession( void );
|
||||
CNetSession( const CNetSession& );
|
||||
CNetSession& operator=( const CNetSession& );
|
||||
|
||||
CNetHost* m_Host; // The associated local host
|
||||
ENetPeer* m_Peer; // Represents the peer host
|
||||
uint m_ID; // Session ID
|
||||
CStrW m_Name; // Session name
|
||||
CPlayer* m_Player;
|
||||
CPlayerSlot* m_PlayerSlot;
|
||||
bool m_ReadyForTurn; // Next turn ready flag
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetServerSession
|
||||
DESCRIPTION :
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
/*class CNetServerSession : public CNetSession,
|
||||
public CJSObject< CNetServerSession >
|
||||
{
|
||||
public:
|
||||
|
||||
bool IsObserver ( void ) const { return m_IsObserver; }
|
||||
CPlayer* GetPlayer ( void ) const { return m_Player; }
|
||||
CPlayerSlot* GetPlayerSlot ( void ) const { return m_PlayerSlot; }
|
||||
void StartGame ( void );
|
||||
void SetPlayer ( CPlayer* pPlayer );
|
||||
void SetPlayerSlot ( CPlayerSlot* pPlayerSlot );
|
||||
|
||||
protected:
|
||||
|
||||
CNetServerSession(
|
||||
CNetServer* pServer,
|
||||
NetMessageHandler* pHandler = m_HandshakeHandler );
|
||||
CNetServerSession(
|
||||
CNetServer* pServer,
|
||||
CSocketInternal* pSocketInternal,
|
||||
NetMessageHandler* pHandler = m_HandshakeHandler );
|
||||
virtual ~CNetServerSession( void );
|
||||
|
||||
private:
|
||||
|
||||
static void ScriptingInit ( void );
|
||||
bool JSI_Close (
|
||||
JSContext* pContext,
|
||||
uintN argc,
|
||||
jsval* argv );
|
||||
|
||||
CNetServer* m_Server;
|
||||
CPlayer* m_Player;
|
||||
CPlayerSlot* m_PlayerSlot;
|
||||
bool m_IsObserver;
|
||||
|
||||
static bool HandshakeHandler( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool ObserverHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool BaseHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool AuthHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool PreGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool InGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool ChatHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
};*/
|
||||
|
||||
#endif // NETSESSION_H
|
||||
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetSession.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network session class interface file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETSESSION_H
|
||||
#define NETSESSION_H
|
||||
|
||||
// INCLUDES
|
||||
#include "Network.h"
|
||||
#include "ps/Singleton.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/Player.h"
|
||||
#include "fsm.h"
|
||||
#include <enet/enet.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// DECLARATIONS
|
||||
#define INVALID_SESSION 0
|
||||
#define ENET_DEFAULT_CHANNEL 0
|
||||
|
||||
class CNetSession;
|
||||
class CNetHost;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ENetPeer* pPeer;
|
||||
CNetSession* pSession;
|
||||
|
||||
} PeerSession;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CNetHost* pHost;
|
||||
CNetSession* pSession;
|
||||
|
||||
} FsmActionCtx;
|
||||
|
||||
typedef std::vector< PeerSession > PeerSessionList;
|
||||
|
||||
/*
|
||||
CLASS : CNetHost
|
||||
DESCRIPTION : CNetHost is a wrapper around ENet host conecept
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetHost : public Singleton< CNetHost >
|
||||
{
|
||||
public:
|
||||
|
||||
CNetHost( void );
|
||||
virtual ~CNetHost( void );
|
||||
|
||||
bool Create( void );
|
||||
bool Create( uint port, uint maxPeers );
|
||||
void Shutdown( void );
|
||||
|
||||
/**
|
||||
* Indicates whether the host is currently a server
|
||||
*
|
||||
* @return Boolean indicating whether the host is a server
|
||||
*/
|
||||
virtual bool IsServer( void ) const { return false; }
|
||||
|
||||
/**
|
||||
* Indicates whether the host is currently a client
|
||||
*
|
||||
* @return Boolean indicating whether the host is a client
|
||||
*/
|
||||
virtual bool IsClient( void ) const { return false; }
|
||||
|
||||
/**
|
||||
* Returns the number of sessions for the host
|
||||
*
|
||||
* @return The number of sessions
|
||||
*/
|
||||
uint GetSessionCount( void ) const;
|
||||
|
||||
/**
|
||||
* Returns the session object for the specified index
|
||||
*
|
||||
* @param index Index for session
|
||||
* @return Session object for index or NULL if not found
|
||||
*/
|
||||
CNetSession* GetSession( uint index );
|
||||
|
||||
/**
|
||||
* Connects to foreign host
|
||||
*
|
||||
* @param host Foreign host name
|
||||
* @param port Port on which the foreign host listens
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool Connect( const CStr& host, uint port );
|
||||
|
||||
/**
|
||||
* Disconnects session from host
|
||||
*
|
||||
* @param pSession Session representing peer
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool Disconnect( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Listens for incoming connections and dispatches host events
|
||||
*
|
||||
* @return true on exit, false dispatch failure
|
||||
*/
|
||||
//bool Run( void );
|
||||
bool Poll( void );
|
||||
|
||||
/**
|
||||
* Broadcast the specified message to connected clients
|
||||
*
|
||||
* @param pMessage Message to broadcast
|
||||
*/
|
||||
void Broadcast( const CNetMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Send the specified message to client
|
||||
*
|
||||
* @param pMessage The message to send
|
||||
*/
|
||||
virtual bool SendMessage(
|
||||
const CNetSession* pSession,
|
||||
const CNetMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Receive a message from client if available
|
||||
*
|
||||
*/
|
||||
virtual CNetMessage* ReceiveMessage( const CNetSession* pSession );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Attempts to resize the internal buffer to the size indicated by the
|
||||
* passed parameter.
|
||||
*
|
||||
* @param size The new size for the buffer
|
||||
*/
|
||||
void ResizeBuffer( size_t size );
|
||||
|
||||
// Allow application to handle new client connect
|
||||
virtual bool SetupSession ( CNetSession* pSession );
|
||||
virtual bool HandleConnect ( CNetSession* pSession );
|
||||
virtual bool HandleDisconnect ( CNetSession* pSession );
|
||||
virtual bool HandleMessageReceive (
|
||||
CNetMessage* pMessage,
|
||||
CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Worker thread function
|
||||
*
|
||||
* @pData Argument specified on thread creation
|
||||
* @return NULL
|
||||
*/
|
||||
//static void* WorkerFunc( void* pData );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetHost( const CNetHost& );
|
||||
CNetHost& operator=( const CNetHost& );
|
||||
|
||||
u8* m_Buffer; // Serialize out messages buffer
|
||||
size_t m_BufferSize; // Output buffer size
|
||||
ENetHost* m_Host; // Represents this host
|
||||
PeerSessionList m_PeerSessions; // Session list of connected peers
|
||||
//pthread_t m_WorkerID; // Worker thread
|
||||
//sem_t* m_StopWorker; // Worker thread stop semaphore
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetSession
|
||||
DESCRIPTION : CNetSession is a wrapper class around ENet peer concept
|
||||
which represents a peer from a network connection. A
|
||||
network session is spawned by CNetServer each time a
|
||||
client connects and destroyed when it disconnects. When a
|
||||
new message is received fom a client, its representing
|
||||
session object's message handler is called for processing
|
||||
that message.
|
||||
CNetSession is also a state machine. All client requests
|
||||
are delegated to the current state. The current
|
||||
CNetSessionState object's methods will change the current
|
||||
state as appropriate.
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetSession : public CFsm,
|
||||
public CJSObject< CNetSession >,
|
||||
public IMessagePipeEnd
|
||||
{
|
||||
friend class CNetHost;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~CNetSession( void );
|
||||
|
||||
/**
|
||||
* Retrieves the name of the session
|
||||
*
|
||||
* @return Session name
|
||||
*/
|
||||
const CStrW& GetName( void ) const { return m_Name; }
|
||||
|
||||
/**
|
||||
* Set the new name for the session
|
||||
*
|
||||
* @param name The session new name
|
||||
*/
|
||||
void SetName( const CStr& name );
|
||||
|
||||
/**
|
||||
* Retrieves the ID of the session
|
||||
*
|
||||
* @return Session ID
|
||||
*/
|
||||
uint GetID( void ) const { return m_ID; }
|
||||
|
||||
/**
|
||||
* Set the ID for this session
|
||||
*
|
||||
* @param New session ID
|
||||
*/
|
||||
void SetID( uint ID );
|
||||
|
||||
/**
|
||||
* Allows both client and server to set a callback handler
|
||||
*
|
||||
* @param pCallbackHandler Callback handler
|
||||
*/
|
||||
//void SetCallbackHandler( ISessionCallback* pCallbackHandler );
|
||||
|
||||
/**
|
||||
* Disconnects the client from remote host
|
||||
*
|
||||
*/
|
||||
void Reset( void );
|
||||
|
||||
void SetPlayer( CPlayer* pPlayer );
|
||||
CPlayer* GetPlayer( void ) { return m_Player; }
|
||||
void SetPlayerSlot( CPlayerSlot* pPlayerSlot );
|
||||
CPlayerSlot* GetPlayerSlot( void ) { return m_PlayerSlot; }
|
||||
void StartGame( void );
|
||||
virtual void Push( CNetMessage* pMessage );
|
||||
virtual CNetMessage* TryPop( void );
|
||||
bool IsReadyForTurn( void ) const { return m_ReadyForTurn; }
|
||||
void SetReadyForTurn( bool newValue ) { m_ReadyForTurn = newValue; }
|
||||
bool JSI_Close( JSContext *cx, uintN argc, jsval *argv );
|
||||
static void ScriptingInit( void );
|
||||
|
||||
//bool HandleMessage( CNetMessage* pMessage );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Process the message passed as parameter
|
||||
*
|
||||
* @param message The message to process
|
||||
* @return true if the message was handler
|
||||
* successufully, false otherwise
|
||||
*/
|
||||
//bool ProcessMessage( const CNetMessage& message );
|
||||
|
||||
private:
|
||||
|
||||
// Only the hosts can create sessions
|
||||
CNetSession( CNetHost* pHost, ENetPeer* pPeer );
|
||||
|
||||
// Not implemented
|
||||
CNetSession( void );
|
||||
CNetSession( const CNetSession& );
|
||||
CNetSession& operator=( const CNetSession& );
|
||||
|
||||
CNetHost* m_Host; // The associated local host
|
||||
ENetPeer* m_Peer; // Represents the peer host
|
||||
uint m_ID; // Session ID
|
||||
CStrW m_Name; // Session name
|
||||
CPlayer* m_Player;
|
||||
CPlayerSlot* m_PlayerSlot;
|
||||
bool m_ReadyForTurn; // Next turn ready flag
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetServerSession
|
||||
DESCRIPTION :
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
/*class CNetServerSession : public CNetSession,
|
||||
public CJSObject< CNetServerSession >
|
||||
{
|
||||
public:
|
||||
|
||||
bool IsObserver ( void ) const { return m_IsObserver; }
|
||||
CPlayer* GetPlayer ( void ) const { return m_Player; }
|
||||
CPlayerSlot* GetPlayerSlot ( void ) const { return m_PlayerSlot; }
|
||||
void StartGame ( void );
|
||||
void SetPlayer ( CPlayer* pPlayer );
|
||||
void SetPlayerSlot ( CPlayerSlot* pPlayerSlot );
|
||||
|
||||
protected:
|
||||
|
||||
CNetServerSession(
|
||||
CNetServer* pServer,
|
||||
NetMessageHandler* pHandler = m_HandshakeHandler );
|
||||
CNetServerSession(
|
||||
CNetServer* pServer,
|
||||
CSocketInternal* pSocketInternal,
|
||||
NetMessageHandler* pHandler = m_HandshakeHandler );
|
||||
virtual ~CNetServerSession( void );
|
||||
|
||||
private:
|
||||
|
||||
static void ScriptingInit ( void );
|
||||
bool JSI_Close (
|
||||
JSContext* pContext,
|
||||
uintN argc,
|
||||
jsval* argv );
|
||||
|
||||
CNetServer* m_Server;
|
||||
CPlayer* m_Player;
|
||||
CPlayerSlot* m_PlayerSlot;
|
||||
bool m_IsObserver;
|
||||
|
||||
static bool HandshakeHandler( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool ObserverHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool BaseHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool AuthHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool PreGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool InGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
static bool ChatHandler ( CNetMessage* pMessage, CNetSession* pSession );
|
||||
};*/
|
||||
|
||||
#endif // NETSESSION_H
|
||||
|
||||
|
@ -1,445 +1,445 @@
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : fsm.cpp
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Finite state machine class implementation
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// INCLUDES
|
||||
#include "precompiled.h"
|
||||
#include "fsm.h"
|
||||
|
||||
// DECLARATIONS
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CFsmEvent()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmEvent::CFsmEvent( unsigned int type )
|
||||
{
|
||||
m_Type = type;
|
||||
m_Param = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name; ~CFsmEvent()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmEvent::~CFsmEvent( void )
|
||||
{
|
||||
m_Param = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetParamRef()
|
||||
// Desc: Sets the parameter for the event
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmEvent::SetParamRef( void* pParam )
|
||||
{
|
||||
m_Param = pParam;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CFsmTransition()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition::CFsmTransition( unsigned int state )
|
||||
{
|
||||
m_CurrState = state;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CFsmTransition()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition::~CFsmTransition( void )
|
||||
{
|
||||
m_Actions.clear();
|
||||
m_Conditions.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: RegisterAction()
|
||||
// Desc: Adds action that will be executed when the transition will occur
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::RegisterAction( void* pAction, void* pContext )
|
||||
{
|
||||
CallbackFunction callback;
|
||||
|
||||
// Add action at the end of actions list
|
||||
callback.pFunction = pAction;
|
||||
callback.pContext = pContext;
|
||||
|
||||
m_Actions.push_back( callback );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddCondition()
|
||||
// Desc: Adds condition which will be evaluated when the transition will occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::RegisterCondition( void* pCondition, void* pContext )
|
||||
{
|
||||
CallbackFunction callback;
|
||||
|
||||
// Add condition at the end of conditions list
|
||||
callback.pFunction = pCondition;
|
||||
callback.pContext = pContext;
|
||||
|
||||
m_Conditions.push_back( callback );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetEvent()
|
||||
// Desc: Set event for which transition will occur
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::SetEvent( CFsmEvent* pEvent )
|
||||
{
|
||||
m_Event = pEvent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetNextState()
|
||||
// Desc: Set next state the transition will switch the system to
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::SetNextState( unsigned int nextState )
|
||||
{
|
||||
m_NextState = nextState;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ApplyConditions()
|
||||
// Desc: Evaluate conditions for the transition
|
||||
// Note: If there are no conditions, assume true
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsmTransition::ApplyConditions( void ) const
|
||||
{
|
||||
bool eval = true;
|
||||
|
||||
CallbackList::const_iterator it = m_Conditions.begin();
|
||||
for( ; it != m_Conditions.end(); it++ )
|
||||
{
|
||||
if ( it->pFunction )
|
||||
{
|
||||
// Evaluate condition
|
||||
CONDITION Condition = ( CONDITION )it->pFunction;
|
||||
eval &= Condition( it->pContext );
|
||||
}
|
||||
}
|
||||
|
||||
return eval;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: RunActions()
|
||||
// Desc: Execur actions for the transition
|
||||
// Note: If there are no actions, assume true
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsmTransition::RunActions( void ) const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
CallbackList::const_iterator it = m_Actions.begin();
|
||||
for( ; it != m_Actions.end(); it++ )
|
||||
{
|
||||
if ( it->pFunction )
|
||||
{
|
||||
// Run action
|
||||
ACTION Action = ( ACTION )it->pFunction;
|
||||
result &= Action( it->pContext, m_Event );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CFsm()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsm::CFsm( void )
|
||||
{
|
||||
m_Done = false;
|
||||
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
|
||||
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CFsm()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsm::~CFsm( void )
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Setup()
|
||||
// Desc: Setup events, actions and state transitions
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::Setup( void )
|
||||
{
|
||||
// Does nothing by default
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Reset()
|
||||
// Desc: Shuts down the state machine and releases any resources
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::Shutdown( void )
|
||||
{
|
||||
// Release transitions
|
||||
TransitionList::iterator itTransition = m_Transitions.begin();
|
||||
for ( ; itTransition < m_Transitions.end(); itTransition++ )
|
||||
{
|
||||
CFsmTransition* pCurrTransition = *itTransition;
|
||||
if ( !pCurrTransition ) continue;
|
||||
|
||||
delete pCurrTransition;
|
||||
}
|
||||
|
||||
// Release events
|
||||
EventMap::iterator itEvent = m_Events.begin();
|
||||
for( ; itEvent != m_Events.end(); itEvent++ )
|
||||
{
|
||||
CFsmEvent* pCurrEvent = itEvent->second;
|
||||
if ( !pCurrEvent ) continue;
|
||||
|
||||
delete pCurrEvent;
|
||||
}
|
||||
|
||||
m_States.clear();
|
||||
m_Events.clear();
|
||||
m_Transitions.clear();
|
||||
|
||||
m_Done = false;
|
||||
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
|
||||
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddState()
|
||||
// Desc: Adds the specified state to the internal list of states
|
||||
// Note: If a state with the specified ID exists, the state is not added
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::AddState( unsigned int state )
|
||||
{
|
||||
m_States.insert( state );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddEvent()
|
||||
// Desc: Adds the specified event to the internal list of events
|
||||
// Note: If an eveny with the specified ID exists, the event is not added
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmEvent* CFsm::AddEvent( unsigned int eventType )
|
||||
{
|
||||
CFsmEvent* pEvent = NULL;
|
||||
|
||||
// Lookup event by type
|
||||
EventMap::iterator it = m_Events.find( eventType );
|
||||
if ( it != m_Events.end() )
|
||||
{
|
||||
pEvent = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEvent = new CFsmEvent( eventType );
|
||||
if ( !pEvent ) return NULL;
|
||||
|
||||
// Store new event into internal map
|
||||
m_Events[ eventType ] = pEvent;
|
||||
}
|
||||
|
||||
return pEvent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddTransition()
|
||||
// Desc: Adds a new transistion to the state machine
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition* CFsm::AddTransition(
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState )
|
||||
{
|
||||
// Make sure we store the current state
|
||||
AddState( state );
|
||||
|
||||
// Make sure we store the next state
|
||||
AddState( nextState );
|
||||
|
||||
// Make sure we store the event
|
||||
CFsmEvent* pEvent = AddEvent( eventType );
|
||||
if ( !pEvent ) return NULL;
|
||||
|
||||
// Create new transition
|
||||
CFsmTransition* pNewTransition = new CFsmTransition( state );
|
||||
if ( !pNewTransition ) return NULL;
|
||||
|
||||
// Setup new transition
|
||||
pNewTransition->SetEvent( pEvent );
|
||||
pNewTransition->SetNextState( nextState );
|
||||
|
||||
// Store new transition
|
||||
m_Transitions.push_back( pNewTransition );
|
||||
|
||||
return pNewTransition;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddTransition()
|
||||
// Desc: Adds a new transistion to the state machine
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition* CFsm::AddTransition(
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState,
|
||||
void* pAction,
|
||||
void* pContext )
|
||||
{
|
||||
CFsmTransition* pTransition = AddTransition( state, eventType, nextState );
|
||||
if ( !pTransition ) return NULL;
|
||||
|
||||
// If action specified, register it
|
||||
if ( pAction )
|
||||
pTransition->RegisterAction( pAction, pContext );
|
||||
|
||||
return pTransition;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: GetTransition()
|
||||
// Desc: Lookup transition given the state, event and next state to transition
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition* CFsm::GetTransition(
|
||||
unsigned int state,
|
||||
unsigned int eventType ) const
|
||||
{
|
||||
// Valid state?
|
||||
if ( !IsValidState( state ) ) return NULL;
|
||||
|
||||
// Valid event?
|
||||
if ( !IsValidEvent( eventType ) ) return NULL;
|
||||
|
||||
// Loop through the list of transitions
|
||||
TransitionList::const_iterator it = m_Transitions.begin();
|
||||
for ( ; it != m_Transitions.end(); it++ )
|
||||
{
|
||||
CFsmTransition* pCurrTransition = *it;
|
||||
if ( !pCurrTransition ) continue;
|
||||
|
||||
CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
|
||||
if ( !pCurrEvent ) continue;
|
||||
|
||||
// Is it our transition?
|
||||
if ( pCurrTransition->GetCurrState() == state &&
|
||||
pCurrEvent->GetType() == eventType )
|
||||
{
|
||||
return pCurrTransition;
|
||||
}
|
||||
}
|
||||
|
||||
// No transition found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetFirstState()
|
||||
// Desc: Set initial state for FSM
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::SetFirstState( unsigned int firstState )
|
||||
{
|
||||
m_FirstState = firstState;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetCurrState()
|
||||
// Desc: Set current state and update last state to current state
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::SetCurrState( unsigned int state )
|
||||
{
|
||||
m_CurrState = state;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsFirstTime()
|
||||
// Desc: Verifies if the state machine has been already updated
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsFirstTime( void ) const
|
||||
{
|
||||
return ( m_CurrState == FSM_INVALID_STATE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Update()
|
||||
// Desc: Updates state machine and retrieves next state
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::Update( unsigned int eventType, void* pEventParam )
|
||||
{
|
||||
// Valid event?
|
||||
if ( !IsValidEvent( eventType ) )
|
||||
return false;
|
||||
|
||||
// First time update?
|
||||
if ( IsFirstTime() )
|
||||
m_CurrState = m_FirstState;
|
||||
|
||||
// Lookup transition
|
||||
CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
|
||||
if ( !pTransition ) return false;
|
||||
|
||||
// Setup event parameter
|
||||
EventMap::iterator it = m_Events.find( eventType );
|
||||
if ( it != m_Events.end() )
|
||||
{
|
||||
CFsmEvent* pEvent = it->second;
|
||||
if ( pEvent ) pEvent->SetParamRef( pEventParam );
|
||||
}
|
||||
|
||||
// Valid transition?
|
||||
if ( !pTransition->ApplyConditions() ) return false;
|
||||
|
||||
// Run transition actions
|
||||
if ( !pTransition->RunActions() ) return false;
|
||||
|
||||
// Switch state
|
||||
SetCurrState( pTransition->GetNextState() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsDone()
|
||||
// Desc: Tests whether the state machine has finished its work
|
||||
// Note: This is state machine specific
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsDone( void ) const
|
||||
{
|
||||
// By default the internal flag m_Done is tested
|
||||
return m_Done;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsValidState()
|
||||
// Desc: Verifies whether the specified state is managed by FSM
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsValidState( unsigned int state ) const
|
||||
{
|
||||
StateSet::const_iterator it = m_States.find( state );
|
||||
if ( it == m_States.end() ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsValidEvent()
|
||||
// Desc: Verifies whether the specified event is managed by FSM
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsValidEvent( unsigned int eventType ) const
|
||||
{
|
||||
EventMap::const_iterator it = m_Events.find( eventType );
|
||||
if ( it == m_Events.end() ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : fsm.cpp
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Finite state machine class implementation
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// INCLUDES
|
||||
#include "precompiled.h"
|
||||
#include "fsm.h"
|
||||
|
||||
// DECLARATIONS
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CFsmEvent()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmEvent::CFsmEvent( unsigned int type )
|
||||
{
|
||||
m_Type = type;
|
||||
m_Param = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name; ~CFsmEvent()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmEvent::~CFsmEvent( void )
|
||||
{
|
||||
m_Param = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetParamRef()
|
||||
// Desc: Sets the parameter for the event
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmEvent::SetParamRef( void* pParam )
|
||||
{
|
||||
m_Param = pParam;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CFsmTransition()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition::CFsmTransition( unsigned int state )
|
||||
{
|
||||
m_CurrState = state;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CFsmTransition()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition::~CFsmTransition( void )
|
||||
{
|
||||
m_Actions.clear();
|
||||
m_Conditions.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: RegisterAction()
|
||||
// Desc: Adds action that will be executed when the transition will occur
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::RegisterAction( void* pAction, void* pContext )
|
||||
{
|
||||
CallbackFunction callback;
|
||||
|
||||
// Add action at the end of actions list
|
||||
callback.pFunction = pAction;
|
||||
callback.pContext = pContext;
|
||||
|
||||
m_Actions.push_back( callback );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddCondition()
|
||||
// Desc: Adds condition which will be evaluated when the transition will occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::RegisterCondition( void* pCondition, void* pContext )
|
||||
{
|
||||
CallbackFunction callback;
|
||||
|
||||
// Add condition at the end of conditions list
|
||||
callback.pFunction = pCondition;
|
||||
callback.pContext = pContext;
|
||||
|
||||
m_Conditions.push_back( callback );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetEvent()
|
||||
// Desc: Set event for which transition will occur
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::SetEvent( CFsmEvent* pEvent )
|
||||
{
|
||||
m_Event = pEvent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetNextState()
|
||||
// Desc: Set next state the transition will switch the system to
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsmTransition::SetNextState( unsigned int nextState )
|
||||
{
|
||||
m_NextState = nextState;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ApplyConditions()
|
||||
// Desc: Evaluate conditions for the transition
|
||||
// Note: If there are no conditions, assume true
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsmTransition::ApplyConditions( void ) const
|
||||
{
|
||||
bool eval = true;
|
||||
|
||||
CallbackList::const_iterator it = m_Conditions.begin();
|
||||
for( ; it != m_Conditions.end(); it++ )
|
||||
{
|
||||
if ( it->pFunction )
|
||||
{
|
||||
// Evaluate condition
|
||||
CONDITION Condition = ( CONDITION )it->pFunction;
|
||||
eval &= Condition( it->pContext );
|
||||
}
|
||||
}
|
||||
|
||||
return eval;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: RunActions()
|
||||
// Desc: Execur actions for the transition
|
||||
// Note: If there are no actions, assume true
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsmTransition::RunActions( void ) const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
CallbackList::const_iterator it = m_Actions.begin();
|
||||
for( ; it != m_Actions.end(); it++ )
|
||||
{
|
||||
if ( it->pFunction )
|
||||
{
|
||||
// Run action
|
||||
ACTION Action = ( ACTION )it->pFunction;
|
||||
result &= Action( it->pContext, m_Event );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CFsm()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsm::CFsm( void )
|
||||
{
|
||||
m_Done = false;
|
||||
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
|
||||
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CFsm()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsm::~CFsm( void )
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Setup()
|
||||
// Desc: Setup events, actions and state transitions
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::Setup( void )
|
||||
{
|
||||
// Does nothing by default
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Reset()
|
||||
// Desc: Shuts down the state machine and releases any resources
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::Shutdown( void )
|
||||
{
|
||||
// Release transitions
|
||||
TransitionList::iterator itTransition = m_Transitions.begin();
|
||||
for ( ; itTransition < m_Transitions.end(); itTransition++ )
|
||||
{
|
||||
CFsmTransition* pCurrTransition = *itTransition;
|
||||
if ( !pCurrTransition ) continue;
|
||||
|
||||
delete pCurrTransition;
|
||||
}
|
||||
|
||||
// Release events
|
||||
EventMap::iterator itEvent = m_Events.begin();
|
||||
for( ; itEvent != m_Events.end(); itEvent++ )
|
||||
{
|
||||
CFsmEvent* pCurrEvent = itEvent->second;
|
||||
if ( !pCurrEvent ) continue;
|
||||
|
||||
delete pCurrEvent;
|
||||
}
|
||||
|
||||
m_States.clear();
|
||||
m_Events.clear();
|
||||
m_Transitions.clear();
|
||||
|
||||
m_Done = false;
|
||||
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
|
||||
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddState()
|
||||
// Desc: Adds the specified state to the internal list of states
|
||||
// Note: If a state with the specified ID exists, the state is not added
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::AddState( unsigned int state )
|
||||
{
|
||||
m_States.insert( state );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddEvent()
|
||||
// Desc: Adds the specified event to the internal list of events
|
||||
// Note: If an eveny with the specified ID exists, the event is not added
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmEvent* CFsm::AddEvent( unsigned int eventType )
|
||||
{
|
||||
CFsmEvent* pEvent = NULL;
|
||||
|
||||
// Lookup event by type
|
||||
EventMap::iterator it = m_Events.find( eventType );
|
||||
if ( it != m_Events.end() )
|
||||
{
|
||||
pEvent = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEvent = new CFsmEvent( eventType );
|
||||
if ( !pEvent ) return NULL;
|
||||
|
||||
// Store new event into internal map
|
||||
m_Events[ eventType ] = pEvent;
|
||||
}
|
||||
|
||||
return pEvent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddTransition()
|
||||
// Desc: Adds a new transistion to the state machine
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition* CFsm::AddTransition(
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState )
|
||||
{
|
||||
// Make sure we store the current state
|
||||
AddState( state );
|
||||
|
||||
// Make sure we store the next state
|
||||
AddState( nextState );
|
||||
|
||||
// Make sure we store the event
|
||||
CFsmEvent* pEvent = AddEvent( eventType );
|
||||
if ( !pEvent ) return NULL;
|
||||
|
||||
// Create new transition
|
||||
CFsmTransition* pNewTransition = new CFsmTransition( state );
|
||||
if ( !pNewTransition ) return NULL;
|
||||
|
||||
// Setup new transition
|
||||
pNewTransition->SetEvent( pEvent );
|
||||
pNewTransition->SetNextState( nextState );
|
||||
|
||||
// Store new transition
|
||||
m_Transitions.push_back( pNewTransition );
|
||||
|
||||
return pNewTransition;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddTransition()
|
||||
// Desc: Adds a new transistion to the state machine
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition* CFsm::AddTransition(
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState,
|
||||
void* pAction,
|
||||
void* pContext )
|
||||
{
|
||||
CFsmTransition* pTransition = AddTransition( state, eventType, nextState );
|
||||
if ( !pTransition ) return NULL;
|
||||
|
||||
// If action specified, register it
|
||||
if ( pAction )
|
||||
pTransition->RegisterAction( pAction, pContext );
|
||||
|
||||
return pTransition;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: GetTransition()
|
||||
// Desc: Lookup transition given the state, event and next state to transition
|
||||
//-----------------------------------------------------------------------------
|
||||
CFsmTransition* CFsm::GetTransition(
|
||||
unsigned int state,
|
||||
unsigned int eventType ) const
|
||||
{
|
||||
// Valid state?
|
||||
if ( !IsValidState( state ) ) return NULL;
|
||||
|
||||
// Valid event?
|
||||
if ( !IsValidEvent( eventType ) ) return NULL;
|
||||
|
||||
// Loop through the list of transitions
|
||||
TransitionList::const_iterator it = m_Transitions.begin();
|
||||
for ( ; it != m_Transitions.end(); it++ )
|
||||
{
|
||||
CFsmTransition* pCurrTransition = *it;
|
||||
if ( !pCurrTransition ) continue;
|
||||
|
||||
CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
|
||||
if ( !pCurrEvent ) continue;
|
||||
|
||||
// Is it our transition?
|
||||
if ( pCurrTransition->GetCurrState() == state &&
|
||||
pCurrEvent->GetType() == eventType )
|
||||
{
|
||||
return pCurrTransition;
|
||||
}
|
||||
}
|
||||
|
||||
// No transition found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetFirstState()
|
||||
// Desc: Set initial state for FSM
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::SetFirstState( unsigned int firstState )
|
||||
{
|
||||
m_FirstState = firstState;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetCurrState()
|
||||
// Desc: Set current state and update last state to current state
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFsm::SetCurrState( unsigned int state )
|
||||
{
|
||||
m_CurrState = state;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsFirstTime()
|
||||
// Desc: Verifies if the state machine has been already updated
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsFirstTime( void ) const
|
||||
{
|
||||
return ( m_CurrState == FSM_INVALID_STATE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Update()
|
||||
// Desc: Updates state machine and retrieves next state
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::Update( unsigned int eventType, void* pEventParam )
|
||||
{
|
||||
// Valid event?
|
||||
if ( !IsValidEvent( eventType ) )
|
||||
return false;
|
||||
|
||||
// First time update?
|
||||
if ( IsFirstTime() )
|
||||
m_CurrState = m_FirstState;
|
||||
|
||||
// Lookup transition
|
||||
CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
|
||||
if ( !pTransition ) return false;
|
||||
|
||||
// Setup event parameter
|
||||
EventMap::iterator it = m_Events.find( eventType );
|
||||
if ( it != m_Events.end() )
|
||||
{
|
||||
CFsmEvent* pEvent = it->second;
|
||||
if ( pEvent ) pEvent->SetParamRef( pEventParam );
|
||||
}
|
||||
|
||||
// Valid transition?
|
||||
if ( !pTransition->ApplyConditions() ) return false;
|
||||
|
||||
// Run transition actions
|
||||
if ( !pTransition->RunActions() ) return false;
|
||||
|
||||
// Switch state
|
||||
SetCurrState( pTransition->GetNextState() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsDone()
|
||||
// Desc: Tests whether the state machine has finished its work
|
||||
// Note: This is state machine specific
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsDone( void ) const
|
||||
{
|
||||
// By default the internal flag m_Done is tested
|
||||
return m_Done;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsValidState()
|
||||
// Desc: Verifies whether the specified state is managed by FSM
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsValidState( unsigned int state ) const
|
||||
{
|
||||
StateSet::const_iterator it = m_States.find( state );
|
||||
if ( it == m_States.end() ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: IsValidEvent()
|
||||
// Desc: Verifies whether the specified event is managed by FSM
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFsm::IsValidEvent( unsigned int eventType ) const
|
||||
{
|
||||
EventMap::const_iterator it = m_Events.find( eventType );
|
||||
if ( it == m_Events.end() ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,193 +1,193 @@
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : fsm.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Finite state machine class definitions
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef FSM_H
|
||||
#define FSM_H
|
||||
|
||||
// INCLUDES
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
// DECLARATIONS
|
||||
#define FSM_INVALID_STATE ( unsigned int )( ~0 )
|
||||
|
||||
class CFsmEvent;
|
||||
class CFsmTransition;
|
||||
class CFsm;
|
||||
|
||||
typedef bool ( *CONDITION ) ( void* pContext );
|
||||
typedef bool ( *ACTION ) ( void* pContext, const CFsmEvent* pEvent );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* pFunction;
|
||||
void* pContext;
|
||||
|
||||
} CallbackFunction;
|
||||
|
||||
typedef std::set< unsigned int > StateSet;
|
||||
typedef std::map< unsigned int, CFsmEvent* > EventMap;
|
||||
typedef std::vector< CFsmTransition* > TransitionList;
|
||||
typedef std::vector< CallbackFunction > CallbackList;
|
||||
|
||||
/*
|
||||
CLASS : CFsmEvent
|
||||
DESCRIPTION : CFsmEvent class represents a signal in the state machine
|
||||
that a change has occured.
|
||||
NOTES : The CFsmEvent objects are under the control of CFsm so
|
||||
they are created and deleted via CFsm.
|
||||
*/
|
||||
|
||||
class CFsmEvent
|
||||
{
|
||||
public:
|
||||
|
||||
CFsmEvent( unsigned int type );
|
||||
~CFsmEvent( void );
|
||||
|
||||
unsigned int GetType ( void ) const { return m_Type; }
|
||||
void* GetParamRef ( void ) { return m_Param; }
|
||||
void SetParamRef ( void* pParam );
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsmEvent( const CFsmEvent& );
|
||||
CFsmEvent& operator=( const CFsmEvent& );
|
||||
|
||||
unsigned int m_Type; // Event type
|
||||
void* m_Param; // Event paramater
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
CLASS : CFsmTransition
|
||||
DESCRIPTION : The CFsmTransition class is an association of event, condition,
|
||||
action and next state.
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CFsmTransition
|
||||
{
|
||||
public:
|
||||
|
||||
CFsmTransition( unsigned int state );
|
||||
~CFsmTransition( void );
|
||||
|
||||
void RegisterAction (
|
||||
void* pAction,
|
||||
void* pContext );
|
||||
void RegisterCondition (
|
||||
void* pCondition,
|
||||
void* pContext );
|
||||
void SetEvent ( CFsmEvent* pEvent );
|
||||
CFsmEvent* GetEvent ( void ) const { return m_Event; }
|
||||
void SetNextState ( unsigned int nextState );
|
||||
unsigned int GetNextState ( void ) const { return m_NextState; }
|
||||
unsigned int GetCurrState ( void ) const { return m_CurrState; }
|
||||
const CallbackList& GetActions ( void ) const { return m_Actions; }
|
||||
const CallbackList& GetConditions ( void ) const { return m_Conditions; }
|
||||
bool ApplyConditions ( void ) const;
|
||||
bool RunActions ( void ) const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsmTransition( const CFsmTransition& );
|
||||
CFsmTransition& operator=( const CFsmTransition& );
|
||||
|
||||
unsigned int m_CurrState; // Current state
|
||||
unsigned int m_NextState; // Next state
|
||||
CFsmEvent* m_Event; // Transition event
|
||||
CallbackList m_Actions; // List of actions for transition
|
||||
CallbackList m_Conditions; // List of conditions for transition
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CFsm
|
||||
DESCRIPTION : CFsm manages states, events, actions and transitions
|
||||
between states. It provides an interface for advertising
|
||||
events and track the current state. The implementation is
|
||||
a Mealy state machine, so the system respond to events
|
||||
and execute some action.
|
||||
NOTES : A Mealy state machine has behaviour associated with state
|
||||
transitions; Mealy machines are event driven where an
|
||||
event triggers a state transition
|
||||
*/
|
||||
|
||||
class CFsm
|
||||
{
|
||||
public:
|
||||
|
||||
CFsm( void );
|
||||
~CFsm( void );
|
||||
|
||||
/**
|
||||
* Constructs the state machine. This method must be overriden so that
|
||||
* connections are constructed for the particular state machine implemented
|
||||
*
|
||||
*/
|
||||
virtual void Setup( void );
|
||||
|
||||
/**
|
||||
* Clear event, action and condition lists and reset state machine
|
||||
*
|
||||
*/
|
||||
void Shutdown( void );
|
||||
|
||||
void AddState ( unsigned int state );
|
||||
CFsmEvent* AddEvent ( unsigned int eventType );
|
||||
CFsmTransition* AddTransition (
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState );
|
||||
CFsmTransition* AddTransition (
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState,
|
||||
void* pAction,
|
||||
void* pContext );
|
||||
CFsmTransition* GetTransition (
|
||||
unsigned int state,
|
||||
unsigned int eventType ) const;
|
||||
CFsmTransition* GetEventTransition ( unsigned int eventType ) const;
|
||||
void SetFirstState ( unsigned int firstState );
|
||||
unsigned int GetCurrState ( void ) const { return m_CurrState; }
|
||||
const StateSet& GetStates ( void ) const { return m_States; }
|
||||
const EventMap& GetEvents ( void ) const { return m_Events; }
|
||||
const TransitionList& GetTransitions ( void ) const { return m_Transitions; }
|
||||
bool Update ( unsigned int eventType, void* pEventData );
|
||||
bool IsValidState ( unsigned int state ) const;
|
||||
bool IsValidEvent ( unsigned int eventType ) const;
|
||||
virtual bool IsDone ( void ) const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsm( const CFsm& );
|
||||
CFsm& operator=( const CFsm& );
|
||||
|
||||
void SetCurrState ( unsigned int state );
|
||||
bool IsFirstTime ( void ) const;
|
||||
|
||||
bool m_Done; // FSM work is done
|
||||
unsigned int m_FirstState; // Initial state
|
||||
unsigned int m_CurrState; // Current state
|
||||
StateSet m_States; // List of states
|
||||
EventMap m_Events; // List of events
|
||||
TransitionList m_Transitions; // State transitions
|
||||
};
|
||||
|
||||
#endif // FSM_H
|
||||
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : fsm.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Finite state machine class definitions
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef FSM_H
|
||||
#define FSM_H
|
||||
|
||||
// INCLUDES
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
// DECLARATIONS
|
||||
#define FSM_INVALID_STATE ( unsigned int )( ~0 )
|
||||
|
||||
class CFsmEvent;
|
||||
class CFsmTransition;
|
||||
class CFsm;
|
||||
|
||||
typedef bool ( *CONDITION ) ( void* pContext );
|
||||
typedef bool ( *ACTION ) ( void* pContext, const CFsmEvent* pEvent );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* pFunction;
|
||||
void* pContext;
|
||||
|
||||
} CallbackFunction;
|
||||
|
||||
typedef std::set< unsigned int > StateSet;
|
||||
typedef std::map< unsigned int, CFsmEvent* > EventMap;
|
||||
typedef std::vector< CFsmTransition* > TransitionList;
|
||||
typedef std::vector< CallbackFunction > CallbackList;
|
||||
|
||||
/*
|
||||
CLASS : CFsmEvent
|
||||
DESCRIPTION : CFsmEvent class represents a signal in the state machine
|
||||
that a change has occured.
|
||||
NOTES : The CFsmEvent objects are under the control of CFsm so
|
||||
they are created and deleted via CFsm.
|
||||
*/
|
||||
|
||||
class CFsmEvent
|
||||
{
|
||||
public:
|
||||
|
||||
CFsmEvent( unsigned int type );
|
||||
~CFsmEvent( void );
|
||||
|
||||
unsigned int GetType ( void ) const { return m_Type; }
|
||||
void* GetParamRef ( void ) { return m_Param; }
|
||||
void SetParamRef ( void* pParam );
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsmEvent( const CFsmEvent& );
|
||||
CFsmEvent& operator=( const CFsmEvent& );
|
||||
|
||||
unsigned int m_Type; // Event type
|
||||
void* m_Param; // Event paramater
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
CLASS : CFsmTransition
|
||||
DESCRIPTION : The CFsmTransition class is an association of event, condition,
|
||||
action and next state.
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CFsmTransition
|
||||
{
|
||||
public:
|
||||
|
||||
CFsmTransition( unsigned int state );
|
||||
~CFsmTransition( void );
|
||||
|
||||
void RegisterAction (
|
||||
void* pAction,
|
||||
void* pContext );
|
||||
void RegisterCondition (
|
||||
void* pCondition,
|
||||
void* pContext );
|
||||
void SetEvent ( CFsmEvent* pEvent );
|
||||
CFsmEvent* GetEvent ( void ) const { return m_Event; }
|
||||
void SetNextState ( unsigned int nextState );
|
||||
unsigned int GetNextState ( void ) const { return m_NextState; }
|
||||
unsigned int GetCurrState ( void ) const { return m_CurrState; }
|
||||
const CallbackList& GetActions ( void ) const { return m_Actions; }
|
||||
const CallbackList& GetConditions ( void ) const { return m_Conditions; }
|
||||
bool ApplyConditions ( void ) const;
|
||||
bool RunActions ( void ) const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsmTransition( const CFsmTransition& );
|
||||
CFsmTransition& operator=( const CFsmTransition& );
|
||||
|
||||
unsigned int m_CurrState; // Current state
|
||||
unsigned int m_NextState; // Next state
|
||||
CFsmEvent* m_Event; // Transition event
|
||||
CallbackList m_Actions; // List of actions for transition
|
||||
CallbackList m_Conditions; // List of conditions for transition
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CFsm
|
||||
DESCRIPTION : CFsm manages states, events, actions and transitions
|
||||
between states. It provides an interface for advertising
|
||||
events and track the current state. The implementation is
|
||||
a Mealy state machine, so the system respond to events
|
||||
and execute some action.
|
||||
NOTES : A Mealy state machine has behaviour associated with state
|
||||
transitions; Mealy machines are event driven where an
|
||||
event triggers a state transition
|
||||
*/
|
||||
|
||||
class CFsm
|
||||
{
|
||||
public:
|
||||
|
||||
CFsm( void );
|
||||
~CFsm( void );
|
||||
|
||||
/**
|
||||
* Constructs the state machine. This method must be overriden so that
|
||||
* connections are constructed for the particular state machine implemented
|
||||
*
|
||||
*/
|
||||
virtual void Setup( void );
|
||||
|
||||
/**
|
||||
* Clear event, action and condition lists and reset state machine
|
||||
*
|
||||
*/
|
||||
void Shutdown( void );
|
||||
|
||||
void AddState ( unsigned int state );
|
||||
CFsmEvent* AddEvent ( unsigned int eventType );
|
||||
CFsmTransition* AddTransition (
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState );
|
||||
CFsmTransition* AddTransition (
|
||||
unsigned int state,
|
||||
unsigned int eventType,
|
||||
unsigned int nextState,
|
||||
void* pAction,
|
||||
void* pContext );
|
||||
CFsmTransition* GetTransition (
|
||||
unsigned int state,
|
||||
unsigned int eventType ) const;
|
||||
CFsmTransition* GetEventTransition ( unsigned int eventType ) const;
|
||||
void SetFirstState ( unsigned int firstState );
|
||||
unsigned int GetCurrState ( void ) const { return m_CurrState; }
|
||||
const StateSet& GetStates ( void ) const { return m_States; }
|
||||
const EventMap& GetEvents ( void ) const { return m_Events; }
|
||||
const TransitionList& GetTransitions ( void ) const { return m_Transitions; }
|
||||
bool Update ( unsigned int eventType, void* pEventData );
|
||||
bool IsValidState ( unsigned int state ) const;
|
||||
bool IsValidEvent ( unsigned int eventType ) const;
|
||||
virtual bool IsDone ( void ) const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsm( const CFsm& );
|
||||
CFsm& operator=( const CFsm& );
|
||||
|
||||
void SetCurrState ( unsigned int state );
|
||||
bool IsFirstTime ( void ) const;
|
||||
|
||||
bool m_Done; // FSM work is done
|
||||
unsigned int m_FirstState; // Initial state
|
||||
unsigned int m_CurrState; // Current state
|
||||
StateSet m_States; // List of states
|
||||
EventMap m_Events; // List of events
|
||||
TransitionList m_Transitions; // State transitions
|
||||
};
|
||||
|
||||
#endif // FSM_H
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// Atlas-specific PCH:
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
#include "tools/atlas/GameInterface/Messages.h"
|
||||
#include "ps/CStr.h"
|
||||
|
||||
#endif // HAVE_PCH
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// Atlas-specific PCH:
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
#include "tools/atlas/GameInterface/Messages.h"
|
||||
#include "ps/CStr.h"
|
||||
|
||||
#endif // HAVE_PCH
|
||||
|
@ -1,17 +1,17 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "engine"-specific PCH:
|
||||
|
||||
#include "ps/Pyrogenesis.h" // MICROLOG and old error system
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
// some other external libraries that are used in several places:
|
||||
// .. CStr is included very frequently, so a reasonable amount of time is
|
||||
// saved by including it here. (~10% in a full rebuild, as of r2365)
|
||||
#include "ps/CStr.h"
|
||||
#include "scripting/SpiderMonkey.h"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#endif // HAVE_PCH
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "engine"-specific PCH:
|
||||
|
||||
#include "ps/Pyrogenesis.h" // MICROLOG and old error system
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
// some other external libraries that are used in several places:
|
||||
// .. CStr is included very frequently, so a reasonable amount of time is
|
||||
// saved by including it here. (~10% in a full rebuild, as of r2365)
|
||||
#include "ps/CStr.h"
|
||||
#include "scripting/SpiderMonkey.h"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#endif // HAVE_PCH
|
||||
|
@ -1,3 +1,3 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "graphics"-specific PCH:
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "graphics"-specific PCH:
|
||||
|
@ -1,3 +1,3 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "gui"-specific PCH:
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "gui"-specific PCH:
|
||||
|
@ -1,3 +1,3 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "i18n"-specific PCH:
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "i18n"-specific PCH:
|
||||
|
@ -1,3 +1,3 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "lowlevel"-specific PCH:
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// "lowlevel"-specific PCH:
|
||||
|
@ -1 +1 @@
|
||||
#include "precompiled.h"
|
||||
#include "precompiled.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// network-specific PCH:
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
#endif // HAVE_PCH
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// network-specific PCH:
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
#endif // HAVE_PCH
|
||||
|
@ -1 +1 @@
|
||||
#include "precompiled.h"
|
||||
#include "precompiled.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// se PCH:
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
#endif // HAVE_PCH
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// se PCH:
|
||||
|
||||
#if HAVE_PCH
|
||||
|
||||
#endif // HAVE_PCH
|
||||
|
@ -1,71 +1,71 @@
|
||||
#include "precompiled.h"
|
||||
#include "Filesystem.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
#define LOG_CATEGORY "file"
|
||||
|
||||
|
||||
PIVFS g_VFS;
|
||||
|
||||
bool FileExists(const char* pathname)
|
||||
{
|
||||
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
|
||||
}
|
||||
|
||||
bool FileExists(const VfsPath& pathname)
|
||||
{
|
||||
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CVFSFile::CVFSFile()
|
||||
{
|
||||
}
|
||||
|
||||
CVFSFile::~CVFSFile()
|
||||
{
|
||||
}
|
||||
|
||||
PSRETURN CVFSFile::Load(const VfsPath& filename)
|
||||
{
|
||||
// Load should never be called more than once, so complain
|
||||
if (m_Buffer)
|
||||
{
|
||||
debug_assert(0);
|
||||
return PSRETURN_CVFSFile_AlreadyLoaded;
|
||||
}
|
||||
|
||||
LibError ret = g_VFS->LoadFile(filename, m_Buffer, m_BufferSize);
|
||||
if (ret != INFO::OK)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "CVFSFile: file %s couldn't be opened (vfs_load: %d)", filename.string().c_str(), ret);
|
||||
return PSRETURN_CVFSFile_LoadFailed;
|
||||
}
|
||||
|
||||
return PSRETURN_OK;
|
||||
}
|
||||
|
||||
const u8* CVFSFile::GetBuffer() const
|
||||
{
|
||||
// Die in a very obvious way, to avoid subtle problems caused by
|
||||
// accidentally forgetting to check that the open succeeded
|
||||
if (!m_Buffer)
|
||||
{
|
||||
debug_warn("GetBuffer() called with no file loaded");
|
||||
throw PSERROR_CVFSFile_InvalidBufferAccess();
|
||||
}
|
||||
|
||||
return m_Buffer.get();
|
||||
}
|
||||
|
||||
size_t CVFSFile::GetBufferSize() const
|
||||
{
|
||||
return m_BufferSize;
|
||||
}
|
||||
|
||||
CStr CVFSFile::GetAsString() const
|
||||
{
|
||||
return std::string((char*)GetBuffer(), GetBufferSize());
|
||||
}
|
||||
#include "precompiled.h"
|
||||
#include "Filesystem.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
#define LOG_CATEGORY "file"
|
||||
|
||||
|
||||
PIVFS g_VFS;
|
||||
|
||||
bool FileExists(const char* pathname)
|
||||
{
|
||||
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
|
||||
}
|
||||
|
||||
bool FileExists(const VfsPath& pathname)
|
||||
{
|
||||
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CVFSFile::CVFSFile()
|
||||
{
|
||||
}
|
||||
|
||||
CVFSFile::~CVFSFile()
|
||||
{
|
||||
}
|
||||
|
||||
PSRETURN CVFSFile::Load(const VfsPath& filename)
|
||||
{
|
||||
// Load should never be called more than once, so complain
|
||||
if (m_Buffer)
|
||||
{
|
||||
debug_assert(0);
|
||||
return PSRETURN_CVFSFile_AlreadyLoaded;
|
||||
}
|
||||
|
||||
LibError ret = g_VFS->LoadFile(filename, m_Buffer, m_BufferSize);
|
||||
if (ret != INFO::OK)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "CVFSFile: file %s couldn't be opened (vfs_load: %d)", filename.string().c_str(), ret);
|
||||
return PSRETURN_CVFSFile_LoadFailed;
|
||||
}
|
||||
|
||||
return PSRETURN_OK;
|
||||
}
|
||||
|
||||
const u8* CVFSFile::GetBuffer() const
|
||||
{
|
||||
// Die in a very obvious way, to avoid subtle problems caused by
|
||||
// accidentally forgetting to check that the open succeeded
|
||||
if (!m_Buffer)
|
||||
{
|
||||
debug_warn("GetBuffer() called with no file loaded");
|
||||
throw PSERROR_CVFSFile_InvalidBufferAccess();
|
||||
}
|
||||
|
||||
return m_Buffer.get();
|
||||
}
|
||||
|
||||
size_t CVFSFile::GetBufferSize() const
|
||||
{
|
||||
return m_BufferSize;
|
||||
}
|
||||
|
||||
CStr CVFSFile::GetAsString() const
|
||||
{
|
||||
return std::string((char*)GetBuffer(), GetBufferSize());
|
||||
}
|
||||
|
@ -1,45 +1,45 @@
|
||||
#ifndef INCLUDED_FILESYSTEM
|
||||
#define INCLUDED_FILESYSTEM
|
||||
|
||||
#include "lib/path_util.h"
|
||||
#include "lib/file/file.h"
|
||||
#include "lib/file/io/io.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/io/write_buffer.h"
|
||||
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Errors.h"
|
||||
|
||||
extern PIVFS g_VFS;
|
||||
|
||||
extern bool FileExists(const char* pathname);
|
||||
extern bool FileExists(const VfsPath& pathname);
|
||||
|
||||
ERROR_GROUP(CVFSFile);
|
||||
ERROR_TYPE(CVFSFile, LoadFailed);
|
||||
ERROR_TYPE(CVFSFile, AlreadyLoaded);
|
||||
ERROR_TYPE(CVFSFile, InvalidBufferAccess);
|
||||
|
||||
// Reads a file, then gives read-only access to the contents
|
||||
class CVFSFile
|
||||
{
|
||||
public:
|
||||
CVFSFile();
|
||||
~CVFSFile();
|
||||
|
||||
// Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
|
||||
// Dies if a file has already been successfully loaded.
|
||||
PSRETURN Load(const VfsPath& filename);
|
||||
|
||||
// These die if called when no file has been successfully loaded.
|
||||
const u8* GetBuffer() const;
|
||||
size_t GetBufferSize() const;
|
||||
CStr GetAsString() const;
|
||||
|
||||
private:
|
||||
shared_ptr<u8> m_Buffer;
|
||||
size_t m_BufferSize;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_FILESYSTEM
|
||||
#ifndef INCLUDED_FILESYSTEM
|
||||
#define INCLUDED_FILESYSTEM
|
||||
|
||||
#include "lib/path_util.h"
|
||||
#include "lib/file/file.h"
|
||||
#include "lib/file/io/io.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/io/write_buffer.h"
|
||||
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Errors.h"
|
||||
|
||||
extern PIVFS g_VFS;
|
||||
|
||||
extern bool FileExists(const char* pathname);
|
||||
extern bool FileExists(const VfsPath& pathname);
|
||||
|
||||
ERROR_GROUP(CVFSFile);
|
||||
ERROR_TYPE(CVFSFile, LoadFailed);
|
||||
ERROR_TYPE(CVFSFile, AlreadyLoaded);
|
||||
ERROR_TYPE(CVFSFile, InvalidBufferAccess);
|
||||
|
||||
// Reads a file, then gives read-only access to the contents
|
||||
class CVFSFile
|
||||
{
|
||||
public:
|
||||
CVFSFile();
|
||||
~CVFSFile();
|
||||
|
||||
// Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
|
||||
// Dies if a file has already been successfully loaded.
|
||||
PSRETURN Load(const VfsPath& filename);
|
||||
|
||||
// These die if called when no file has been successfully loaded.
|
||||
const u8* GetBuffer() const;
|
||||
size_t GetBufferSize() const;
|
||||
CStr GetAsString() const;
|
||||
|
||||
private:
|
||||
shared_ptr<u8> m_Buffer;
|
||||
size_t m_BufferSize;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_FILESYSTEM
|
||||
|
@ -1,8 +1,8 @@
|
||||
#ifndef INCLUDED_KEYNAME
|
||||
#define INCLUDED_KEYNAME
|
||||
|
||||
extern void InitKeyNameMap();
|
||||
extern CStr FindKeyName( int keycode );
|
||||
extern int FindKeyCode( const CStr& keyname );
|
||||
|
||||
#endif // #ifndef INCLUDED_KEYNAME
|
||||
#ifndef INCLUDED_KEYNAME
|
||||
#define INCLUDED_KEYNAME
|
||||
|
||||
extern void InitKeyNameMap();
|
||||
extern CStr FindKeyName( int keycode );
|
||||
extern int FindKeyCode( const CStr& keyname );
|
||||
|
||||
#endif // #ifndef INCLUDED_KEYNAME
|
||||
|
@ -1,211 +1,211 @@
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/XML/XMLWriter.h"
|
||||
|
||||
class TestXmlWriter : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test1()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Root");
|
||||
{
|
||||
XML_Comment("Comment test.");
|
||||
XML_Comment("Comment test again.");
|
||||
{
|
||||
XML_Element("a");
|
||||
XML_Attribute("one", 1);
|
||||
XML_Attribute("two", "TWO");
|
||||
XML_Text("b");
|
||||
XML_Text(" (etc)");
|
||||
}
|
||||
{
|
||||
XML_Element("c");
|
||||
XML_Text("d");
|
||||
}
|
||||
XML_Setting("c2", "d2");
|
||||
{
|
||||
XML_Element("e");
|
||||
{
|
||||
{
|
||||
XML_Element("f");
|
||||
XML_Text("g");
|
||||
}
|
||||
{
|
||||
XML_Element("h");
|
||||
}
|
||||
{
|
||||
XML_Element("i");
|
||||
XML_Attribute("j", 1.23);
|
||||
{
|
||||
XML_Element("k");
|
||||
XML_Attribute("l", 2.34);
|
||||
XML_Text("m");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"\n"
|
||||
"<Root>\n"
|
||||
"\t<!-- Comment test. -->\n"
|
||||
"\t<!-- Comment test again. -->\n"
|
||||
"\t<a one=\"1\" two=\"TWO\">b (etc)</a>\n"
|
||||
"\t<c>d</c>\n"
|
||||
"\t<c2>d2</c2>\n"
|
||||
"\t<e>\n"
|
||||
"\t\t<f>g</f>\n"
|
||||
"\t\t<h/>\n"
|
||||
"\t\t<i j=\"1.23\">\n"
|
||||
"\t\t\t<k l=\"2.34\">m</k>\n"
|
||||
"\t\t</i>\n"
|
||||
"\t</e>\n"
|
||||
"</Root>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_basic()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
{
|
||||
XML_Element("example");
|
||||
{
|
||||
XML_Element("content");
|
||||
XML_Text("text");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"\n"
|
||||
"<Test>\n"
|
||||
"\t<example>\n"
|
||||
"\t\t<content>text</content>\n"
|
||||
"\t</example>\n"
|
||||
"</Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_nonpretty()
|
||||
{
|
||||
XML_Start();
|
||||
XML_SetPrettyPrint(false);
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
{
|
||||
XML_Element("example");
|
||||
{
|
||||
XML_Element("content");
|
||||
XML_Text("text");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<Test><example><content>text</content></example></Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_text()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Text("a");
|
||||
XML_Text("b");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"\n"
|
||||
"<Test>ab</Test>"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void test_utf8()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
{
|
||||
const wchar_t text[] = { 0x0251, 0 };
|
||||
XML_Text(text);
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test>\xC9\x91</Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_attr_escape()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Attribute("example", "abc > ]]> < & \"\" ");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test example=\"abc > ]]> < & "" \"/>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_chardata_escape()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Text("abc > ]]> < & \"\" ");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test>abc > ]]> < & \"\" </Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_comment_escape()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Comment("test - -- --- ---- test");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test>\n"
|
||||
"\t<!-- test - \xE2\x80\x90\xE2\x80\x90 \xE2\x80\x90\xE2\x80\x90- \xE2\x80\x90\xE2\x80\x90\xE2\x80\x90\xE2\x80\x90 test -->\n"
|
||||
"</Test>"
|
||||
);
|
||||
}
|
||||
};
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/XML/XMLWriter.h"
|
||||
|
||||
class TestXmlWriter : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test1()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Root");
|
||||
{
|
||||
XML_Comment("Comment test.");
|
||||
XML_Comment("Comment test again.");
|
||||
{
|
||||
XML_Element("a");
|
||||
XML_Attribute("one", 1);
|
||||
XML_Attribute("two", "TWO");
|
||||
XML_Text("b");
|
||||
XML_Text(" (etc)");
|
||||
}
|
||||
{
|
||||
XML_Element("c");
|
||||
XML_Text("d");
|
||||
}
|
||||
XML_Setting("c2", "d2");
|
||||
{
|
||||
XML_Element("e");
|
||||
{
|
||||
{
|
||||
XML_Element("f");
|
||||
XML_Text("g");
|
||||
}
|
||||
{
|
||||
XML_Element("h");
|
||||
}
|
||||
{
|
||||
XML_Element("i");
|
||||
XML_Attribute("j", 1.23);
|
||||
{
|
||||
XML_Element("k");
|
||||
XML_Attribute("l", 2.34);
|
||||
XML_Text("m");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"\n"
|
||||
"<Root>\n"
|
||||
"\t<!-- Comment test. -->\n"
|
||||
"\t<!-- Comment test again. -->\n"
|
||||
"\t<a one=\"1\" two=\"TWO\">b (etc)</a>\n"
|
||||
"\t<c>d</c>\n"
|
||||
"\t<c2>d2</c2>\n"
|
||||
"\t<e>\n"
|
||||
"\t\t<f>g</f>\n"
|
||||
"\t\t<h/>\n"
|
||||
"\t\t<i j=\"1.23\">\n"
|
||||
"\t\t\t<k l=\"2.34\">m</k>\n"
|
||||
"\t\t</i>\n"
|
||||
"\t</e>\n"
|
||||
"</Root>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_basic()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
{
|
||||
XML_Element("example");
|
||||
{
|
||||
XML_Element("content");
|
||||
XML_Text("text");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"\n"
|
||||
"<Test>\n"
|
||||
"\t<example>\n"
|
||||
"\t\t<content>text</content>\n"
|
||||
"\t</example>\n"
|
||||
"</Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_nonpretty()
|
||||
{
|
||||
XML_Start();
|
||||
XML_SetPrettyPrint(false);
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
{
|
||||
XML_Element("example");
|
||||
{
|
||||
XML_Element("content");
|
||||
XML_Text("text");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<Test><example><content>text</content></example></Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_text()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Text("a");
|
||||
XML_Text("b");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"\n"
|
||||
"<Test>ab</Test>"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void test_utf8()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
{
|
||||
const wchar_t text[] = { 0x0251, 0 };
|
||||
XML_Text(text);
|
||||
}
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test>\xC9\x91</Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_attr_escape()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Attribute("example", "abc > ]]> < & \"\" ");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test example=\"abc > ]]> < & "" \"/>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_chardata_escape()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Text("abc > ]]> < & \"\" ");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test>abc > ]]> < & \"\" </Test>"
|
||||
);
|
||||
}
|
||||
|
||||
void test_comment_escape()
|
||||
{
|
||||
XML_Start();
|
||||
|
||||
{
|
||||
XML_Element("Test");
|
||||
XML_Comment("test - -- --- ---- test");
|
||||
}
|
||||
|
||||
CStr output = XML_GetOutput();
|
||||
TS_ASSERT_STR_EQUALS(output,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
|
||||
"<Test>\n"
|
||||
"\t<!-- test - \xE2\x80\x90\xE2\x80\x90 \xE2\x80\x90\xE2\x80\x90- \xE2\x80\x90\xE2\x80\x90\xE2\x80\x90\xE2\x80\x90 test -->\n"
|
||||
"</Test>"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include "lib/self_test.h"
|
||||
|
||||
// usually defined by main.cpp, used by engine's scripting/ScriptGlue.cpp,
|
||||
// must be included here to placate linker.
|
||||
void kill_mainloop()
|
||||
{
|
||||
}
|
||||
|
||||
// just so that cxxtestgen doesn't complain "No tests defined"
|
||||
class TestDummy : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_dummy()
|
||||
{
|
||||
}
|
||||
};
|
||||
#include "lib/self_test.h"
|
||||
|
||||
// usually defined by main.cpp, used by engine's scripting/ScriptGlue.cpp,
|
||||
// must be included here to placate linker.
|
||||
void kill_mainloop()
|
||||
{
|
||||
}
|
||||
|
||||
// just so that cxxtestgen doesn't complain "No tests defined"
|
||||
class TestDummy : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_dummy()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -1,52 +1,52 @@
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/CStr.h"
|
||||
|
||||
class TestCStr : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_utf8_utf16_conversion()
|
||||
{
|
||||
const wchar_t chr_utf16[] = {
|
||||
0x12,
|
||||
0xff,
|
||||
0x1234,
|
||||
0x3456,
|
||||
0x5678,
|
||||
0x7890,
|
||||
0x9abc,
|
||||
0xbcde,
|
||||
0xfffe
|
||||
};
|
||||
const unsigned char chr_utf8[] = {
|
||||
0x12,
|
||||
0xc3, 0xbf,
|
||||
0xe1, 0x88, 0xb4,
|
||||
0xe3, 0x91, 0x96,
|
||||
0xe5, 0x99, 0xb8,
|
||||
0xe7, 0xa2, 0x90,
|
||||
0xe9, 0xaa, 0xbc,
|
||||
0xeb, 0xb3, 0x9e,
|
||||
0xef, 0xbf, 0xbe
|
||||
};
|
||||
CStrW str_utf16 (chr_utf16, sizeof(chr_utf16)/sizeof(wchar_t));
|
||||
|
||||
CStr8 str_utf8 = str_utf16.ToUTF8();
|
||||
TS_ASSERT_EQUALS(str_utf8.length(), sizeof(chr_utf8));
|
||||
TS_ASSERT_SAME_DATA(str_utf8.data(), chr_utf8, sizeof(chr_utf8));
|
||||
|
||||
CStrW str_utf16b = str_utf8.FromUTF8();
|
||||
TS_ASSERT_WSTR_EQUALS(str_utf16b, str_utf16);
|
||||
}
|
||||
|
||||
void test_invalid_utf8()
|
||||
{
|
||||
const unsigned char chr_utf8_a[] = { 'a', 0xef };
|
||||
const unsigned char chr_utf8_b[] = { 'b', 0xef, 0xbf };
|
||||
const unsigned char chr_utf8_c[] = { 'c', 0xef, 0xbf, 0x01 };
|
||||
|
||||
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_a, sizeof(chr_utf8_a)).FromUTF8(), L"");
|
||||
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_b, sizeof(chr_utf8_b)).FromUTF8(), L"");
|
||||
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_c, sizeof(chr_utf8_c)).FromUTF8(), L"");
|
||||
}
|
||||
};
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/CStr.h"
|
||||
|
||||
class TestCStr : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_utf8_utf16_conversion()
|
||||
{
|
||||
const wchar_t chr_utf16[] = {
|
||||
0x12,
|
||||
0xff,
|
||||
0x1234,
|
||||
0x3456,
|
||||
0x5678,
|
||||
0x7890,
|
||||
0x9abc,
|
||||
0xbcde,
|
||||
0xfffe
|
||||
};
|
||||
const unsigned char chr_utf8[] = {
|
||||
0x12,
|
||||
0xc3, 0xbf,
|
||||
0xe1, 0x88, 0xb4,
|
||||
0xe3, 0x91, 0x96,
|
||||
0xe5, 0x99, 0xb8,
|
||||
0xe7, 0xa2, 0x90,
|
||||
0xe9, 0xaa, 0xbc,
|
||||
0xeb, 0xb3, 0x9e,
|
||||
0xef, 0xbf, 0xbe
|
||||
};
|
||||
CStrW str_utf16 (chr_utf16, sizeof(chr_utf16)/sizeof(wchar_t));
|
||||
|
||||
CStr8 str_utf8 = str_utf16.ToUTF8();
|
||||
TS_ASSERT_EQUALS(str_utf8.length(), sizeof(chr_utf8));
|
||||
TS_ASSERT_SAME_DATA(str_utf8.data(), chr_utf8, sizeof(chr_utf8));
|
||||
|
||||
CStrW str_utf16b = str_utf8.FromUTF8();
|
||||
TS_ASSERT_WSTR_EQUALS(str_utf16b, str_utf16);
|
||||
}
|
||||
|
||||
void test_invalid_utf8()
|
||||
{
|
||||
const unsigned char chr_utf8_a[] = { 'a', 0xef };
|
||||
const unsigned char chr_utf8_b[] = { 'b', 0xef, 0xbf };
|
||||
const unsigned char chr_utf8_c[] = { 'c', 0xef, 0xbf, 0x01 };
|
||||
|
||||
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_a, sizeof(chr_utf8_a)).FromUTF8(), L"");
|
||||
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_b, sizeof(chr_utf8_b)).FromUTF8(), L"");
|
||||
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_c, sizeof(chr_utf8_c)).FromUTF8(), L"");
|
||||
}
|
||||
};
|
||||
|
@ -1,95 +1,95 @@
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/Parser.h"
|
||||
|
||||
class TestParser : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test1()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "_$ident_=_$value_");
|
||||
|
||||
std::string str;
|
||||
int i;
|
||||
|
||||
CParserLine Line;
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "value=23"));
|
||||
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "value");
|
||||
TS_ASSERT(Line.GetArgInt(1, i) && i == 23);
|
||||
}
|
||||
|
||||
|
||||
void test2()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "_$value_[$value]_");
|
||||
|
||||
std::string str;
|
||||
|
||||
CParserLine Line;
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "12 34"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
|
||||
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "56"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "56");
|
||||
|
||||
TS_ASSERT(! Line.ParseString(Parser, " "));
|
||||
}
|
||||
|
||||
|
||||
void test3()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "_[$value]_[$value]_[$value]_");
|
||||
|
||||
std::string str;
|
||||
|
||||
CParserLine Line;
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "12 34 56"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 3);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
|
||||
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
|
||||
TS_ASSERT(Line.GetArgString(2, str) && str == "56");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "78 90"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "78");
|
||||
TS_ASSERT(Line.GetArgString(1, str) && str == "90");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "ab"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "ab");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, " "));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 0);
|
||||
}
|
||||
|
||||
|
||||
void test4()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "<[_a_][_b_]_x_>");
|
||||
|
||||
std::string str;
|
||||
|
||||
CParserLine Line;
|
||||
TS_ASSERT(Line.ParseString(Parser, "a b x a b x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "a x b x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "a x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "b x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "x"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a x c x"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a b a x"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a a x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "a x a b x a x b x b x b x b x a x a x a b x a b x b x a x"));
|
||||
}
|
||||
};
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/Parser.h"
|
||||
|
||||
class TestParser : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test1()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "_$ident_=_$value_");
|
||||
|
||||
std::string str;
|
||||
int i;
|
||||
|
||||
CParserLine Line;
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "value=23"));
|
||||
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "value");
|
||||
TS_ASSERT(Line.GetArgInt(1, i) && i == 23);
|
||||
}
|
||||
|
||||
|
||||
void test2()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "_$value_[$value]_");
|
||||
|
||||
std::string str;
|
||||
|
||||
CParserLine Line;
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "12 34"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
|
||||
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "56"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "56");
|
||||
|
||||
TS_ASSERT(! Line.ParseString(Parser, " "));
|
||||
}
|
||||
|
||||
|
||||
void test3()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "_[$value]_[$value]_[$value]_");
|
||||
|
||||
std::string str;
|
||||
|
||||
CParserLine Line;
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "12 34 56"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 3);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
|
||||
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
|
||||
TS_ASSERT(Line.GetArgString(2, str) && str == "56");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "78 90"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "78");
|
||||
TS_ASSERT(Line.GetArgString(1, str) && str == "90");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, "ab"));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
|
||||
TS_ASSERT(Line.GetArgString(0, str) && str == "ab");
|
||||
|
||||
TS_ASSERT(Line.ParseString(Parser, " "));
|
||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 0);
|
||||
}
|
||||
|
||||
|
||||
void test4()
|
||||
{
|
||||
CParser Parser;
|
||||
Parser.InputTaskType("test", "<[_a_][_b_]_x_>");
|
||||
|
||||
std::string str;
|
||||
|
||||
CParserLine Line;
|
||||
TS_ASSERT(Line.ParseString(Parser, "a b x a b x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "a x b x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "a x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "b x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "x"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a x c x"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a b a x"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a"));
|
||||
TS_ASSERT(! Line.ParseString(Parser, "a a x"));
|
||||
TS_ASSERT(Line.ParseString(Parser, "a x a b x a x b x b x b x b x a x a x a b x a b x b x a x"));
|
||||
}
|
||||
};
|
||||
|
@ -1,32 +1,32 @@
|
||||
/**
|
||||
* File : Scene.cpp
|
||||
* Project : graphics
|
||||
* Description : This file contains default implementations and utilities
|
||||
* : to be used together with the Scene interface and related
|
||||
* : classes.
|
||||
*
|
||||
* @note This file would fit just as well into the graphics/ subdirectory.
|
||||
**/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "graphics/Model.h"
|
||||
|
||||
#include "renderer/Scene.h"
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Default implementation traverses the model recursively and uses
|
||||
// SubmitNonRecursive for the actual work.
|
||||
void SceneCollector::SubmitRecursive(CModel* model)
|
||||
{
|
||||
SubmitNonRecursive(model);
|
||||
|
||||
const std::vector<CModel::Prop>& props = model->GetProps();
|
||||
for (size_t i=0;i<props.size();i++) {
|
||||
SubmitRecursive(props[i].m_Model);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* File : Scene.cpp
|
||||
* Project : graphics
|
||||
* Description : This file contains default implementations and utilities
|
||||
* : to be used together with the Scene interface and related
|
||||
* : classes.
|
||||
*
|
||||
* @note This file would fit just as well into the graphics/ subdirectory.
|
||||
**/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "graphics/Model.h"
|
||||
|
||||
#include "renderer/Scene.h"
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Default implementation traverses the model recursively and uses
|
||||
// SubmitNonRecursive for the actual work.
|
||||
void SceneCollector::SubmitRecursive(CModel* model)
|
||||
{
|
||||
SubmitNonRecursive(model);
|
||||
|
||||
const std::vector<CModel::Prop>& props = model->GetProps();
|
||||
for (size_t i=0;i<props.size();i++) {
|
||||
SubmitRecursive(props[i].m_Model);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,67 +1,67 @@
|
||||
/**
|
||||
* File : Scene.h
|
||||
* Project : graphics
|
||||
* Description : This file contains the interfaces that are used to send a
|
||||
* : scene to the renderer, and for the renderer to query objects
|
||||
* : in that scene.
|
||||
*
|
||||
* @note This file would fit just as well into the graphics/ subdirectory.
|
||||
**/
|
||||
|
||||
#ifndef INCLUDED_SCENE
|
||||
#define INCLUDED_SCENE
|
||||
|
||||
class CFrustum;
|
||||
class CModel;
|
||||
class CPatch;
|
||||
|
||||
class SceneCollector;
|
||||
|
||||
/**
|
||||
* This interface describes a scene to the renderer.
|
||||
*
|
||||
* @see CRenderer::RenderScene
|
||||
*/
|
||||
class Scene {
|
||||
public:
|
||||
/**
|
||||
* Send all objects that can be seen when rendering the given frustum
|
||||
* to the scene collector.
|
||||
* @param frustum The frustum that will be used for rendering.
|
||||
* @param c The scene collector that should receive objects inside the frustum
|
||||
* that are visible.
|
||||
*/
|
||||
virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c) = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This interface accepts renderable objects.
|
||||
*
|
||||
* @see Scene::EnumerateObjects
|
||||
*/
|
||||
class SceneCollector {
|
||||
public:
|
||||
/**
|
||||
* Submit a terrain patch that is part of the scene.
|
||||
*/
|
||||
virtual void Submit(CPatch* patch) = 0;
|
||||
|
||||
/**
|
||||
* Submit a model that is part of the scene,
|
||||
* without submitting attached models.
|
||||
*/
|
||||
virtual void SubmitNonRecursive(CModel* model) = 0;
|
||||
|
||||
/**
|
||||
* Submit a model that is part of the scene,
|
||||
* including attached sub-models.
|
||||
*
|
||||
* @note This function is implemented using SubmitNonRecursive,
|
||||
* so you shouldn't have to reimplement it.
|
||||
*/
|
||||
virtual void SubmitRecursive(CModel* model);
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_SCENE
|
||||
/**
|
||||
* File : Scene.h
|
||||
* Project : graphics
|
||||
* Description : This file contains the interfaces that are used to send a
|
||||
* : scene to the renderer, and for the renderer to query objects
|
||||
* : in that scene.
|
||||
*
|
||||
* @note This file would fit just as well into the graphics/ subdirectory.
|
||||
**/
|
||||
|
||||
#ifndef INCLUDED_SCENE
|
||||
#define INCLUDED_SCENE
|
||||
|
||||
class CFrustum;
|
||||
class CModel;
|
||||
class CPatch;
|
||||
|
||||
class SceneCollector;
|
||||
|
||||
/**
|
||||
* This interface describes a scene to the renderer.
|
||||
*
|
||||
* @see CRenderer::RenderScene
|
||||
*/
|
||||
class Scene {
|
||||
public:
|
||||
/**
|
||||
* Send all objects that can be seen when rendering the given frustum
|
||||
* to the scene collector.
|
||||
* @param frustum The frustum that will be used for rendering.
|
||||
* @param c The scene collector that should receive objects inside the frustum
|
||||
* that are visible.
|
||||
*/
|
||||
virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c) = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This interface accepts renderable objects.
|
||||
*
|
||||
* @see Scene::EnumerateObjects
|
||||
*/
|
||||
class SceneCollector {
|
||||
public:
|
||||
/**
|
||||
* Submit a terrain patch that is part of the scene.
|
||||
*/
|
||||
virtual void Submit(CPatch* patch) = 0;
|
||||
|
||||
/**
|
||||
* Submit a model that is part of the scene,
|
||||
* without submitting attached models.
|
||||
*/
|
||||
virtual void SubmitNonRecursive(CModel* model) = 0;
|
||||
|
||||
/**
|
||||
* Submit a model that is part of the scene,
|
||||
* including attached sub-models.
|
||||
*
|
||||
* @note This function is implemented using SubmitNonRecursive,
|
||||
* so you shouldn't have to reimplement it.
|
||||
*/
|
||||
virtual void SubmitRecursive(CModel* model);
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_SCENE
|
||||
|
@ -1,15 +1,15 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "SpiderMonkey.h"
|
||||
|
||||
jsval jsu_report_param_error(JSContext* cx, jsval* rval)
|
||||
{
|
||||
JS_ReportError(cx, "Invalid parameter(s) or count");
|
||||
|
||||
if(rval)
|
||||
*rval = JSVAL_NULL;
|
||||
|
||||
// yes, we had an error, but returning JS_FALSE would cause SpiderMonkey
|
||||
// to abort. that would be hard to debug.
|
||||
return JS_TRUE;
|
||||
}
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "SpiderMonkey.h"
|
||||
|
||||
jsval jsu_report_param_error(JSContext* cx, jsval* rval)
|
||||
{
|
||||
JS_ReportError(cx, "Invalid parameter(s) or count");
|
||||
|
||||
if(rval)
|
||||
*rval = JSVAL_NULL;
|
||||
|
||||
// yes, we had an error, but returning JS_FALSE would cause SpiderMonkey
|
||||
// to abort. that would be hard to debug.
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -1,44 +1,44 @@
|
||||
// included from SpiderMonkey.h
|
||||
|
||||
extern jsval jsu_report_param_error(JSContext* cx, jsval* rval);
|
||||
|
||||
|
||||
// consistent argc checking for normal function wrappers: reports an
|
||||
// error via JS and returns if number of parameters is incorrect.
|
||||
// .. require exact number (most common case)
|
||||
#define JSU_REQUIRE_PARAMS(exact_number)\
|
||||
if(argc != exact_number)\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
// .. require 0 params (avoids L4 warning "unused argv param")
|
||||
#define JSU_REQUIRE_NO_PARAMS()\
|
||||
UNUSED2(argv);\
|
||||
if(argc != 0)\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
// .. require a certain range (e.g. due to optional params)
|
||||
#define JSU_REQUIRE_PARAM_RANGE(min_number, max_number)\
|
||||
if(!(min_number <= argc && argc <= max_number))\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
// .. require at least a certain count (rarely needed)
|
||||
#define JSU_REQUIRE_MIN_PARAMS(min_number)\
|
||||
if(argc < min_number)\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
|
||||
// same as JSU_REQUIRE_PARAMS, but used from C++ functions that are
|
||||
// a bit further removed from SpiderMonkey, i.e. return a
|
||||
// C++ bool indicating success, and not taking an rval param.
|
||||
#define JSU_REQUIRE_PARAMS_CPP(exact_number)\
|
||||
if(argc != exact_number)\
|
||||
{\
|
||||
jsu_report_param_error(cx, 0);\
|
||||
return false;\
|
||||
}
|
||||
|
||||
|
||||
#define JSU_ASSERT(expr, msg)\
|
||||
STMT(\
|
||||
if(!(expr))\
|
||||
{\
|
||||
JS_ReportError(cx, msg);\
|
||||
return JS_FALSE;\
|
||||
}\
|
||||
)
|
||||
// included from SpiderMonkey.h
|
||||
|
||||
extern jsval jsu_report_param_error(JSContext* cx, jsval* rval);
|
||||
|
||||
|
||||
// consistent argc checking for normal function wrappers: reports an
|
||||
// error via JS and returns if number of parameters is incorrect.
|
||||
// .. require exact number (most common case)
|
||||
#define JSU_REQUIRE_PARAMS(exact_number)\
|
||||
if(argc != exact_number)\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
// .. require 0 params (avoids L4 warning "unused argv param")
|
||||
#define JSU_REQUIRE_NO_PARAMS()\
|
||||
UNUSED2(argv);\
|
||||
if(argc != 0)\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
// .. require a certain range (e.g. due to optional params)
|
||||
#define JSU_REQUIRE_PARAM_RANGE(min_number, max_number)\
|
||||
if(!(min_number <= argc && argc <= max_number))\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
// .. require at least a certain count (rarely needed)
|
||||
#define JSU_REQUIRE_MIN_PARAMS(min_number)\
|
||||
if(argc < min_number)\
|
||||
return jsu_report_param_error(cx, rval);
|
||||
|
||||
// same as JSU_REQUIRE_PARAMS, but used from C++ functions that are
|
||||
// a bit further removed from SpiderMonkey, i.e. return a
|
||||
// C++ bool indicating success, and not taking an rval param.
|
||||
#define JSU_REQUIRE_PARAMS_CPP(exact_number)\
|
||||
if(argc != exact_number)\
|
||||
{\
|
||||
jsu_report_param_error(cx, 0);\
|
||||
return false;\
|
||||
}
|
||||
|
||||
|
||||
#define JSU_ASSERT(expr, msg)\
|
||||
STMT(\
|
||||
if(!(expr))\
|
||||
{\
|
||||
JS_ReportError(cx, msg);\
|
||||
return JS_FALSE;\
|
||||
}\
|
||||
)
|
||||
|
@ -1,23 +1,23 @@
|
||||
#include "precompiled.h"
|
||||
#include "TRAStarEngine.h"
|
||||
|
||||
#ifdef USE_DCDT
|
||||
|
||||
CTRAStarEngine::CTRAStarEngine(void)
|
||||
{
|
||||
|
||||
mGoal = new AStarGoalLowLevel;
|
||||
}
|
||||
|
||||
CTRAStarEngine::~CTRAStarEngine(void)
|
||||
{
|
||||
delete mGoal;
|
||||
}
|
||||
|
||||
bool CTRAStarEngine::FindPath(const CVector2D &src, const CVector2D &dest, HEntity UNUSED(entity), SeDcdt& dcdtPathfinder, float radius )
|
||||
{
|
||||
bool found = dcdtPathfinder.SearchPathFast(src.x, src.y, dest.x, dest.y, radius);
|
||||
return found;
|
||||
}
|
||||
|
||||
#endif // USE_DCDT
|
||||
#include "precompiled.h"
|
||||
#include "TRAStarEngine.h"
|
||||
|
||||
#ifdef USE_DCDT
|
||||
|
||||
CTRAStarEngine::CTRAStarEngine(void)
|
||||
{
|
||||
|
||||
mGoal = new AStarGoalLowLevel;
|
||||
}
|
||||
|
||||
CTRAStarEngine::~CTRAStarEngine(void)
|
||||
{
|
||||
delete mGoal;
|
||||
}
|
||||
|
||||
bool CTRAStarEngine::FindPath(const CVector2D &src, const CVector2D &dest, HEntity UNUSED(entity), SeDcdt& dcdtPathfinder, float radius )
|
||||
{
|
||||
bool found = dcdtPathfinder.SearchPathFast(src.x, src.y, dest.x, dest.y, radius);
|
||||
return found;
|
||||
}
|
||||
|
||||
#endif // USE_DCDT
|
||||
|
@ -1,22 +1,22 @@
|
||||
#ifndef INCLUDED_TRASTARENGINE
|
||||
#define INCLUDED_TRASTARENGINE
|
||||
|
||||
#ifdef USE_DCDT
|
||||
|
||||
#include "AStarEngine.h"
|
||||
|
||||
class CTRAStarEngine :
|
||||
public CAStarEngine
|
||||
{
|
||||
public:
|
||||
CTRAStarEngine(void);
|
||||
~CTRAStarEngine(void);
|
||||
|
||||
SeDcdt dcdtPathfinder;;
|
||||
|
||||
bool FindPath( const CVector2D& src, const CVector2D& dest, HEntity entity, SeDcdt& dcdtPathfinder,float radius=0.0f );
|
||||
};
|
||||
|
||||
#endif // USE_DCDT
|
||||
|
||||
#endif
|
||||
#ifndef INCLUDED_TRASTARENGINE
|
||||
#define INCLUDED_TRASTARENGINE
|
||||
|
||||
#ifdef USE_DCDT
|
||||
|
||||
#include "AStarEngine.h"
|
||||
|
||||
class CTRAStarEngine :
|
||||
public CAStarEngine
|
||||
{
|
||||
public:
|
||||
CTRAStarEngine(void);
|
||||
~CTRAStarEngine(void);
|
||||
|
||||
SeDcdt dcdtPathfinder;;
|
||||
|
||||
bool FindPath( const CVector2D& src, const CVector2D& dest, HEntity entity, SeDcdt& dcdtPathfinder,float radius=0.0f );
|
||||
};
|
||||
|
||||
#endif // USE_DCDT
|
||||
|
||||
#endif
|
||||
|
@ -1,68 +1,68 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "TechnologyCollection.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Player.h"
|
||||
|
||||
#define LOG_CATEGORY "tech"
|
||||
|
||||
void CTechnologyCollection::LoadFile( const VfsPath& pathname )
|
||||
{
|
||||
const CStrW basename(fs::basename(pathname));
|
||||
m_techFilenames[basename] = pathname.string();
|
||||
}
|
||||
|
||||
static LibError LoadTechThunk( const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), uintptr_t cbData )
|
||||
{
|
||||
CTechnologyCollection* this_ = (CTechnologyCollection*)cbData;
|
||||
this_->LoadFile(pathname);
|
||||
return INFO::CB_CONTINUE;
|
||||
}
|
||||
|
||||
int CTechnologyCollection::LoadTechnologies()
|
||||
{
|
||||
// Load all files in techs/ and subdirectories.
|
||||
THROW_ERR( fs_ForEachFile(g_VFS, "technologies/", LoadTechThunk, (uintptr_t)this, "*.xml", DIR_RECURSIVE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
CTechnology* CTechnologyCollection::GetTechnology( const CStrW& name, CPlayer* player )
|
||||
{
|
||||
// Find player ID
|
||||
debug_assert( player != 0 );
|
||||
const size_t id = player->GetPlayerID();
|
||||
|
||||
// Check whether this template has already been loaded.
|
||||
//If previously loaded, all slots will be found, so any entry works.
|
||||
TechMap::iterator it = m_techs[id].find( name );
|
||||
if( it != m_techs[id].end() )
|
||||
return( it->second );
|
||||
|
||||
// Find the filename corresponding to this template
|
||||
TechFilenameMap::iterator filename_it = m_techFilenames.find( name );
|
||||
if( filename_it == m_techFilenames.end() )
|
||||
return( NULL );
|
||||
|
||||
CStr path( filename_it->second );
|
||||
|
||||
//Try to load to the tech
|
||||
CTechnology* newTemplate = new CTechnology( name, player );
|
||||
if( !newTemplate->LoadXml( path ) )
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Couldn't load tech \"%s\"", path.c_str());
|
||||
delete newTemplate;
|
||||
return( NULL );
|
||||
|
||||
}
|
||||
m_techs[id][name] = newTemplate;
|
||||
|
||||
LOG(CLogger::Normal, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Loaded tech \"%s\"", path.c_str());
|
||||
return newTemplate;
|
||||
}
|
||||
|
||||
CTechnologyCollection::~CTechnologyCollection()
|
||||
{
|
||||
for( size_t id=0; id<PS_MAX_PLAYERS+1; id++ )
|
||||
for( TechMap::iterator it = m_techs[id].begin(); it != m_techs[id].end(); ++it )
|
||||
delete( it->second );
|
||||
}
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "TechnologyCollection.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Player.h"
|
||||
|
||||
#define LOG_CATEGORY "tech"
|
||||
|
||||
void CTechnologyCollection::LoadFile( const VfsPath& pathname )
|
||||
{
|
||||
const CStrW basename(fs::basename(pathname));
|
||||
m_techFilenames[basename] = pathname.string();
|
||||
}
|
||||
|
||||
static LibError LoadTechThunk( const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), uintptr_t cbData )
|
||||
{
|
||||
CTechnologyCollection* this_ = (CTechnologyCollection*)cbData;
|
||||
this_->LoadFile(pathname);
|
||||
return INFO::CB_CONTINUE;
|
||||
}
|
||||
|
||||
int CTechnologyCollection::LoadTechnologies()
|
||||
{
|
||||
// Load all files in techs/ and subdirectories.
|
||||
THROW_ERR( fs_ForEachFile(g_VFS, "technologies/", LoadTechThunk, (uintptr_t)this, "*.xml", DIR_RECURSIVE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
CTechnology* CTechnologyCollection::GetTechnology( const CStrW& name, CPlayer* player )
|
||||
{
|
||||
// Find player ID
|
||||
debug_assert( player != 0 );
|
||||
const size_t id = player->GetPlayerID();
|
||||
|
||||
// Check whether this template has already been loaded.
|
||||
//If previously loaded, all slots will be found, so any entry works.
|
||||
TechMap::iterator it = m_techs[id].find( name );
|
||||
if( it != m_techs[id].end() )
|
||||
return( it->second );
|
||||
|
||||
// Find the filename corresponding to this template
|
||||
TechFilenameMap::iterator filename_it = m_techFilenames.find( name );
|
||||
if( filename_it == m_techFilenames.end() )
|
||||
return( NULL );
|
||||
|
||||
CStr path( filename_it->second );
|
||||
|
||||
//Try to load to the tech
|
||||
CTechnology* newTemplate = new CTechnology( name, player );
|
||||
if( !newTemplate->LoadXml( path ) )
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Couldn't load tech \"%s\"", path.c_str());
|
||||
delete newTemplate;
|
||||
return( NULL );
|
||||
|
||||
}
|
||||
m_techs[id][name] = newTemplate;
|
||||
|
||||
LOG(CLogger::Normal, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Loaded tech \"%s\"", path.c_str());
|
||||
return newTemplate;
|
||||
}
|
||||
|
||||
CTechnologyCollection::~CTechnologyCollection()
|
||||
{
|
||||
for( size_t id=0; id<PS_MAX_PLAYERS+1; id++ )
|
||||
for( TechMap::iterator it = m_techs[id].begin(); it != m_techs[id].end(); ++it )
|
||||
delete( it->second );
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
//Manages the tech templates. More detail: see CFormation and CEntityTemplate (collections)
|
||||
|
||||
|
||||
#ifndef INCLUDED_TECHNOLOGYCOLLECTION
|
||||
#define INCLUDED_TECHNOLOGYCOLLECTION
|
||||
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Singleton.h"
|
||||
#include "Technology.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/Filesystem.h"
|
||||
|
||||
#define g_TechnologyCollection CTechnologyCollection::GetSingleton()
|
||||
|
||||
class CTechnologyCollection : public Singleton<CTechnologyCollection>
|
||||
{
|
||||
typedef std::map<CStrW, CTechnology*> TechMap;
|
||||
typedef std::map<CStrW, CStr> TechFilenameMap;
|
||||
|
||||
TechMap m_techs[PS_MAX_PLAYERS+1];
|
||||
TechFilenameMap m_techFilenames;
|
||||
|
||||
public:
|
||||
std::vector<CTechnology*> activeTechs[PS_MAX_PLAYERS+1];
|
||||
|
||||
CTechnology* GetTechnology( const CStrW& techType, CPlayer* player );
|
||||
~CTechnologyCollection();
|
||||
|
||||
int LoadTechnologies();
|
||||
|
||||
// called by non-member trampoline via LoadTechnologies
|
||||
void LoadFile( const VfsPath& path );
|
||||
};
|
||||
|
||||
#endif
|
||||
//Manages the tech templates. More detail: see CFormation and CEntityTemplate (collections)
|
||||
|
||||
|
||||
#ifndef INCLUDED_TECHNOLOGYCOLLECTION
|
||||
#define INCLUDED_TECHNOLOGYCOLLECTION
|
||||
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Singleton.h"
|
||||
#include "Technology.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/Filesystem.h"
|
||||
|
||||
#define g_TechnologyCollection CTechnologyCollection::GetSingleton()
|
||||
|
||||
class CTechnologyCollection : public Singleton<CTechnologyCollection>
|
||||
{
|
||||
typedef std::map<CStrW, CTechnology*> TechMap;
|
||||
typedef std::map<CStrW, CStr> TechFilenameMap;
|
||||
|
||||
TechMap m_techs[PS_MAX_PLAYERS+1];
|
||||
TechFilenameMap m_techFilenames;
|
||||
|
||||
public:
|
||||
std::vector<CTechnology*> activeTechs[PS_MAX_PLAYERS+1];
|
||||
|
||||
CTechnology* GetTechnology( const CStrW& techType, CPlayer* player );
|
||||
~CTechnologyCollection();
|
||||
|
||||
int LoadTechnologies();
|
||||
|
||||
// called by non-member trampoline via LoadTechnologies
|
||||
void LoadFile( const VfsPath& path );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,487 +1,487 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "TriggerManager.h"
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "ps/XML/XeroXMB.h"
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
#define LOG_CATEGORY "Triggers"
|
||||
|
||||
|
||||
CTrigger::CTrigger()
|
||||
{
|
||||
m_timeLeft = m_timeDelay = m_maxRunCount = m_runCount = m_active = 0;
|
||||
}
|
||||
CTrigger::~CTrigger()
|
||||
{
|
||||
|
||||
}
|
||||
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
|
||||
const CStrW& effectFunc)
|
||||
{
|
||||
m_name = name;
|
||||
m_active = active;
|
||||
m_timeLeft = m_timeDelay = delay;
|
||||
m_runCount = 0;
|
||||
m_maxRunCount = maxRuns;
|
||||
|
||||
CStrW validName = name;
|
||||
validName.Replace(L" ", L"_");
|
||||
|
||||
m_conditionFuncString = condFunc;
|
||||
m_effectFuncString = effectFunc;
|
||||
m_conditionFunction.Compile( L"TriggerCondition_" + validName, condFunc );
|
||||
m_effectFunction.Compile( L"TriggerEffect_" + validName, effectFunc );
|
||||
}
|
||||
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
|
||||
CScriptObject& condFunc, CScriptObject& effectFunc)
|
||||
{
|
||||
m_name = name;
|
||||
m_active = active;
|
||||
m_timeLeft = m_timeDelay = delay;
|
||||
m_runCount = 0;
|
||||
m_maxRunCount = maxRuns;
|
||||
m_conditionFunction = condFunc;
|
||||
m_effectFunction = effectFunc;
|
||||
}
|
||||
|
||||
JSBool CTrigger::Construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
JSU_REQUIRE_PARAMS_CPP(6);
|
||||
|
||||
CScriptObject condFunc( JS_ValueToFunction(cx, argv[4]) );
|
||||
CScriptObject effectFunc( JS_ValueToFunction(cx, argv[5]) );
|
||||
CTrigger* newTrigger = new CTrigger( ToPrimitive<CStr>( argv[0] ),
|
||||
ToPrimitive<bool>( argv[1] ),
|
||||
ToPrimitive<float>( argv[2] ),
|
||||
ToPrimitive<int>( argv[3]),
|
||||
condFunc, effectFunc );
|
||||
|
||||
g_TriggerManager.AddTrigger(newTrigger);
|
||||
*rval = OBJECT_TO_JSVAL( newTrigger->GetScript() );
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
CTrigger& CTrigger::operator= (const CTrigger& trigger)
|
||||
{
|
||||
m_name = trigger.m_name;
|
||||
m_active = trigger.m_active;
|
||||
m_timeLeft = trigger.m_timeLeft;
|
||||
m_timeDelay = trigger.m_timeDelay;
|
||||
m_maxRunCount = trigger.m_maxRunCount;
|
||||
m_conditionFunction = trigger.m_conditionFunction;
|
||||
m_effectFunction = trigger.m_effectFunction;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CTrigger::ScriptingInit()
|
||||
{
|
||||
AddProperty<int>(L"runCount", &CTrigger::m_runCount, true);
|
||||
AddProperty(L"name", &CTrigger::m_name, true);
|
||||
AddProperty<int>(L"maxRunCount", &CTrigger::m_maxRunCount);
|
||||
AddProperty<float>(L"timeDelay", &CTrigger::m_timeDelay);
|
||||
|
||||
AddMethod<void, &CTrigger::Activate>( "activate", 0 );
|
||||
AddMethod<void, &CTrigger::Deactivate>( "deactivate", 0 );
|
||||
|
||||
CJSObject<CTrigger>::ScriptingInit("Trigger", CTrigger::Construct, 6);
|
||||
}
|
||||
|
||||
bool CTrigger::ShouldFire()
|
||||
{
|
||||
if ( !m_active )
|
||||
return false;
|
||||
return m_conditionFunction.Run( this->GetScript() );
|
||||
}
|
||||
bool CTrigger::Fire()
|
||||
{
|
||||
m_effectFunction.Run( this->GetScript() );
|
||||
++m_runCount;
|
||||
m_timeLeft = m_timeDelay;
|
||||
return (m_runCount < m_maxRunCount);
|
||||
}
|
||||
|
||||
void CTrigger::Activate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
m_active = true;
|
||||
}
|
||||
void CTrigger::Deactivate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
|
||||
void TriggerParameter::SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize)
|
||||
{
|
||||
windowPosition.Remove( CStrW(L" ") );
|
||||
windowSize.Remove( CStrW(L" ") );
|
||||
|
||||
xPos = windowPosition.BeforeFirst( CStrW(L",") ).ToInt();
|
||||
yPos = windowPosition.AfterFirst( CStrW(L",") ).ToInt();
|
||||
xSize = windowSize.BeforeFirst( CStrW(L",") ).ToInt();
|
||||
ySize = windowSize.AfterFirst( CStrW(L",") ).ToInt();
|
||||
windowType = _windowType;
|
||||
}
|
||||
|
||||
bool TriggerParameter::operator< ( const TriggerParameter& rhs ) const
|
||||
{
|
||||
if ( row < rhs.row )
|
||||
return true;
|
||||
else if ( row == rhs.row)
|
||||
return ( column < rhs.column );
|
||||
|
||||
return false;
|
||||
}
|
||||
//===========Trigger Manager===========
|
||||
|
||||
CTriggerManager::CTriggerManager() : m_UpdateRate(.20f), m_UpdateTime(.20f)
|
||||
{
|
||||
}
|
||||
|
||||
CTriggerManager::~CTriggerManager()
|
||||
{
|
||||
DestroyEngineTriggers();
|
||||
}
|
||||
|
||||
void CTriggerManager::DestroyEngineTriggers()
|
||||
{
|
||||
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
|
||||
{
|
||||
SAFE_DELETE(it->second);
|
||||
}
|
||||
m_TriggerMap.clear();
|
||||
}
|
||||
|
||||
std::vector<std::wstring> CTriggerManager::GetTriggerChoices(const std::wstring& name)
|
||||
{
|
||||
return m_TriggerChoices[name];
|
||||
}
|
||||
std::vector<std::wstring> CTriggerManager::GetTriggerTranslations(const std::wstring& name)
|
||||
{
|
||||
return m_TriggerTranslations[name];
|
||||
}
|
||||
|
||||
void CTriggerManager::Update(float delta_ms)
|
||||
{
|
||||
float delta = delta_ms / 1000.f;
|
||||
m_UpdateTime -= delta;
|
||||
if ( m_UpdateTime < 0 )
|
||||
m_UpdateTime += m_UpdateRate;
|
||||
else
|
||||
return;
|
||||
|
||||
std::list<TriggerIter> expired;
|
||||
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
|
||||
{
|
||||
if ( it->second->ShouldFire() )
|
||||
{
|
||||
it->second->m_timeLeft -= m_UpdateRate;
|
||||
if ( it->second->m_timeLeft < 0 )
|
||||
{
|
||||
if ( !it->second->Fire() )
|
||||
expired.push_back(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove all expired triggers
|
||||
for ( std::list<TriggerIter>::iterator it = expired.begin(); it != expired.end(); ++it )
|
||||
{
|
||||
delete (*it)->second;
|
||||
m_TriggerMap.erase(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void CTriggerManager::AddTrigger(CTrigger* trigger)
|
||||
{
|
||||
m_TriggerMap[trigger->GetName()] = trigger;
|
||||
}
|
||||
void CTriggerManager::AddGroup(const MapTriggerGroup& group)
|
||||
{
|
||||
m_GroupList.push_back(group);
|
||||
}
|
||||
void CTriggerManager::SetAllGroups(const std::list<MapTriggerGroup>& groups)
|
||||
{
|
||||
m_GroupList = groups;
|
||||
}
|
||||
|
||||
void CTriggerManager::AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger)
|
||||
{
|
||||
CStrW conditionBody;
|
||||
CStrW linkLogic[] = { CStrW(L""), CStrW(L" && "), CStrW(L" || ") };
|
||||
size_t i=0;
|
||||
bool allParameters = true;
|
||||
|
||||
if(trigger.conditions.size() == 0) {
|
||||
conditionBody = CStrW(L"return ( true );");
|
||||
}
|
||||
else {
|
||||
conditionBody = CStrW(L"return ( ");
|
||||
|
||||
for ( std::list<MapTriggerCondition>::const_iterator it = trigger.conditions.begin();
|
||||
it != trigger.conditions.end(); ++it, ++i )
|
||||
{
|
||||
//Opening parenthesis here?
|
||||
std::set<MapTriggerLogicBlock>::const_iterator blockIt;
|
||||
if ( ( blockIt = trigger.logicBlocks.find(MapTriggerLogicBlock(i)) ) != trigger.logicBlocks.end() )
|
||||
{
|
||||
if ( blockIt->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += CStrW(L" (");
|
||||
}
|
||||
|
||||
if ( it->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += it->functionName;
|
||||
conditionBody += CStrW(L"(");
|
||||
|
||||
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
|
||||
it->parameters.end(); ++it2 )
|
||||
{
|
||||
size_t params = (size_t)std::find(m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName)->funcParameters;
|
||||
size_t distance = std::distance(it->parameters.begin(), it2);
|
||||
|
||||
//Parameters end here, additional "parameters" are used directly as script
|
||||
if ( distance == params )
|
||||
{
|
||||
conditionBody += CStrW(L") ");
|
||||
allParameters = false;
|
||||
}
|
||||
|
||||
//Take display parameter and translate into JS usable code...evilness
|
||||
CTriggerSpec spec = *std::find( m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName );
|
||||
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
|
||||
|
||||
//Don't use specialized find, since we're searching for a different member
|
||||
std::set<TriggerParameter>::const_iterator specParam = std::find(
|
||||
specParameters.begin(), specParameters.end(), (int)distance);
|
||||
std::wstring combined = std::wstring( it->functionName + specParam->name );
|
||||
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
|
||||
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
|
||||
|
||||
if ( m_TriggerTranslations[combined].empty() )
|
||||
conditionBody += *it2;
|
||||
else
|
||||
conditionBody += m_TriggerTranslations[combined][translatedIndex];
|
||||
|
||||
if ( distance + 1 < params )
|
||||
conditionBody += CStrW(L", ");
|
||||
}
|
||||
|
||||
if ( allParameters ) //Otherwise, closed inside loop
|
||||
conditionBody += CStrW(L")");
|
||||
if ( trigger.logicBlockEnds.find(i) != trigger.logicBlockEnds.end() )
|
||||
conditionBody += CStrW(L" )");
|
||||
|
||||
if ( std::distance(it, trigger.conditions.end()) != 1 )
|
||||
conditionBody += linkLogic[it->linkLogic];
|
||||
}
|
||||
|
||||
conditionBody += CStrW(L" );");
|
||||
}
|
||||
|
||||
CStrW effectBody;
|
||||
|
||||
for ( std::list<MapTriggerEffect>::const_iterator it = trigger.effects.begin();
|
||||
it != trigger.effects.end(); ++it )
|
||||
{
|
||||
effectBody += it->functionName;
|
||||
effectBody += CStrW(L"(");
|
||||
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
|
||||
it->parameters.end(); ++it2 )
|
||||
{
|
||||
size_t distance = std::distance(it->parameters.begin(), it2);
|
||||
//Take display parameter and translate into JS usable code...evilness
|
||||
CTriggerSpec spec = *std::find( m_EffectSpecs.begin(), m_EffectSpecs.end(), it->displayName );
|
||||
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
|
||||
|
||||
//Don't use specialized find, since we're searching for a different member
|
||||
std::set<TriggerParameter>::const_iterator specParam = std::find(
|
||||
specParameters.begin(), specParameters.end(), (int)distance);
|
||||
std::wstring combined = std::wstring( it->functionName + specParam->name );
|
||||
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
|
||||
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
|
||||
|
||||
if ( m_TriggerTranslations[combined].empty() )
|
||||
effectBody += *it2;
|
||||
else
|
||||
effectBody += m_TriggerTranslations[combined][translatedIndex];
|
||||
std::list<CStrW>::const_iterator endIt = it->parameters.end();
|
||||
if ( std::distance(it2, endIt) != 1 )
|
||||
effectBody += CStrW(L", ");
|
||||
}
|
||||
|
||||
effectBody += CStrW(L");");
|
||||
}
|
||||
|
||||
group.triggers.push_back(trigger);
|
||||
CTrigger* newTrigger = new CTrigger(trigger.name, trigger.active, trigger.timeValue,
|
||||
trigger.maxRunCount, conditionBody, effectBody);
|
||||
AddTrigger(newTrigger);
|
||||
}
|
||||
|
||||
|
||||
//XML stuff
|
||||
|
||||
bool CTriggerManager::LoadXml( const CStr& filename )
|
||||
{
|
||||
CXeromyces XeroFile;
|
||||
|
||||
if ( XeroFile.Load( filename.c_str() ) != PSRETURN_OK )
|
||||
return false;
|
||||
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
|
||||
EL(condition);
|
||||
EL(effect);
|
||||
EL(definitions);
|
||||
|
||||
#undef EL
|
||||
#undef AT
|
||||
|
||||
//Return false on any error to be extra sure the point gets across (FIX IT)
|
||||
XMBElement root = XeroFile.GetRoot();
|
||||
|
||||
if ( root.GetNodeName() != el_definitions )
|
||||
return false;
|
||||
|
||||
XERO_ITER_EL(root, rootChild)
|
||||
{
|
||||
int name = rootChild.GetNodeName();
|
||||
if ( name == el_condition )
|
||||
{
|
||||
if ( !LoadTriggerSpec(rootChild, XeroFile, true) )
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <condition> tag. File: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( name == el_effect )
|
||||
{
|
||||
if ( !LoadTriggerSpec(rootChild, XeroFile, false) )
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <effect> tag. File: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Invalid tag in trigger XML. File: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTriggerManager::LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition )
|
||||
{
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
|
||||
EL(parameter);
|
||||
EL(window);
|
||||
EL(inputtype);
|
||||
EL(parameterorder);
|
||||
EL(windowrow);
|
||||
EL(choices);
|
||||
EL(choicetranslation);
|
||||
|
||||
AT(type);
|
||||
AT(position);
|
||||
AT(name);
|
||||
AT(size);
|
||||
AT(function);
|
||||
AT(funcParameters);
|
||||
|
||||
#undef EL
|
||||
#undef AT
|
||||
|
||||
CTriggerSpec specStore;
|
||||
specStore.functionName = CStrW( condition.GetAttributes().GetNamedItem(at_function) );
|
||||
specStore.displayName = CStrW( condition.GetAttributes().GetNamedItem(at_name) );
|
||||
specStore.funcParameters = CStr( condition.GetAttributes().GetNamedItem(at_funcParameters) ).ToInt();
|
||||
int row = -1, column = -1;
|
||||
|
||||
XERO_ITER_EL(condition, child)
|
||||
{
|
||||
int childID = child.GetNodeName();
|
||||
|
||||
if ( childID == el_windowrow )
|
||||
{
|
||||
++row;
|
||||
column = -1;
|
||||
|
||||
XERO_ITER_EL(child, windowChild)
|
||||
{
|
||||
++column;
|
||||
TriggerParameter specParam(row, column);
|
||||
specParam.name = windowChild.GetAttributes().GetNamedItem(at_name);
|
||||
childID = windowChild.GetNodeName();
|
||||
|
||||
if ( childID != el_parameter)
|
||||
return false;
|
||||
|
||||
XERO_ITER_EL(windowChild, parameterChild)
|
||||
{
|
||||
childID = parameterChild.GetNodeName();
|
||||
|
||||
if ( childID == el_window )
|
||||
{
|
||||
CStrW type( parameterChild.GetAttributes().GetNamedItem(at_type) );
|
||||
CStrW pos( parameterChild.GetAttributes().GetNamedItem(at_position) );
|
||||
CStrW size( parameterChild.GetAttributes().GetNamedItem(at_size) );
|
||||
specParam.SetWindowData(type, pos, size);
|
||||
}
|
||||
|
||||
else if ( childID == el_inputtype )
|
||||
specParam.inputType = CStrW( parameterChild.GetText() );
|
||||
else if ( childID == el_parameterorder )
|
||||
specParam.parameterOrder = CStrW( parameterChild.GetText() ).ToInt();
|
||||
else if ( childID == el_choices )
|
||||
{
|
||||
std::vector<std::wstring> choices;
|
||||
CStrW comma(L","), input(parameterChild.GetText());
|
||||
CStrW substr;
|
||||
while ( (substr = input.BeforeFirst(comma)) != input )
|
||||
{
|
||||
choices.push_back(substr);
|
||||
input = input.AfterFirst(comma);
|
||||
}
|
||||
|
||||
choices.push_back(substr); //Last element has no comma
|
||||
m_TriggerChoices[specStore.functionName + specParam.name] = choices;
|
||||
}
|
||||
else if ( childID == el_choicetranslation )
|
||||
{
|
||||
std::vector<std::wstring> choices;
|
||||
CStrW comma(L","), input(parameterChild.GetText());
|
||||
CStrW substr;
|
||||
while ( (substr = input.BeforeFirst(comma)) != input )
|
||||
{
|
||||
choices.push_back(substr);
|
||||
input = input.AfterFirst(comma);
|
||||
}
|
||||
|
||||
choices.push_back(substr); //Last element has no comma
|
||||
m_TriggerTranslations[specStore.functionName + specParam.name] = choices;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
specStore.AddParameter(specParam);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isCondition )
|
||||
m_ConditionSpecs.push_back(specStore);
|
||||
else
|
||||
m_EffectSpecs.push_back(specStore);
|
||||
|
||||
return true;
|
||||
}
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "TriggerManager.h"
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "ps/XML/XeroXMB.h"
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
#define LOG_CATEGORY "Triggers"
|
||||
|
||||
|
||||
CTrigger::CTrigger()
|
||||
{
|
||||
m_timeLeft = m_timeDelay = m_maxRunCount = m_runCount = m_active = 0;
|
||||
}
|
||||
CTrigger::~CTrigger()
|
||||
{
|
||||
|
||||
}
|
||||
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
|
||||
const CStrW& effectFunc)
|
||||
{
|
||||
m_name = name;
|
||||
m_active = active;
|
||||
m_timeLeft = m_timeDelay = delay;
|
||||
m_runCount = 0;
|
||||
m_maxRunCount = maxRuns;
|
||||
|
||||
CStrW validName = name;
|
||||
validName.Replace(L" ", L"_");
|
||||
|
||||
m_conditionFuncString = condFunc;
|
||||
m_effectFuncString = effectFunc;
|
||||
m_conditionFunction.Compile( L"TriggerCondition_" + validName, condFunc );
|
||||
m_effectFunction.Compile( L"TriggerEffect_" + validName, effectFunc );
|
||||
}
|
||||
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
|
||||
CScriptObject& condFunc, CScriptObject& effectFunc)
|
||||
{
|
||||
m_name = name;
|
||||
m_active = active;
|
||||
m_timeLeft = m_timeDelay = delay;
|
||||
m_runCount = 0;
|
||||
m_maxRunCount = maxRuns;
|
||||
m_conditionFunction = condFunc;
|
||||
m_effectFunction = effectFunc;
|
||||
}
|
||||
|
||||
JSBool CTrigger::Construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
JSU_REQUIRE_PARAMS_CPP(6);
|
||||
|
||||
CScriptObject condFunc( JS_ValueToFunction(cx, argv[4]) );
|
||||
CScriptObject effectFunc( JS_ValueToFunction(cx, argv[5]) );
|
||||
CTrigger* newTrigger = new CTrigger( ToPrimitive<CStr>( argv[0] ),
|
||||
ToPrimitive<bool>( argv[1] ),
|
||||
ToPrimitive<float>( argv[2] ),
|
||||
ToPrimitive<int>( argv[3]),
|
||||
condFunc, effectFunc );
|
||||
|
||||
g_TriggerManager.AddTrigger(newTrigger);
|
||||
*rval = OBJECT_TO_JSVAL( newTrigger->GetScript() );
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
CTrigger& CTrigger::operator= (const CTrigger& trigger)
|
||||
{
|
||||
m_name = trigger.m_name;
|
||||
m_active = trigger.m_active;
|
||||
m_timeLeft = trigger.m_timeLeft;
|
||||
m_timeDelay = trigger.m_timeDelay;
|
||||
m_maxRunCount = trigger.m_maxRunCount;
|
||||
m_conditionFunction = trigger.m_conditionFunction;
|
||||
m_effectFunction = trigger.m_effectFunction;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CTrigger::ScriptingInit()
|
||||
{
|
||||
AddProperty<int>(L"runCount", &CTrigger::m_runCount, true);
|
||||
AddProperty(L"name", &CTrigger::m_name, true);
|
||||
AddProperty<int>(L"maxRunCount", &CTrigger::m_maxRunCount);
|
||||
AddProperty<float>(L"timeDelay", &CTrigger::m_timeDelay);
|
||||
|
||||
AddMethod<void, &CTrigger::Activate>( "activate", 0 );
|
||||
AddMethod<void, &CTrigger::Deactivate>( "deactivate", 0 );
|
||||
|
||||
CJSObject<CTrigger>::ScriptingInit("Trigger", CTrigger::Construct, 6);
|
||||
}
|
||||
|
||||
bool CTrigger::ShouldFire()
|
||||
{
|
||||
if ( !m_active )
|
||||
return false;
|
||||
return m_conditionFunction.Run( this->GetScript() );
|
||||
}
|
||||
bool CTrigger::Fire()
|
||||
{
|
||||
m_effectFunction.Run( this->GetScript() );
|
||||
++m_runCount;
|
||||
m_timeLeft = m_timeDelay;
|
||||
return (m_runCount < m_maxRunCount);
|
||||
}
|
||||
|
||||
void CTrigger::Activate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
m_active = true;
|
||||
}
|
||||
void CTrigger::Deactivate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
|
||||
void TriggerParameter::SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize)
|
||||
{
|
||||
windowPosition.Remove( CStrW(L" ") );
|
||||
windowSize.Remove( CStrW(L" ") );
|
||||
|
||||
xPos = windowPosition.BeforeFirst( CStrW(L",") ).ToInt();
|
||||
yPos = windowPosition.AfterFirst( CStrW(L",") ).ToInt();
|
||||
xSize = windowSize.BeforeFirst( CStrW(L",") ).ToInt();
|
||||
ySize = windowSize.AfterFirst( CStrW(L",") ).ToInt();
|
||||
windowType = _windowType;
|
||||
}
|
||||
|
||||
bool TriggerParameter::operator< ( const TriggerParameter& rhs ) const
|
||||
{
|
||||
if ( row < rhs.row )
|
||||
return true;
|
||||
else if ( row == rhs.row)
|
||||
return ( column < rhs.column );
|
||||
|
||||
return false;
|
||||
}
|
||||
//===========Trigger Manager===========
|
||||
|
||||
CTriggerManager::CTriggerManager() : m_UpdateRate(.20f), m_UpdateTime(.20f)
|
||||
{
|
||||
}
|
||||
|
||||
CTriggerManager::~CTriggerManager()
|
||||
{
|
||||
DestroyEngineTriggers();
|
||||
}
|
||||
|
||||
void CTriggerManager::DestroyEngineTriggers()
|
||||
{
|
||||
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
|
||||
{
|
||||
SAFE_DELETE(it->second);
|
||||
}
|
||||
m_TriggerMap.clear();
|
||||
}
|
||||
|
||||
std::vector<std::wstring> CTriggerManager::GetTriggerChoices(const std::wstring& name)
|
||||
{
|
||||
return m_TriggerChoices[name];
|
||||
}
|
||||
std::vector<std::wstring> CTriggerManager::GetTriggerTranslations(const std::wstring& name)
|
||||
{
|
||||
return m_TriggerTranslations[name];
|
||||
}
|
||||
|
||||
void CTriggerManager::Update(float delta_ms)
|
||||
{
|
||||
float delta = delta_ms / 1000.f;
|
||||
m_UpdateTime -= delta;
|
||||
if ( m_UpdateTime < 0 )
|
||||
m_UpdateTime += m_UpdateRate;
|
||||
else
|
||||
return;
|
||||
|
||||
std::list<TriggerIter> expired;
|
||||
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
|
||||
{
|
||||
if ( it->second->ShouldFire() )
|
||||
{
|
||||
it->second->m_timeLeft -= m_UpdateRate;
|
||||
if ( it->second->m_timeLeft < 0 )
|
||||
{
|
||||
if ( !it->second->Fire() )
|
||||
expired.push_back(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove all expired triggers
|
||||
for ( std::list<TriggerIter>::iterator it = expired.begin(); it != expired.end(); ++it )
|
||||
{
|
||||
delete (*it)->second;
|
||||
m_TriggerMap.erase(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void CTriggerManager::AddTrigger(CTrigger* trigger)
|
||||
{
|
||||
m_TriggerMap[trigger->GetName()] = trigger;
|
||||
}
|
||||
void CTriggerManager::AddGroup(const MapTriggerGroup& group)
|
||||
{
|
||||
m_GroupList.push_back(group);
|
||||
}
|
||||
void CTriggerManager::SetAllGroups(const std::list<MapTriggerGroup>& groups)
|
||||
{
|
||||
m_GroupList = groups;
|
||||
}
|
||||
|
||||
void CTriggerManager::AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger)
|
||||
{
|
||||
CStrW conditionBody;
|
||||
CStrW linkLogic[] = { CStrW(L""), CStrW(L" && "), CStrW(L" || ") };
|
||||
size_t i=0;
|
||||
bool allParameters = true;
|
||||
|
||||
if(trigger.conditions.size() == 0) {
|
||||
conditionBody = CStrW(L"return ( true );");
|
||||
}
|
||||
else {
|
||||
conditionBody = CStrW(L"return ( ");
|
||||
|
||||
for ( std::list<MapTriggerCondition>::const_iterator it = trigger.conditions.begin();
|
||||
it != trigger.conditions.end(); ++it, ++i )
|
||||
{
|
||||
//Opening parenthesis here?
|
||||
std::set<MapTriggerLogicBlock>::const_iterator blockIt;
|
||||
if ( ( blockIt = trigger.logicBlocks.find(MapTriggerLogicBlock(i)) ) != trigger.logicBlocks.end() )
|
||||
{
|
||||
if ( blockIt->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += CStrW(L" (");
|
||||
}
|
||||
|
||||
if ( it->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += it->functionName;
|
||||
conditionBody += CStrW(L"(");
|
||||
|
||||
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
|
||||
it->parameters.end(); ++it2 )
|
||||
{
|
||||
size_t params = (size_t)std::find(m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName)->funcParameters;
|
||||
size_t distance = std::distance(it->parameters.begin(), it2);
|
||||
|
||||
//Parameters end here, additional "parameters" are used directly as script
|
||||
if ( distance == params )
|
||||
{
|
||||
conditionBody += CStrW(L") ");
|
||||
allParameters = false;
|
||||
}
|
||||
|
||||
//Take display parameter and translate into JS usable code...evilness
|
||||
CTriggerSpec spec = *std::find( m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName );
|
||||
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
|
||||
|
||||
//Don't use specialized find, since we're searching for a different member
|
||||
std::set<TriggerParameter>::const_iterator specParam = std::find(
|
||||
specParameters.begin(), specParameters.end(), (int)distance);
|
||||
std::wstring combined = std::wstring( it->functionName + specParam->name );
|
||||
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
|
||||
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
|
||||
|
||||
if ( m_TriggerTranslations[combined].empty() )
|
||||
conditionBody += *it2;
|
||||
else
|
||||
conditionBody += m_TriggerTranslations[combined][translatedIndex];
|
||||
|
||||
if ( distance + 1 < params )
|
||||
conditionBody += CStrW(L", ");
|
||||
}
|
||||
|
||||
if ( allParameters ) //Otherwise, closed inside loop
|
||||
conditionBody += CStrW(L")");
|
||||
if ( trigger.logicBlockEnds.find(i) != trigger.logicBlockEnds.end() )
|
||||
conditionBody += CStrW(L" )");
|
||||
|
||||
if ( std::distance(it, trigger.conditions.end()) != 1 )
|
||||
conditionBody += linkLogic[it->linkLogic];
|
||||
}
|
||||
|
||||
conditionBody += CStrW(L" );");
|
||||
}
|
||||
|
||||
CStrW effectBody;
|
||||
|
||||
for ( std::list<MapTriggerEffect>::const_iterator it = trigger.effects.begin();
|
||||
it != trigger.effects.end(); ++it )
|
||||
{
|
||||
effectBody += it->functionName;
|
||||
effectBody += CStrW(L"(");
|
||||
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
|
||||
it->parameters.end(); ++it2 )
|
||||
{
|
||||
size_t distance = std::distance(it->parameters.begin(), it2);
|
||||
//Take display parameter and translate into JS usable code...evilness
|
||||
CTriggerSpec spec = *std::find( m_EffectSpecs.begin(), m_EffectSpecs.end(), it->displayName );
|
||||
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
|
||||
|
||||
//Don't use specialized find, since we're searching for a different member
|
||||
std::set<TriggerParameter>::const_iterator specParam = std::find(
|
||||
specParameters.begin(), specParameters.end(), (int)distance);
|
||||
std::wstring combined = std::wstring( it->functionName + specParam->name );
|
||||
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
|
||||
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
|
||||
|
||||
if ( m_TriggerTranslations[combined].empty() )
|
||||
effectBody += *it2;
|
||||
else
|
||||
effectBody += m_TriggerTranslations[combined][translatedIndex];
|
||||
std::list<CStrW>::const_iterator endIt = it->parameters.end();
|
||||
if ( std::distance(it2, endIt) != 1 )
|
||||
effectBody += CStrW(L", ");
|
||||
}
|
||||
|
||||
effectBody += CStrW(L");");
|
||||
}
|
||||
|
||||
group.triggers.push_back(trigger);
|
||||
CTrigger* newTrigger = new CTrigger(trigger.name, trigger.active, trigger.timeValue,
|
||||
trigger.maxRunCount, conditionBody, effectBody);
|
||||
AddTrigger(newTrigger);
|
||||
}
|
||||
|
||||
|
||||
//XML stuff
|
||||
|
||||
bool CTriggerManager::LoadXml( const CStr& filename )
|
||||
{
|
||||
CXeromyces XeroFile;
|
||||
|
||||
if ( XeroFile.Load( filename.c_str() ) != PSRETURN_OK )
|
||||
return false;
|
||||
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
|
||||
EL(condition);
|
||||
EL(effect);
|
||||
EL(definitions);
|
||||
|
||||
#undef EL
|
||||
#undef AT
|
||||
|
||||
//Return false on any error to be extra sure the point gets across (FIX IT)
|
||||
XMBElement root = XeroFile.GetRoot();
|
||||
|
||||
if ( root.GetNodeName() != el_definitions )
|
||||
return false;
|
||||
|
||||
XERO_ITER_EL(root, rootChild)
|
||||
{
|
||||
int name = rootChild.GetNodeName();
|
||||
if ( name == el_condition )
|
||||
{
|
||||
if ( !LoadTriggerSpec(rootChild, XeroFile, true) )
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <condition> tag. File: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( name == el_effect )
|
||||
{
|
||||
if ( !LoadTriggerSpec(rootChild, XeroFile, false) )
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <effect> tag. File: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Invalid tag in trigger XML. File: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTriggerManager::LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition )
|
||||
{
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
|
||||
EL(parameter);
|
||||
EL(window);
|
||||
EL(inputtype);
|
||||
EL(parameterorder);
|
||||
EL(windowrow);
|
||||
EL(choices);
|
||||
EL(choicetranslation);
|
||||
|
||||
AT(type);
|
||||
AT(position);
|
||||
AT(name);
|
||||
AT(size);
|
||||
AT(function);
|
||||
AT(funcParameters);
|
||||
|
||||
#undef EL
|
||||
#undef AT
|
||||
|
||||
CTriggerSpec specStore;
|
||||
specStore.functionName = CStrW( condition.GetAttributes().GetNamedItem(at_function) );
|
||||
specStore.displayName = CStrW( condition.GetAttributes().GetNamedItem(at_name) );
|
||||
specStore.funcParameters = CStr( condition.GetAttributes().GetNamedItem(at_funcParameters) ).ToInt();
|
||||
int row = -1, column = -1;
|
||||
|
||||
XERO_ITER_EL(condition, child)
|
||||
{
|
||||
int childID = child.GetNodeName();
|
||||
|
||||
if ( childID == el_windowrow )
|
||||
{
|
||||
++row;
|
||||
column = -1;
|
||||
|
||||
XERO_ITER_EL(child, windowChild)
|
||||
{
|
||||
++column;
|
||||
TriggerParameter specParam(row, column);
|
||||
specParam.name = windowChild.GetAttributes().GetNamedItem(at_name);
|
||||
childID = windowChild.GetNodeName();
|
||||
|
||||
if ( childID != el_parameter)
|
||||
return false;
|
||||
|
||||
XERO_ITER_EL(windowChild, parameterChild)
|
||||
{
|
||||
childID = parameterChild.GetNodeName();
|
||||
|
||||
if ( childID == el_window )
|
||||
{
|
||||
CStrW type( parameterChild.GetAttributes().GetNamedItem(at_type) );
|
||||
CStrW pos( parameterChild.GetAttributes().GetNamedItem(at_position) );
|
||||
CStrW size( parameterChild.GetAttributes().GetNamedItem(at_size) );
|
||||
specParam.SetWindowData(type, pos, size);
|
||||
}
|
||||
|
||||
else if ( childID == el_inputtype )
|
||||
specParam.inputType = CStrW( parameterChild.GetText() );
|
||||
else if ( childID == el_parameterorder )
|
||||
specParam.parameterOrder = CStrW( parameterChild.GetText() ).ToInt();
|
||||
else if ( childID == el_choices )
|
||||
{
|
||||
std::vector<std::wstring> choices;
|
||||
CStrW comma(L","), input(parameterChild.GetText());
|
||||
CStrW substr;
|
||||
while ( (substr = input.BeforeFirst(comma)) != input )
|
||||
{
|
||||
choices.push_back(substr);
|
||||
input = input.AfterFirst(comma);
|
||||
}
|
||||
|
||||
choices.push_back(substr); //Last element has no comma
|
||||
m_TriggerChoices[specStore.functionName + specParam.name] = choices;
|
||||
}
|
||||
else if ( childID == el_choicetranslation )
|
||||
{
|
||||
std::vector<std::wstring> choices;
|
||||
CStrW comma(L","), input(parameterChild.GetText());
|
||||
CStrW substr;
|
||||
while ( (substr = input.BeforeFirst(comma)) != input )
|
||||
{
|
||||
choices.push_back(substr);
|
||||
input = input.AfterFirst(comma);
|
||||
}
|
||||
|
||||
choices.push_back(substr); //Last element has no comma
|
||||
m_TriggerTranslations[specStore.functionName + specParam.name] = choices;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
specStore.AddParameter(specParam);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isCondition )
|
||||
m_ConditionSpecs.push_back(specStore);
|
||||
else
|
||||
m_EffectSpecs.push_back(specStore);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,221 +1,221 @@
|
||||
//========================================================
|
||||
//Description: Manages loading trigger specs (format in Atlas) and updating trigger objects
|
||||
//=======================================================
|
||||
|
||||
#ifndef INCLUDED_TRIGGERMANAGER
|
||||
#define INCLUDED_TRIGGERMANAGER
|
||||
|
||||
#include "ps/Singleton.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "simulation/ScriptObject.h"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
class CXeromyces;
|
||||
class XMBElement;
|
||||
|
||||
//Trigger storage - used be Atlas to keep track of different triggers
|
||||
|
||||
struct MapTriggerCondition
|
||||
{
|
||||
MapTriggerCondition() : linkLogic(0), negated(false) { }
|
||||
CStrW name, functionName, displayName;
|
||||
std::list<CStrW> parameters;
|
||||
int linkLogic; //0 = NONE, 1 = AND, 2 = OR
|
||||
bool negated;
|
||||
};
|
||||
|
||||
struct MapTriggerEffect
|
||||
{
|
||||
CStrW name, functionName, displayName;
|
||||
std::list<CStrW> parameters;
|
||||
};
|
||||
|
||||
struct MapTriggerLogicBlock
|
||||
{
|
||||
MapTriggerLogicBlock(size_t i, bool _not=false) : index(i), negated(_not) { }
|
||||
size_t index;
|
||||
bool negated;
|
||||
|
||||
bool operator< (const MapTriggerLogicBlock& block) const { return (index < block.index); }
|
||||
bool operator== (const MapTriggerLogicBlock& block) const { return (index == block.index); }
|
||||
};
|
||||
|
||||
struct MapTrigger
|
||||
{
|
||||
MapTrigger() : active(false), maxRunCount(0), timeValue(0) { }
|
||||
bool active;
|
||||
int maxRunCount;
|
||||
float timeValue;
|
||||
CStrW name, groupName;
|
||||
|
||||
std::set<MapTriggerLogicBlock> logicBlocks; //Indices of where "(" 's go before
|
||||
std::set<size_t> logicBlockEnds; //Indices of where ")" 's come after
|
||||
std::list<MapTriggerCondition> conditions;
|
||||
std::list<MapTriggerEffect> effects;
|
||||
|
||||
void AddLogicBlock(bool negated) { logicBlocks.insert( MapTriggerLogicBlock(conditions.size(), negated) ); }
|
||||
void AddLogicBlockEnd() { logicBlockEnds.insert( effects.size() ); }
|
||||
};
|
||||
|
||||
struct MapTriggerGroup
|
||||
{
|
||||
MapTriggerGroup() { }
|
||||
MapTriggerGroup(const CStrW& _name, const CStrW& _parentName) : name(_name), parentName(_parentName) {}
|
||||
|
||||
std::list<MapTrigger> triggers;
|
||||
std::list<CStrW> childGroups; //Indices of children
|
||||
CStrW name, parentName;
|
||||
|
||||
bool operator== (const CStrW& _name) const { return (name == _name); }
|
||||
bool operator== (const MapTriggerGroup& group) const { return (name == group.name); }
|
||||
};
|
||||
|
||||
|
||||
struct CopyIfRootChild
|
||||
{
|
||||
CopyIfRootChild(std::list<MapTriggerGroup>& groupList) : m_groupList(groupList) {}
|
||||
void operator() ( const MapTriggerGroup& group )
|
||||
{
|
||||
if ( group.parentName == L"Triggers" )
|
||||
m_groupList.push_back(group);
|
||||
}
|
||||
private:
|
||||
void operator= (const CopyIfRootChild& UNUSED(group)) const {}
|
||||
std::list<MapTriggerGroup>& m_groupList;
|
||||
};
|
||||
|
||||
//Triggers used by engine
|
||||
|
||||
class CTrigger : public CJSObject<CTrigger>
|
||||
{
|
||||
int m_runCount;
|
||||
CStrW m_conditionFuncString, m_effectFuncString, m_name, m_groupName;
|
||||
CScriptObject m_effectFunction;
|
||||
CScriptObject m_conditionFunction;
|
||||
|
||||
public:
|
||||
CTrigger();
|
||||
CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
|
||||
const CStrW& effectFunc);
|
||||
CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
|
||||
CScriptObject& condFunc, CScriptObject& effectFunc);
|
||||
|
||||
CTrigger& operator= (const CTrigger& trigger);
|
||||
~CTrigger();
|
||||
|
||||
void SetFunctionBody(const CStrW& body);
|
||||
const CStrW& GetConditionString() { return m_conditionFuncString; }
|
||||
const CStrW& GetEffectString() { return m_effectFuncString; }
|
||||
const CStrW& GetName() { return m_name; }
|
||||
const CStrW& GetGroupName() { return m_groupName; }
|
||||
|
||||
bool ShouldFire();
|
||||
//Returns false if trigger exceeds run count
|
||||
bool Fire();
|
||||
|
||||
void Activate(JSContext* cx, uintN argc, jsval* argv);
|
||||
void Deactivate(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
static JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
static void ScriptingInit();
|
||||
|
||||
JSContext* m_cx;
|
||||
|
||||
bool m_active;
|
||||
//Changeable by Atlas or needed by manager, no additional affects required
|
||||
int m_maxRunCount;
|
||||
float m_timeLeft, m_timeDelay;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//*****Holds information specifying how conditions and effects should look like in atlas******
|
||||
|
||||
struct TriggerParameter
|
||||
{
|
||||
TriggerParameter() {}
|
||||
TriggerParameter(int _row, int _column) : row(_row), column(_column) {}
|
||||
void SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize);
|
||||
//Sort parameters in the order they will be added to a sizer in atlas
|
||||
bool operator< ( const TriggerParameter& rhs ) const;
|
||||
bool operator< ( const int parameter ) const { return parameterOrder < parameter; }
|
||||
bool operator== ( const int parameter ) const { return parameterOrder == parameter; }
|
||||
|
||||
CStrW name, windowType, inputType;
|
||||
int row, column, xPos, yPos, xSize, ySize, parameterOrder;
|
||||
};
|
||||
|
||||
class CTriggerSpec
|
||||
{
|
||||
public:
|
||||
CTriggerSpec() {}
|
||||
~CTriggerSpec() {}
|
||||
|
||||
void AddParameter(const TriggerParameter& param) { parameters.insert(param); }
|
||||
const std::set<TriggerParameter>& GetParameters() const { return parameters; }
|
||||
|
||||
int funcParameters;
|
||||
CStrW displayName, functionName;
|
||||
|
||||
bool operator== (const std::wstring& display) const { return display == displayName; }
|
||||
|
||||
private:
|
||||
|
||||
//Sorted by parameter order to make things easy for Atlas
|
||||
std::set<TriggerParameter> parameters;
|
||||
};
|
||||
typedef CTriggerSpec CTriggerEffect;
|
||||
typedef CTriggerSpec CTriggerCondition;
|
||||
|
||||
|
||||
/******************************Trigger manager******************************/
|
||||
|
||||
class CTriggerManager : public Singleton<CTriggerManager>
|
||||
{
|
||||
public:
|
||||
typedef std::map<CStrW, CTrigger*>::iterator TriggerIter ;
|
||||
|
||||
CTriggerManager();
|
||||
~CTriggerManager();
|
||||
|
||||
//Returns false on detection of error
|
||||
bool LoadXml( const CStr& filename );
|
||||
void Update(float delta);
|
||||
|
||||
//Add simulation trigger (probably only called from JS)
|
||||
void AddTrigger(CTrigger* trigger);
|
||||
void AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger);
|
||||
void AddGroup(const MapTriggerGroup& group);
|
||||
void SetAllGroups(const std::list<MapTriggerGroup>& groups);
|
||||
void DestroyEngineTriggers();
|
||||
|
||||
const std::list<CTriggerCondition>& GetAllConditions() const { return m_ConditionSpecs; }
|
||||
const std::list<CTriggerEffect>& GetAllEffects() const { return m_EffectSpecs; }
|
||||
const std::list<MapTriggerGroup>& GetAllTriggerGroups() const { return m_GroupList; }
|
||||
std::vector<std::wstring> GetTriggerChoices(const std::wstring& name);
|
||||
std::vector<std::wstring> GetTriggerTranslations(const std::wstring& name);
|
||||
|
||||
std::map<CStrW, CTrigger*> m_TriggerMap; //Simulation triggers - used in engine
|
||||
|
||||
private:
|
||||
bool LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition );
|
||||
|
||||
//Contains choices for trigger choice box parameters, with key = spec.funcName+paramName
|
||||
std::map<std::wstring, std::vector<std::wstring> > m_TriggerChoices;
|
||||
std::map<std::wstring, std::vector<std::wstring> > m_TriggerTranslations;
|
||||
|
||||
//Holds information which descibes trigger layout in atlas
|
||||
std::list<MapTriggerGroup> m_GroupList;
|
||||
std::list<CTriggerCondition> m_ConditionSpecs;
|
||||
std::list<CTriggerEffect> m_EffectSpecs;
|
||||
|
||||
float m_UpdateRate; //TODO: Get this from a config setting
|
||||
float m_UpdateTime;
|
||||
|
||||
};
|
||||
|
||||
#define g_TriggerManager CTriggerManager::GetSingleton()
|
||||
|
||||
#endif //ifndef INCLUDED_TRIGGERMANAGER
|
||||
//========================================================
|
||||
//Description: Manages loading trigger specs (format in Atlas) and updating trigger objects
|
||||
//=======================================================
|
||||
|
||||
#ifndef INCLUDED_TRIGGERMANAGER
|
||||
#define INCLUDED_TRIGGERMANAGER
|
||||
|
||||
#include "ps/Singleton.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "simulation/ScriptObject.h"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
class CXeromyces;
|
||||
class XMBElement;
|
||||
|
||||
//Trigger storage - used be Atlas to keep track of different triggers
|
||||
|
||||
struct MapTriggerCondition
|
||||
{
|
||||
MapTriggerCondition() : linkLogic(0), negated(false) { }
|
||||
CStrW name, functionName, displayName;
|
||||
std::list<CStrW> parameters;
|
||||
int linkLogic; //0 = NONE, 1 = AND, 2 = OR
|
||||
bool negated;
|
||||
};
|
||||
|
||||
struct MapTriggerEffect
|
||||
{
|
||||
CStrW name, functionName, displayName;
|
||||
std::list<CStrW> parameters;
|
||||
};
|
||||
|
||||
struct MapTriggerLogicBlock
|
||||
{
|
||||
MapTriggerLogicBlock(size_t i, bool _not=false) : index(i), negated(_not) { }
|
||||
size_t index;
|
||||
bool negated;
|
||||
|
||||
bool operator< (const MapTriggerLogicBlock& block) const { return (index < block.index); }
|
||||
bool operator== (const MapTriggerLogicBlock& block) const { return (index == block.index); }
|
||||
};
|
||||
|
||||
struct MapTrigger
|
||||
{
|
||||
MapTrigger() : active(false), maxRunCount(0), timeValue(0) { }
|
||||
bool active;
|
||||
int maxRunCount;
|
||||
float timeValue;
|
||||
CStrW name, groupName;
|
||||
|
||||
std::set<MapTriggerLogicBlock> logicBlocks; //Indices of where "(" 's go before
|
||||
std::set<size_t> logicBlockEnds; //Indices of where ")" 's come after
|
||||
std::list<MapTriggerCondition> conditions;
|
||||
std::list<MapTriggerEffect> effects;
|
||||
|
||||
void AddLogicBlock(bool negated) { logicBlocks.insert( MapTriggerLogicBlock(conditions.size(), negated) ); }
|
||||
void AddLogicBlockEnd() { logicBlockEnds.insert( effects.size() ); }
|
||||
};
|
||||
|
||||
struct MapTriggerGroup
|
||||
{
|
||||
MapTriggerGroup() { }
|
||||
MapTriggerGroup(const CStrW& _name, const CStrW& _parentName) : name(_name), parentName(_parentName) {}
|
||||
|
||||
std::list<MapTrigger> triggers;
|
||||
std::list<CStrW> childGroups; //Indices of children
|
||||
CStrW name, parentName;
|
||||
|
||||
bool operator== (const CStrW& _name) const { return (name == _name); }
|
||||
bool operator== (const MapTriggerGroup& group) const { return (name == group.name); }
|
||||
};
|
||||
|
||||
|
||||
struct CopyIfRootChild
|
||||
{
|
||||
CopyIfRootChild(std::list<MapTriggerGroup>& groupList) : m_groupList(groupList) {}
|
||||
void operator() ( const MapTriggerGroup& group )
|
||||
{
|
||||
if ( group.parentName == L"Triggers" )
|
||||
m_groupList.push_back(group);
|
||||
}
|
||||
private:
|
||||
void operator= (const CopyIfRootChild& UNUSED(group)) const {}
|
||||
std::list<MapTriggerGroup>& m_groupList;
|
||||
};
|
||||
|
||||
//Triggers used by engine
|
||||
|
||||
class CTrigger : public CJSObject<CTrigger>
|
||||
{
|
||||
int m_runCount;
|
||||
CStrW m_conditionFuncString, m_effectFuncString, m_name, m_groupName;
|
||||
CScriptObject m_effectFunction;
|
||||
CScriptObject m_conditionFunction;
|
||||
|
||||
public:
|
||||
CTrigger();
|
||||
CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
|
||||
const CStrW& effectFunc);
|
||||
CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
|
||||
CScriptObject& condFunc, CScriptObject& effectFunc);
|
||||
|
||||
CTrigger& operator= (const CTrigger& trigger);
|
||||
~CTrigger();
|
||||
|
||||
void SetFunctionBody(const CStrW& body);
|
||||
const CStrW& GetConditionString() { return m_conditionFuncString; }
|
||||
const CStrW& GetEffectString() { return m_effectFuncString; }
|
||||
const CStrW& GetName() { return m_name; }
|
||||
const CStrW& GetGroupName() { return m_groupName; }
|
||||
|
||||
bool ShouldFire();
|
||||
//Returns false if trigger exceeds run count
|
||||
bool Fire();
|
||||
|
||||
void Activate(JSContext* cx, uintN argc, jsval* argv);
|
||||
void Deactivate(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
static JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
static void ScriptingInit();
|
||||
|
||||
JSContext* m_cx;
|
||||
|
||||
bool m_active;
|
||||
//Changeable by Atlas or needed by manager, no additional affects required
|
||||
int m_maxRunCount;
|
||||
float m_timeLeft, m_timeDelay;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//*****Holds information specifying how conditions and effects should look like in atlas******
|
||||
|
||||
struct TriggerParameter
|
||||
{
|
||||
TriggerParameter() {}
|
||||
TriggerParameter(int _row, int _column) : row(_row), column(_column) {}
|
||||
void SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize);
|
||||
//Sort parameters in the order they will be added to a sizer in atlas
|
||||
bool operator< ( const TriggerParameter& rhs ) const;
|
||||
bool operator< ( const int parameter ) const { return parameterOrder < parameter; }
|
||||
bool operator== ( const int parameter ) const { return parameterOrder == parameter; }
|
||||
|
||||
CStrW name, windowType, inputType;
|
||||
int row, column, xPos, yPos, xSize, ySize, parameterOrder;
|
||||
};
|
||||
|
||||
class CTriggerSpec
|
||||
{
|
||||
public:
|
||||
CTriggerSpec() {}
|
||||
~CTriggerSpec() {}
|
||||
|
||||
void AddParameter(const TriggerParameter& param) { parameters.insert(param); }
|
||||
const std::set<TriggerParameter>& GetParameters() const { return parameters; }
|
||||
|
||||
int funcParameters;
|
||||
CStrW displayName, functionName;
|
||||
|
||||
bool operator== (const std::wstring& display) const { return display == displayName; }
|
||||
|
||||
private:
|
||||
|
||||
//Sorted by parameter order to make things easy for Atlas
|
||||
std::set<TriggerParameter> parameters;
|
||||
};
|
||||
typedef CTriggerSpec CTriggerEffect;
|
||||
typedef CTriggerSpec CTriggerCondition;
|
||||
|
||||
|
||||
/******************************Trigger manager******************************/
|
||||
|
||||
class CTriggerManager : public Singleton<CTriggerManager>
|
||||
{
|
||||
public:
|
||||
typedef std::map<CStrW, CTrigger*>::iterator TriggerIter ;
|
||||
|
||||
CTriggerManager();
|
||||
~CTriggerManager();
|
||||
|
||||
//Returns false on detection of error
|
||||
bool LoadXml( const CStr& filename );
|
||||
void Update(float delta);
|
||||
|
||||
//Add simulation trigger (probably only called from JS)
|
||||
void AddTrigger(CTrigger* trigger);
|
||||
void AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger);
|
||||
void AddGroup(const MapTriggerGroup& group);
|
||||
void SetAllGroups(const std::list<MapTriggerGroup>& groups);
|
||||
void DestroyEngineTriggers();
|
||||
|
||||
const std::list<CTriggerCondition>& GetAllConditions() const { return m_ConditionSpecs; }
|
||||
const std::list<CTriggerEffect>& GetAllEffects() const { return m_EffectSpecs; }
|
||||
const std::list<MapTriggerGroup>& GetAllTriggerGroups() const { return m_GroupList; }
|
||||
std::vector<std::wstring> GetTriggerChoices(const std::wstring& name);
|
||||
std::vector<std::wstring> GetTriggerTranslations(const std::wstring& name);
|
||||
|
||||
std::map<CStrW, CTrigger*> m_TriggerMap; //Simulation triggers - used in engine
|
||||
|
||||
private:
|
||||
bool LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition );
|
||||
|
||||
//Contains choices for trigger choice box parameters, with key = spec.funcName+paramName
|
||||
std::map<std::wstring, std::vector<std::wstring> > m_TriggerChoices;
|
||||
std::map<std::wstring, std::vector<std::wstring> > m_TriggerTranslations;
|
||||
|
||||
//Holds information which descibes trigger layout in atlas
|
||||
std::list<MapTriggerGroup> m_GroupList;
|
||||
std::list<CTriggerCondition> m_ConditionSpecs;
|
||||
std::list<CTriggerEffect> m_EffectSpecs;
|
||||
|
||||
float m_UpdateRate; //TODO: Get this from a config setting
|
||||
float m_UpdateTime;
|
||||
|
||||
};
|
||||
|
||||
#define g_TriggerManager CTriggerManager::GetSingleton()
|
||||
|
||||
#endif //ifndef INCLUDED_TRIGGERMANAGER
|
||||
|
@ -1,96 +1,96 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "simulation/Scheduler.h"
|
||||
#include "simulation/EntityTemplate.h"
|
||||
#include "simulation/EntityTemplateCollection.h"
|
||||
#include "simulation/Entity.h"
|
||||
#include "simulation/Projectile.h"
|
||||
#include "simulation/EventHandlers.h"
|
||||
#include "simulation/TriggerManager.h"
|
||||
#include "simulation/FormationManager.h"
|
||||
#include "simulation/FormationCollection.h"
|
||||
#include "simulation/ProductionQueue.h"
|
||||
#include "simulation/Technology.h"
|
||||
#include "simulation/TechnologyCollection.h"
|
||||
#include "simulation/PathfindEngine.h"
|
||||
|
||||
void SimulationScriptInit()
|
||||
{
|
||||
CJSProgressTimer::ScriptingInit();
|
||||
CEntityTemplate::ScriptingInit();
|
||||
CEntity::ScriptingInit();
|
||||
CProjectile::ScriptingInit();
|
||||
CTrigger::ScriptingInit();
|
||||
CProductionItem::ScriptingInit();
|
||||
CProductionQueue::ScriptingInit();
|
||||
CTechnology::ScriptingInit();
|
||||
|
||||
EntityCollection::Init( "EntityCollection" );
|
||||
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_ENTER", CFormationEvent::FORMATION_ENTER );
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_LEAVE", CFormationEvent::FORMATION_LEAVE );
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_DAMAGE", CFormationEvent::FORMATION_DAMAGE );
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_ATTACK", CFormationEvent::FORMATION_ATTACK );
|
||||
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_NONE", CEntityListener::NOTIFY_NONE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_GOTO", CEntityListener::NOTIFY_GOTO );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_RUN", CEntityListener::NOTIFY_RUN );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_FOLLOW", CEntityListener::NOTIFY_FOLLOW );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ATTACK", CEntityListener::NOTIFY_ATTACK );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_DAMAGE", CEntityListener::NOTIFY_DAMAGE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_COMBAT", CEntityListener::NOTIFY_COMBAT );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ESCORT", CEntityListener::NOTIFY_ESCORT );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_HEAL", CEntityListener::NOTIFY_HEAL );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_GATHER", CEntityListener::NOTIFY_GATHER );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_IDLE", CEntityListener::NOTIFY_IDLE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ORDER_CHANGE", CEntityListener::NOTIFY_ORDER_CHANGE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ALL", CEntityListener::NOTIFY_ALL );
|
||||
|
||||
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_RUN", CEntityOrder::ORDER_RUN );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_PATROL", CEntityOrder::ORDER_PATROL );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_CONTACT_ACTION", CEntityOrder::ORDER_CONTACT_ACTION );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_PRODUCE", CEntityOrder::ORDER_PRODUCE );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_SET_RALLY_POINT", CEntityOrder::ORDER_SET_RALLY_POINT );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_SET_STANCE", CEntityOrder::ORDER_SET_STANCE );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_START_CONSTRUCTION", CEntityOrder::ORDER_START_CONSTRUCTION );
|
||||
}
|
||||
|
||||
|
||||
void SimulationInit()
|
||||
{
|
||||
TIMER("SimulationInit");
|
||||
|
||||
new CEntityTemplateCollection;
|
||||
new CFormationCollection;
|
||||
new CTechnologyCollection;
|
||||
g_EntityFormationCollection.LoadTemplates();
|
||||
g_TechnologyCollection.LoadTechnologies();
|
||||
new CFormationManager;
|
||||
new CTriggerManager;
|
||||
g_TriggerManager.LoadXml(CStr("scripts/TriggerSpecs.xml"));
|
||||
g_ScriptingHost.RunScript("scripts/trigger_functions.js");
|
||||
|
||||
// CEntityManager is managed by CWorld
|
||||
//new CEntityManager;
|
||||
|
||||
new CPathfindEngine;
|
||||
}
|
||||
|
||||
void SimulationShutdown()
|
||||
{
|
||||
TIMER_BEGIN("shutdown Pathfinder");
|
||||
delete &g_Pathfinder;
|
||||
TIMER_END("shutdown Pathfinder");
|
||||
|
||||
// Managed by CWorld
|
||||
// delete &g_EntityManager;
|
||||
|
||||
delete &g_TriggerManager;
|
||||
delete &g_FormationManager;
|
||||
delete &g_TechnologyCollection;
|
||||
delete &g_EntityFormationCollection;
|
||||
delete &g_EntityTemplateCollection;
|
||||
}
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "simulation/Scheduler.h"
|
||||
#include "simulation/EntityTemplate.h"
|
||||
#include "simulation/EntityTemplateCollection.h"
|
||||
#include "simulation/Entity.h"
|
||||
#include "simulation/Projectile.h"
|
||||
#include "simulation/EventHandlers.h"
|
||||
#include "simulation/TriggerManager.h"
|
||||
#include "simulation/FormationManager.h"
|
||||
#include "simulation/FormationCollection.h"
|
||||
#include "simulation/ProductionQueue.h"
|
||||
#include "simulation/Technology.h"
|
||||
#include "simulation/TechnologyCollection.h"
|
||||
#include "simulation/PathfindEngine.h"
|
||||
|
||||
void SimulationScriptInit()
|
||||
{
|
||||
CJSProgressTimer::ScriptingInit();
|
||||
CEntityTemplate::ScriptingInit();
|
||||
CEntity::ScriptingInit();
|
||||
CProjectile::ScriptingInit();
|
||||
CTrigger::ScriptingInit();
|
||||
CProductionItem::ScriptingInit();
|
||||
CProductionQueue::ScriptingInit();
|
||||
CTechnology::ScriptingInit();
|
||||
|
||||
EntityCollection::Init( "EntityCollection" );
|
||||
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_ENTER", CFormationEvent::FORMATION_ENTER );
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_LEAVE", CFormationEvent::FORMATION_LEAVE );
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_DAMAGE", CFormationEvent::FORMATION_DAMAGE );
|
||||
g_ScriptingHost.DefineConstant( "FORMATION_ATTACK", CFormationEvent::FORMATION_ATTACK );
|
||||
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_NONE", CEntityListener::NOTIFY_NONE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_GOTO", CEntityListener::NOTIFY_GOTO );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_RUN", CEntityListener::NOTIFY_RUN );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_FOLLOW", CEntityListener::NOTIFY_FOLLOW );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ATTACK", CEntityListener::NOTIFY_ATTACK );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_DAMAGE", CEntityListener::NOTIFY_DAMAGE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_COMBAT", CEntityListener::NOTIFY_COMBAT );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ESCORT", CEntityListener::NOTIFY_ESCORT );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_HEAL", CEntityListener::NOTIFY_HEAL );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_GATHER", CEntityListener::NOTIFY_GATHER );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_IDLE", CEntityListener::NOTIFY_IDLE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ORDER_CHANGE", CEntityListener::NOTIFY_ORDER_CHANGE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ALL", CEntityListener::NOTIFY_ALL );
|
||||
|
||||
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_RUN", CEntityOrder::ORDER_RUN );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_PATROL", CEntityOrder::ORDER_PATROL );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_CONTACT_ACTION", CEntityOrder::ORDER_CONTACT_ACTION );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_PRODUCE", CEntityOrder::ORDER_PRODUCE );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_SET_RALLY_POINT", CEntityOrder::ORDER_SET_RALLY_POINT );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_SET_STANCE", CEntityOrder::ORDER_SET_STANCE );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_START_CONSTRUCTION", CEntityOrder::ORDER_START_CONSTRUCTION );
|
||||
}
|
||||
|
||||
|
||||
void SimulationInit()
|
||||
{
|
||||
TIMER("SimulationInit");
|
||||
|
||||
new CEntityTemplateCollection;
|
||||
new CFormationCollection;
|
||||
new CTechnologyCollection;
|
||||
g_EntityFormationCollection.LoadTemplates();
|
||||
g_TechnologyCollection.LoadTechnologies();
|
||||
new CFormationManager;
|
||||
new CTriggerManager;
|
||||
g_TriggerManager.LoadXml(CStr("scripts/TriggerSpecs.xml"));
|
||||
g_ScriptingHost.RunScript("scripts/trigger_functions.js");
|
||||
|
||||
// CEntityManager is managed by CWorld
|
||||
//new CEntityManager;
|
||||
|
||||
new CPathfindEngine;
|
||||
}
|
||||
|
||||
void SimulationShutdown()
|
||||
{
|
||||
TIMER_BEGIN("shutdown Pathfinder");
|
||||
delete &g_Pathfinder;
|
||||
TIMER_END("shutdown Pathfinder");
|
||||
|
||||
// Managed by CWorld
|
||||
// delete &g_EntityManager;
|
||||
|
||||
delete &g_TriggerManager;
|
||||
delete &g_FormationManager;
|
||||
delete &g_TechnologyCollection;
|
||||
delete &g_EntityFormationCollection;
|
||||
delete &g_EntityTemplateCollection;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
extern void SimulationScriptInit();
|
||||
|
||||
extern void SimulationInit();
|
||||
extern void SimulationShutdown();
|
||||
extern void SimulationScriptInit();
|
||||
|
||||
extern void SimulationInit();
|
||||
extern void SimulationShutdown();
|
||||
|
@ -1,360 +1,360 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroup.cpp
|
||||
* Project : 0 A.D.
|
||||
* Description : Loads up a group of sound files with shared properties,
|
||||
* and provides a simple interface for playing them.
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "SoundGroup.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "lib/rand.h"
|
||||
|
||||
#define LOG_CATEGORY "audio"
|
||||
|
||||
|
||||
void CSoundGroup::SetGain(float gain)
|
||||
{
|
||||
gain = std::min(gain, 1.0f);
|
||||
m_Gain = gain;
|
||||
}
|
||||
|
||||
void CSoundGroup::SetDefaultValues()
|
||||
{
|
||||
m_index = 0;
|
||||
m_Flags = 0;
|
||||
m_Intensity = 0;
|
||||
m_CurTime = 0.0f;
|
||||
|
||||
// sane defaults; will probably be replaced by the values read during LoadSoundGroup.
|
||||
SetGain(0.5f);
|
||||
m_Pitch = 1.0f;
|
||||
m_Priority = 60;
|
||||
m_PitchUpper = 1.1f;
|
||||
m_PitchLower = 0.9f;
|
||||
m_GainUpper = 1.0f;
|
||||
m_GainLower = 0.8f;
|
||||
m_ConeOuterGain = 0.0f;
|
||||
m_ConeInnerAngle = 360.0f;
|
||||
m_ConeOuterAngle = 360.0f;
|
||||
m_Decay = 3.0f;
|
||||
m_IntensityThreshold = 3;
|
||||
// WARNING: m_TimeWindow is currently unused and uninitialized
|
||||
}
|
||||
|
||||
CSoundGroup::CSoundGroup()
|
||||
{
|
||||
SetDefaultValues();
|
||||
}
|
||||
|
||||
CSoundGroup::CSoundGroup(const char *XMLfile)
|
||||
{
|
||||
SetDefaultValues();
|
||||
LoadSoundGroup(XMLfile);
|
||||
}
|
||||
|
||||
CSoundGroup::~CSoundGroup()
|
||||
{
|
||||
// clean up all the handles from this group.
|
||||
ReleaseGroup();
|
||||
}
|
||||
|
||||
static float RandFloat(float min, float max)
|
||||
{
|
||||
return float(rand(min*100.0f, max*100.0f) / 100.0f);
|
||||
}
|
||||
|
||||
void CSoundGroup::UploadPropertiesAndPlay(Handle hSound, const CVector3D& position)
|
||||
{
|
||||
// interface/UI sounds should always be played at the listener's
|
||||
// position, which is achieved by setting position to 0 and
|
||||
// having that treated as relative to the listener.
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
bool relative = true;
|
||||
if(!TestFlag(eOmnipresent))
|
||||
{
|
||||
x = position.X;
|
||||
y = position.Y;
|
||||
z = position.Z;
|
||||
relative = false;
|
||||
}
|
||||
|
||||
snd_set_pos(hSound, x, y, z, relative);
|
||||
|
||||
float gain = TestFlag(eRandGain)? RandFloat(m_GainLower, m_GainUpper) : m_Gain;
|
||||
gain = std::min(gain, 1.0f); // guard against roundoff error in RandFloat or too high m_GainUpper
|
||||
snd_set_gain(hSound, gain);
|
||||
|
||||
const float pitch = TestFlag(eRandPitch)? RandFloat(m_PitchLower, m_PitchUpper) : m_Pitch;
|
||||
snd_set_pitch(hSound, pitch);
|
||||
|
||||
snd_play(hSound, m_Priority);
|
||||
}
|
||||
|
||||
|
||||
void CSoundGroup::PlayNext(const CVector3D& position)
|
||||
{
|
||||
if(m_Intensity >= m_IntensityThreshold)
|
||||
{
|
||||
if(!is_playing(m_hReplacement))
|
||||
{
|
||||
// load up replacement file
|
||||
m_hReplacement = snd_open(m_filepath + m_intensity_file);
|
||||
if(m_hReplacement < 0) // one cause: sound is disabled
|
||||
return;
|
||||
|
||||
UploadPropertiesAndPlay(m_hReplacement, position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no sounds, return
|
||||
if (filenames.size() == 0)
|
||||
return;
|
||||
|
||||
// try loading on the fly only when we need the sound to see if that fixes release problems...
|
||||
if(TestFlag(eRandOrder))
|
||||
m_index = (size_t)rand(0, (size_t)filenames.size());
|
||||
// (note: previously snd_group[m_index] was used in place of hs)
|
||||
Handle hs = snd_open(m_filepath + filenames[m_index]);
|
||||
if(hs < 0) // one cause: sound is disabled
|
||||
return;
|
||||
|
||||
UploadPropertiesAndPlay(hs, position);
|
||||
}
|
||||
|
||||
playtimes[m_index] = 0.0f;
|
||||
m_index++;
|
||||
m_Intensity++;
|
||||
if(m_Intensity > m_IntensityThreshold)
|
||||
m_Intensity = m_IntensityThreshold;
|
||||
|
||||
if(m_index >= filenames.size())
|
||||
Reload();
|
||||
}
|
||||
|
||||
void CSoundGroup::Reload()
|
||||
{
|
||||
m_index = 0; // reset our index
|
||||
// get rid of the used handles
|
||||
snd_group.clear();
|
||||
// clear out the old timers
|
||||
playtimes.clear();
|
||||
//Reload the sounds
|
||||
/*for(size_t i = 0; i < filenames.size(); i++)
|
||||
{
|
||||
string szTemp = m_filepath + filenames[i];
|
||||
Handle temp = snd_open(m_filepath + filenames[i]);
|
||||
snd_set_gain(temp, m_Gain);
|
||||
snd_set_pitch(temp, m_Pitch);
|
||||
snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
|
||||
snd_group.push_back(temp);
|
||||
|
||||
}*/
|
||||
while(playtimes.size() < filenames.size())
|
||||
playtimes.push_back(-1.0f);
|
||||
//if(TestFlag(eRandOrder))
|
||||
//random_shuffle(snd_group.begin(), snd_group.end());
|
||||
}
|
||||
|
||||
void CSoundGroup::ReleaseGroup()
|
||||
{
|
||||
for(size_t i = m_index; i<snd_group.size(); i++)
|
||||
{
|
||||
//if(!is_playing(snd_group[i]))
|
||||
snd_free(snd_group[i]);
|
||||
}
|
||||
snd_group.clear();
|
||||
playtimes.clear();
|
||||
//if(is_playing(m_hReplacement))
|
||||
// snd_free(m_hReplacement);
|
||||
m_index = 0;
|
||||
|
||||
}
|
||||
|
||||
void CSoundGroup::Update(float TimeSinceLastFrame)
|
||||
{
|
||||
for(size_t i = 0; i < playtimes.size(); i++)
|
||||
{
|
||||
if(playtimes[i] >= 0.0f)
|
||||
playtimes[i] += TimeSinceLastFrame;
|
||||
|
||||
if(playtimes[i] >= m_Decay)
|
||||
{
|
||||
playtimes[i] = -1.0f;
|
||||
m_Intensity--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSoundGroup::LoadSoundGroup(const char *XMLfile)
|
||||
{
|
||||
CXeromyces XeroFile;
|
||||
if (XeroFile.Load(XMLfile) != PSRETURN_OK)
|
||||
return false;
|
||||
|
||||
// adjust the path name for resources if necessary
|
||||
//m_Name = XMLfile + directorypath;
|
||||
|
||||
//Define elements used in XML file
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
EL(soundgroup);
|
||||
EL(gain);
|
||||
EL(looping);
|
||||
EL(omnipresent);
|
||||
EL(pitch);
|
||||
EL(priority);
|
||||
EL(randorder);
|
||||
EL(randgain);
|
||||
EL(randpitch);
|
||||
EL(conegain);
|
||||
EL(coneinner);
|
||||
EL(coneouter);
|
||||
EL(sound);
|
||||
EL(gainupper);
|
||||
EL(gainlower);
|
||||
EL(pitchupper);
|
||||
EL(pitchlower);
|
||||
EL(path);
|
||||
EL(threshold);
|
||||
EL(decay);
|
||||
EL(replacement);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
XMBElement root = XeroFile.GetRoot();
|
||||
|
||||
if (root.GetNodeName() != el_soundgroup)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Invalid SoundGroup format (unrecognised root element '%s')", XeroFile.GetElementString(root.GetNodeName()).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
XERO_ITER_EL(root, child)
|
||||
{
|
||||
|
||||
int child_name = child.GetNodeName();
|
||||
|
||||
if(child_name == el_gain)
|
||||
{
|
||||
SetGain(CStr(child.GetText()).ToFloat());
|
||||
}
|
||||
|
||||
if(child_name == el_looping)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eLoop);
|
||||
}
|
||||
|
||||
if(child_name == el_omnipresent)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eOmnipresent);
|
||||
}
|
||||
|
||||
if(child_name == el_pitch)
|
||||
{
|
||||
this->m_Pitch = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_priority)
|
||||
{
|
||||
this->m_Priority = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_randorder)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eRandOrder);
|
||||
}
|
||||
|
||||
if(child_name == el_randgain)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eRandGain);
|
||||
}
|
||||
|
||||
if(child_name == el_gainupper)
|
||||
{
|
||||
this->m_GainUpper = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_gainlower)
|
||||
{
|
||||
this->m_GainLower = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_randpitch)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eRandPitch);
|
||||
}
|
||||
|
||||
if(child_name == el_pitchupper)
|
||||
{
|
||||
this->m_PitchUpper = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_pitchlower)
|
||||
{
|
||||
this->m_PitchLower = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_conegain)
|
||||
{
|
||||
this->m_ConeOuterGain = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_coneinner)
|
||||
{
|
||||
this->m_ConeInnerAngle = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_coneouter)
|
||||
{
|
||||
this->m_ConeOuterAngle = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_sound)
|
||||
{
|
||||
CStr szTemp(child.GetText());
|
||||
this->filenames.push_back(szTemp);
|
||||
|
||||
}
|
||||
if(child_name == el_path)
|
||||
{
|
||||
m_filepath = child.GetText();
|
||||
|
||||
}
|
||||
if(child_name == el_threshold)
|
||||
{
|
||||
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
|
||||
m_IntensityThreshold = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_decay)
|
||||
{
|
||||
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
|
||||
m_Decay = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_replacement)
|
||||
{
|
||||
m_intensity_file = child.GetText();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reload();
|
||||
return true;
|
||||
|
||||
}
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroup.cpp
|
||||
* Project : 0 A.D.
|
||||
* Description : Loads up a group of sound files with shared properties,
|
||||
* and provides a simple interface for playing them.
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "SoundGroup.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "lib/rand.h"
|
||||
|
||||
#define LOG_CATEGORY "audio"
|
||||
|
||||
|
||||
void CSoundGroup::SetGain(float gain)
|
||||
{
|
||||
gain = std::min(gain, 1.0f);
|
||||
m_Gain = gain;
|
||||
}
|
||||
|
||||
void CSoundGroup::SetDefaultValues()
|
||||
{
|
||||
m_index = 0;
|
||||
m_Flags = 0;
|
||||
m_Intensity = 0;
|
||||
m_CurTime = 0.0f;
|
||||
|
||||
// sane defaults; will probably be replaced by the values read during LoadSoundGroup.
|
||||
SetGain(0.5f);
|
||||
m_Pitch = 1.0f;
|
||||
m_Priority = 60;
|
||||
m_PitchUpper = 1.1f;
|
||||
m_PitchLower = 0.9f;
|
||||
m_GainUpper = 1.0f;
|
||||
m_GainLower = 0.8f;
|
||||
m_ConeOuterGain = 0.0f;
|
||||
m_ConeInnerAngle = 360.0f;
|
||||
m_ConeOuterAngle = 360.0f;
|
||||
m_Decay = 3.0f;
|
||||
m_IntensityThreshold = 3;
|
||||
// WARNING: m_TimeWindow is currently unused and uninitialized
|
||||
}
|
||||
|
||||
CSoundGroup::CSoundGroup()
|
||||
{
|
||||
SetDefaultValues();
|
||||
}
|
||||
|
||||
CSoundGroup::CSoundGroup(const char *XMLfile)
|
||||
{
|
||||
SetDefaultValues();
|
||||
LoadSoundGroup(XMLfile);
|
||||
}
|
||||
|
||||
CSoundGroup::~CSoundGroup()
|
||||
{
|
||||
// clean up all the handles from this group.
|
||||
ReleaseGroup();
|
||||
}
|
||||
|
||||
static float RandFloat(float min, float max)
|
||||
{
|
||||
return float(rand(min*100.0f, max*100.0f) / 100.0f);
|
||||
}
|
||||
|
||||
void CSoundGroup::UploadPropertiesAndPlay(Handle hSound, const CVector3D& position)
|
||||
{
|
||||
// interface/UI sounds should always be played at the listener's
|
||||
// position, which is achieved by setting position to 0 and
|
||||
// having that treated as relative to the listener.
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
bool relative = true;
|
||||
if(!TestFlag(eOmnipresent))
|
||||
{
|
||||
x = position.X;
|
||||
y = position.Y;
|
||||
z = position.Z;
|
||||
relative = false;
|
||||
}
|
||||
|
||||
snd_set_pos(hSound, x, y, z, relative);
|
||||
|
||||
float gain = TestFlag(eRandGain)? RandFloat(m_GainLower, m_GainUpper) : m_Gain;
|
||||
gain = std::min(gain, 1.0f); // guard against roundoff error in RandFloat or too high m_GainUpper
|
||||
snd_set_gain(hSound, gain);
|
||||
|
||||
const float pitch = TestFlag(eRandPitch)? RandFloat(m_PitchLower, m_PitchUpper) : m_Pitch;
|
||||
snd_set_pitch(hSound, pitch);
|
||||
|
||||
snd_play(hSound, m_Priority);
|
||||
}
|
||||
|
||||
|
||||
void CSoundGroup::PlayNext(const CVector3D& position)
|
||||
{
|
||||
if(m_Intensity >= m_IntensityThreshold)
|
||||
{
|
||||
if(!is_playing(m_hReplacement))
|
||||
{
|
||||
// load up replacement file
|
||||
m_hReplacement = snd_open(m_filepath + m_intensity_file);
|
||||
if(m_hReplacement < 0) // one cause: sound is disabled
|
||||
return;
|
||||
|
||||
UploadPropertiesAndPlay(m_hReplacement, position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no sounds, return
|
||||
if (filenames.size() == 0)
|
||||
return;
|
||||
|
||||
// try loading on the fly only when we need the sound to see if that fixes release problems...
|
||||
if(TestFlag(eRandOrder))
|
||||
m_index = (size_t)rand(0, (size_t)filenames.size());
|
||||
// (note: previously snd_group[m_index] was used in place of hs)
|
||||
Handle hs = snd_open(m_filepath + filenames[m_index]);
|
||||
if(hs < 0) // one cause: sound is disabled
|
||||
return;
|
||||
|
||||
UploadPropertiesAndPlay(hs, position);
|
||||
}
|
||||
|
||||
playtimes[m_index] = 0.0f;
|
||||
m_index++;
|
||||
m_Intensity++;
|
||||
if(m_Intensity > m_IntensityThreshold)
|
||||
m_Intensity = m_IntensityThreshold;
|
||||
|
||||
if(m_index >= filenames.size())
|
||||
Reload();
|
||||
}
|
||||
|
||||
void CSoundGroup::Reload()
|
||||
{
|
||||
m_index = 0; // reset our index
|
||||
// get rid of the used handles
|
||||
snd_group.clear();
|
||||
// clear out the old timers
|
||||
playtimes.clear();
|
||||
//Reload the sounds
|
||||
/*for(size_t i = 0; i < filenames.size(); i++)
|
||||
{
|
||||
string szTemp = m_filepath + filenames[i];
|
||||
Handle temp = snd_open(m_filepath + filenames[i]);
|
||||
snd_set_gain(temp, m_Gain);
|
||||
snd_set_pitch(temp, m_Pitch);
|
||||
snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
|
||||
snd_group.push_back(temp);
|
||||
|
||||
}*/
|
||||
while(playtimes.size() < filenames.size())
|
||||
playtimes.push_back(-1.0f);
|
||||
//if(TestFlag(eRandOrder))
|
||||
//random_shuffle(snd_group.begin(), snd_group.end());
|
||||
}
|
||||
|
||||
void CSoundGroup::ReleaseGroup()
|
||||
{
|
||||
for(size_t i = m_index; i<snd_group.size(); i++)
|
||||
{
|
||||
//if(!is_playing(snd_group[i]))
|
||||
snd_free(snd_group[i]);
|
||||
}
|
||||
snd_group.clear();
|
||||
playtimes.clear();
|
||||
//if(is_playing(m_hReplacement))
|
||||
// snd_free(m_hReplacement);
|
||||
m_index = 0;
|
||||
|
||||
}
|
||||
|
||||
void CSoundGroup::Update(float TimeSinceLastFrame)
|
||||
{
|
||||
for(size_t i = 0; i < playtimes.size(); i++)
|
||||
{
|
||||
if(playtimes[i] >= 0.0f)
|
||||
playtimes[i] += TimeSinceLastFrame;
|
||||
|
||||
if(playtimes[i] >= m_Decay)
|
||||
{
|
||||
playtimes[i] = -1.0f;
|
||||
m_Intensity--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSoundGroup::LoadSoundGroup(const char *XMLfile)
|
||||
{
|
||||
CXeromyces XeroFile;
|
||||
if (XeroFile.Load(XMLfile) != PSRETURN_OK)
|
||||
return false;
|
||||
|
||||
// adjust the path name for resources if necessary
|
||||
//m_Name = XMLfile + directorypath;
|
||||
|
||||
//Define elements used in XML file
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
EL(soundgroup);
|
||||
EL(gain);
|
||||
EL(looping);
|
||||
EL(omnipresent);
|
||||
EL(pitch);
|
||||
EL(priority);
|
||||
EL(randorder);
|
||||
EL(randgain);
|
||||
EL(randpitch);
|
||||
EL(conegain);
|
||||
EL(coneinner);
|
||||
EL(coneouter);
|
||||
EL(sound);
|
||||
EL(gainupper);
|
||||
EL(gainlower);
|
||||
EL(pitchupper);
|
||||
EL(pitchlower);
|
||||
EL(path);
|
||||
EL(threshold);
|
||||
EL(decay);
|
||||
EL(replacement);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
XMBElement root = XeroFile.GetRoot();
|
||||
|
||||
if (root.GetNodeName() != el_soundgroup)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, "Invalid SoundGroup format (unrecognised root element '%s')", XeroFile.GetElementString(root.GetNodeName()).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
XERO_ITER_EL(root, child)
|
||||
{
|
||||
|
||||
int child_name = child.GetNodeName();
|
||||
|
||||
if(child_name == el_gain)
|
||||
{
|
||||
SetGain(CStr(child.GetText()).ToFloat());
|
||||
}
|
||||
|
||||
if(child_name == el_looping)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eLoop);
|
||||
}
|
||||
|
||||
if(child_name == el_omnipresent)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eOmnipresent);
|
||||
}
|
||||
|
||||
if(child_name == el_pitch)
|
||||
{
|
||||
this->m_Pitch = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_priority)
|
||||
{
|
||||
this->m_Priority = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_randorder)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eRandOrder);
|
||||
}
|
||||
|
||||
if(child_name == el_randgain)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eRandGain);
|
||||
}
|
||||
|
||||
if(child_name == el_gainupper)
|
||||
{
|
||||
this->m_GainUpper = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_gainlower)
|
||||
{
|
||||
this->m_GainLower = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_randpitch)
|
||||
{
|
||||
if(CStr(child.GetText()).ToInt() == 1)
|
||||
SetFlag(eRandPitch);
|
||||
}
|
||||
|
||||
if(child_name == el_pitchupper)
|
||||
{
|
||||
this->m_PitchUpper = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_pitchlower)
|
||||
{
|
||||
this->m_PitchLower = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_conegain)
|
||||
{
|
||||
this->m_ConeOuterGain = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_coneinner)
|
||||
{
|
||||
this->m_ConeInnerAngle = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_coneouter)
|
||||
{
|
||||
this->m_ConeOuterAngle = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_sound)
|
||||
{
|
||||
CStr szTemp(child.GetText());
|
||||
this->filenames.push_back(szTemp);
|
||||
|
||||
}
|
||||
if(child_name == el_path)
|
||||
{
|
||||
m_filepath = child.GetText();
|
||||
|
||||
}
|
||||
if(child_name == el_threshold)
|
||||
{
|
||||
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
|
||||
m_IntensityThreshold = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_decay)
|
||||
{
|
||||
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
|
||||
m_Decay = CStr(child.GetText()).ToFloat();
|
||||
}
|
||||
|
||||
if(child_name == el_replacement)
|
||||
{
|
||||
m_intensity_file = child.GetText();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reload();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -1,120 +1,120 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroup.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Loads up a group of sound files with shared properties,
|
||||
* and provides a simple interface for playing them.
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
/*
|
||||
Example usage: (SEE SOUNDGROUPMGR.H)
|
||||
|
||||
|
||||
Example SoundGroup.xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SoundGroup>
|
||||
<Gain>1.0</Gain>
|
||||
<Looping>0</Looping>
|
||||
<Pitch>1.0</Pitch>
|
||||
<Priority>100</Priority>
|
||||
<RandOrder>0</RandOrder>
|
||||
<RandGain>0</RandGain>
|
||||
<RandPitch>0</RandPitch>
|
||||
<ConeGain>1.0</ConeGain>
|
||||
<ConeInner>360</ConeInner>
|
||||
<ConeOuter>360</ConeOuter>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_Attackx.ogg</Sound>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_Chargex.ogg</Sound>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_Engagex.ogg</Sound>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_ForMyFamily.ogg</Sound>
|
||||
</SoundGroup>
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SOUNDGROUP
|
||||
#define INCLUDED_SOUNDGROUP
|
||||
|
||||
#include "lib/res/handle.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "lib/res/sound/snd_mgr.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
enum eSndGrpFlags
|
||||
{
|
||||
eRandOrder = 0x01,
|
||||
eRandGain = 0x02,
|
||||
eRandPitch = 0x04,
|
||||
eLoop = 0x08,
|
||||
eOmnipresent = 0x10
|
||||
};
|
||||
|
||||
|
||||
class CSoundGroup
|
||||
{
|
||||
public:
|
||||
CSoundGroup(const char *XMLfile);
|
||||
CSoundGroup(void);
|
||||
~CSoundGroup(void);
|
||||
|
||||
// Play next sound in group
|
||||
// @param position world position of the entity generating the sound
|
||||
// (ignored if the eOmnipresent flag is set)
|
||||
void PlayNext(const CVector3D& position);
|
||||
|
||||
// Load a group
|
||||
bool LoadSoundGroup(const char *XMLfile);
|
||||
|
||||
void Reload();
|
||||
|
||||
// Release all remaining loaded handles
|
||||
void ReleaseGroup();
|
||||
|
||||
// Update SoundGroup, remove dead sounds from intensity count
|
||||
void Update(float TimeSinceLastFrame);
|
||||
|
||||
// Set a flag using a value from eSndGrpFlags
|
||||
inline void SetFlag(int flag){ m_Flags |= flag; }
|
||||
|
||||
// Test flag, returns true if flag is set.
|
||||
inline bool TestFlag(int flag) { return (m_Flags & flag) != 0;}
|
||||
|
||||
private:
|
||||
void SetGain(float gain);
|
||||
void UploadPropertiesAndPlay(Handle hSound, const CVector3D& position);
|
||||
void SetDefaultValues();
|
||||
|
||||
size_t m_index; // index of the next sound to play
|
||||
|
||||
Handle m_hReplacement;
|
||||
|
||||
std::vector<Handle> snd_group; // we store the handles so we can load now and play later
|
||||
std::vector<CStr> filenames; // we need the filenames so we can reload when necessary.
|
||||
std::vector<float> playtimes; // it would be better to store this in with the Handles perhaps?
|
||||
CStr m_filepath; // the file path for the list of sound file resources
|
||||
CStr m_intensity_file; // the replacement aggregate 'intense' sound
|
||||
|
||||
float m_CurTime; // Time elapsed since soundgroup was created
|
||||
float m_TimeWindow; // The Intensity Threshold Window
|
||||
size_t m_IntensityThreshold; // the allowable intensity before a sound switch
|
||||
size_t m_Intensity; // our current intensity(number of sounds played since m_CurTime - m_TimeWindow)
|
||||
float m_Decay; //
|
||||
unsigned char m_Flags; // up to eight individual parameters, use with eSndGrpFlags.
|
||||
|
||||
float m_Gain;
|
||||
float m_Pitch;
|
||||
float m_Priority;
|
||||
float m_ConeOuterGain;
|
||||
float m_PitchUpper;
|
||||
float m_PitchLower;
|
||||
float m_GainUpper;
|
||||
float m_GainLower;
|
||||
float m_ConeInnerAngle;
|
||||
float m_ConeOuterAngle;
|
||||
};
|
||||
|
||||
#endif //#ifndef INCLUDED_SOUNDGROUP
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroup.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Loads up a group of sound files with shared properties,
|
||||
* and provides a simple interface for playing them.
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
/*
|
||||
Example usage: (SEE SOUNDGROUPMGR.H)
|
||||
|
||||
|
||||
Example SoundGroup.xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SoundGroup>
|
||||
<Gain>1.0</Gain>
|
||||
<Looping>0</Looping>
|
||||
<Pitch>1.0</Pitch>
|
||||
<Priority>100</Priority>
|
||||
<RandOrder>0</RandOrder>
|
||||
<RandGain>0</RandGain>
|
||||
<RandPitch>0</RandPitch>
|
||||
<ConeGain>1.0</ConeGain>
|
||||
<ConeInner>360</ConeInner>
|
||||
<ConeOuter>360</ConeOuter>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_Attackx.ogg</Sound>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_Chargex.ogg</Sound>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_Engagex.ogg</Sound>
|
||||
<Sound>audio/voice/hellenes/soldier/Attack_ForMyFamily.ogg</Sound>
|
||||
</SoundGroup>
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SOUNDGROUP
|
||||
#define INCLUDED_SOUNDGROUP
|
||||
|
||||
#include "lib/res/handle.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "lib/res/sound/snd_mgr.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
enum eSndGrpFlags
|
||||
{
|
||||
eRandOrder = 0x01,
|
||||
eRandGain = 0x02,
|
||||
eRandPitch = 0x04,
|
||||
eLoop = 0x08,
|
||||
eOmnipresent = 0x10
|
||||
};
|
||||
|
||||
|
||||
class CSoundGroup
|
||||
{
|
||||
public:
|
||||
CSoundGroup(const char *XMLfile);
|
||||
CSoundGroup(void);
|
||||
~CSoundGroup(void);
|
||||
|
||||
// Play next sound in group
|
||||
// @param position world position of the entity generating the sound
|
||||
// (ignored if the eOmnipresent flag is set)
|
||||
void PlayNext(const CVector3D& position);
|
||||
|
||||
// Load a group
|
||||
bool LoadSoundGroup(const char *XMLfile);
|
||||
|
||||
void Reload();
|
||||
|
||||
// Release all remaining loaded handles
|
||||
void ReleaseGroup();
|
||||
|
||||
// Update SoundGroup, remove dead sounds from intensity count
|
||||
void Update(float TimeSinceLastFrame);
|
||||
|
||||
// Set a flag using a value from eSndGrpFlags
|
||||
inline void SetFlag(int flag){ m_Flags |= flag; }
|
||||
|
||||
// Test flag, returns true if flag is set.
|
||||
inline bool TestFlag(int flag) { return (m_Flags & flag) != 0;}
|
||||
|
||||
private:
|
||||
void SetGain(float gain);
|
||||
void UploadPropertiesAndPlay(Handle hSound, const CVector3D& position);
|
||||
void SetDefaultValues();
|
||||
|
||||
size_t m_index; // index of the next sound to play
|
||||
|
||||
Handle m_hReplacement;
|
||||
|
||||
std::vector<Handle> snd_group; // we store the handles so we can load now and play later
|
||||
std::vector<CStr> filenames; // we need the filenames so we can reload when necessary.
|
||||
std::vector<float> playtimes; // it would be better to store this in with the Handles perhaps?
|
||||
CStr m_filepath; // the file path for the list of sound file resources
|
||||
CStr m_intensity_file; // the replacement aggregate 'intense' sound
|
||||
|
||||
float m_CurTime; // Time elapsed since soundgroup was created
|
||||
float m_TimeWindow; // The Intensity Threshold Window
|
||||
size_t m_IntensityThreshold; // the allowable intensity before a sound switch
|
||||
size_t m_Intensity; // our current intensity(number of sounds played since m_CurTime - m_TimeWindow)
|
||||
float m_Decay; //
|
||||
unsigned char m_Flags; // up to eight individual parameters, use with eSndGrpFlags.
|
||||
|
||||
float m_Gain;
|
||||
float m_Pitch;
|
||||
float m_Priority;
|
||||
float m_ConeOuterGain;
|
||||
float m_PitchUpper;
|
||||
float m_PitchLower;
|
||||
float m_GainUpper;
|
||||
float m_GainLower;
|
||||
float m_ConeInnerAngle;
|
||||
float m_ConeOuterAngle;
|
||||
};
|
||||
|
||||
#endif //#ifndef INCLUDED_SOUNDGROUP
|
||||
|
@ -1,146 +1,146 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroupMgr.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Manages and updates SoundGroups
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
// Example usage:
|
||||
|
||||
// size_t index;
|
||||
// CSoundGroupMgr *sgm = CSoundGroupMgr::GetInstance();
|
||||
// index = sgm->AddGroup("SoundGroup.xml");
|
||||
|
||||
// sgm->UpdateSoundGroups(TimeSinceLastFrame); // call in Frame()
|
||||
|
||||
// sgm->PlayNext(index); // wash-rinse-repeat
|
||||
|
||||
|
||||
// sgm->RemoveGroup(index); // Remove the group if you like
|
||||
|
||||
// sgm->DeleteInstance(); // Delete instance in shutdown
|
||||
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "SoundGroupMgr.h"
|
||||
|
||||
typedef std::vector<CSoundGroup*> SoundGroups;
|
||||
typedef SoundGroups::iterator SoundGroupIt;
|
||||
|
||||
|
||||
CSoundGroupMgr *CSoundGroupMgr::m_pInstance = 0;
|
||||
|
||||
CSoundGroupMgr::CSoundGroupMgr()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSoundGroupMgr *CSoundGroupMgr::GetInstance()
|
||||
{
|
||||
if(!m_pInstance)
|
||||
m_pInstance = new CSoundGroupMgr();
|
||||
|
||||
return m_pInstance;
|
||||
|
||||
}
|
||||
|
||||
void CSoundGroupMgr::DeleteInstance()
|
||||
{
|
||||
if(m_pInstance)
|
||||
{
|
||||
SoundGroupIt vIter = m_pInstance->m_Groups.begin();
|
||||
while(vIter != m_pInstance->m_Groups.end())
|
||||
vIter = m_pInstance->RemoveGroup(vIter);
|
||||
|
||||
delete m_pInstance;
|
||||
}
|
||||
m_pInstance = 0;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// AddGroup()
|
||||
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
|
||||
// out: size_t index into m_Groups
|
||||
// Loads the given XML file and returns an index for later use
|
||||
///////////////////////////////////////////
|
||||
size_t CSoundGroupMgr::AddGroup(const char *XMLFile)
|
||||
{
|
||||
CSoundGroup* newGroup = new CSoundGroup(XMLFile);
|
||||
m_Groups.push_back(newGroup);
|
||||
|
||||
return m_Groups.size() - 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: size_t index into m_Groups
|
||||
// out: SoundGroupIt - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
SoundGroupIt CSoundGroupMgr::RemoveGroup(size_t index)
|
||||
{
|
||||
SoundGroupIt vIter = m_Groups.begin();
|
||||
if(index >= m_Groups.size())
|
||||
return vIter;
|
||||
|
||||
CSoundGroup *temp = (*vIter);
|
||||
(*vIter)->ReleaseGroup();
|
||||
vIter = m_Groups.erase(vIter+index);
|
||||
|
||||
delete temp;
|
||||
|
||||
return vIter;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: SoundGroupIt - item to remove
|
||||
// out: SoundGroupIt - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
SoundGroupIt CSoundGroupMgr::RemoveGroup(SoundGroupIt iter)
|
||||
{
|
||||
|
||||
(*iter)->ReleaseGroup();
|
||||
|
||||
CSoundGroup *temp = (*iter);
|
||||
|
||||
iter = m_Groups.erase(iter);
|
||||
|
||||
delete temp;
|
||||
|
||||
return iter;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// UpdateSoundGroups()
|
||||
// updates all soundgroups, call in Frame()
|
||||
///////////////////////////////////////////
|
||||
void CSoundGroupMgr::UpdateSoundGroups(float TimeSinceLastFrame)
|
||||
{
|
||||
SoundGroupIt vIter = m_Groups.begin();
|
||||
while(vIter != m_Groups.end())
|
||||
{
|
||||
(*vIter)->Update(TimeSinceLastFrame);
|
||||
vIter++;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// PlayNext()
|
||||
// in: size_t index - index into m_Groups
|
||||
// Plays the next queued sound in an indexed group
|
||||
///////////////////////////////////////////
|
||||
void CSoundGroupMgr::PlayNext(size_t index, const CVector3D& position)
|
||||
{
|
||||
if(index < m_Groups.size())
|
||||
m_Groups[index]->PlayNext(position);
|
||||
else
|
||||
debug_printf("SND: PlayNext(%d) invalid, %d groups defined\n", index, m_Groups.size());
|
||||
}
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroupMgr.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Manages and updates SoundGroups
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
// Example usage:
|
||||
|
||||
// size_t index;
|
||||
// CSoundGroupMgr *sgm = CSoundGroupMgr::GetInstance();
|
||||
// index = sgm->AddGroup("SoundGroup.xml");
|
||||
|
||||
// sgm->UpdateSoundGroups(TimeSinceLastFrame); // call in Frame()
|
||||
|
||||
// sgm->PlayNext(index); // wash-rinse-repeat
|
||||
|
||||
|
||||
// sgm->RemoveGroup(index); // Remove the group if you like
|
||||
|
||||
// sgm->DeleteInstance(); // Delete instance in shutdown
|
||||
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "SoundGroupMgr.h"
|
||||
|
||||
typedef std::vector<CSoundGroup*> SoundGroups;
|
||||
typedef SoundGroups::iterator SoundGroupIt;
|
||||
|
||||
|
||||
CSoundGroupMgr *CSoundGroupMgr::m_pInstance = 0;
|
||||
|
||||
CSoundGroupMgr::CSoundGroupMgr()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSoundGroupMgr *CSoundGroupMgr::GetInstance()
|
||||
{
|
||||
if(!m_pInstance)
|
||||
m_pInstance = new CSoundGroupMgr();
|
||||
|
||||
return m_pInstance;
|
||||
|
||||
}
|
||||
|
||||
void CSoundGroupMgr::DeleteInstance()
|
||||
{
|
||||
if(m_pInstance)
|
||||
{
|
||||
SoundGroupIt vIter = m_pInstance->m_Groups.begin();
|
||||
while(vIter != m_pInstance->m_Groups.end())
|
||||
vIter = m_pInstance->RemoveGroup(vIter);
|
||||
|
||||
delete m_pInstance;
|
||||
}
|
||||
m_pInstance = 0;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// AddGroup()
|
||||
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
|
||||
// out: size_t index into m_Groups
|
||||
// Loads the given XML file and returns an index for later use
|
||||
///////////////////////////////////////////
|
||||
size_t CSoundGroupMgr::AddGroup(const char *XMLFile)
|
||||
{
|
||||
CSoundGroup* newGroup = new CSoundGroup(XMLFile);
|
||||
m_Groups.push_back(newGroup);
|
||||
|
||||
return m_Groups.size() - 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: size_t index into m_Groups
|
||||
// out: SoundGroupIt - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
SoundGroupIt CSoundGroupMgr::RemoveGroup(size_t index)
|
||||
{
|
||||
SoundGroupIt vIter = m_Groups.begin();
|
||||
if(index >= m_Groups.size())
|
||||
return vIter;
|
||||
|
||||
CSoundGroup *temp = (*vIter);
|
||||
(*vIter)->ReleaseGroup();
|
||||
vIter = m_Groups.erase(vIter+index);
|
||||
|
||||
delete temp;
|
||||
|
||||
return vIter;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: SoundGroupIt - item to remove
|
||||
// out: SoundGroupIt - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
SoundGroupIt CSoundGroupMgr::RemoveGroup(SoundGroupIt iter)
|
||||
{
|
||||
|
||||
(*iter)->ReleaseGroup();
|
||||
|
||||
CSoundGroup *temp = (*iter);
|
||||
|
||||
iter = m_Groups.erase(iter);
|
||||
|
||||
delete temp;
|
||||
|
||||
return iter;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// UpdateSoundGroups()
|
||||
// updates all soundgroups, call in Frame()
|
||||
///////////////////////////////////////////
|
||||
void CSoundGroupMgr::UpdateSoundGroups(float TimeSinceLastFrame)
|
||||
{
|
||||
SoundGroupIt vIter = m_Groups.begin();
|
||||
while(vIter != m_Groups.end())
|
||||
{
|
||||
(*vIter)->Update(TimeSinceLastFrame);
|
||||
vIter++;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// PlayNext()
|
||||
// in: size_t index - index into m_Groups
|
||||
// Plays the next queued sound in an indexed group
|
||||
///////////////////////////////////////////
|
||||
void CSoundGroupMgr::PlayNext(size_t index, const CVector3D& position)
|
||||
{
|
||||
if(index < m_Groups.size())
|
||||
m_Groups[index]->PlayNext(position);
|
||||
else
|
||||
debug_printf("SND: PlayNext(%d) invalid, %d groups defined\n", index, m_Groups.size());
|
||||
}
|
||||
|
@ -1,67 +1,67 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroupMgr.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Manages and updates SoundGroups
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
#include "SoundGroup.h"
|
||||
#include <vector>
|
||||
|
||||
class CSoundGroupMgr
|
||||
{
|
||||
public:
|
||||
std::vector <CSoundGroup *> m_Groups; // a collection of sound groups
|
||||
static CSoundGroupMgr *m_pInstance; // our static instance of the manager
|
||||
static CSoundGroupMgr *GetInstance();
|
||||
static void DeleteInstance();
|
||||
|
||||
///////////////////////////////////////////
|
||||
// UpdateSoundGroups()
|
||||
// updates all soundgroups, call in Frame()
|
||||
///////////////////////////////////////////
|
||||
void UpdateSoundGroups(float TimeSinceLastFrame);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// PlayNext()
|
||||
// in: size_t index - index into m_Groups
|
||||
// Plays the next queued sound in an indexed group
|
||||
///////////////////////////////////////////
|
||||
void PlayNext(size_t index, const CVector3D& position);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// AddGroup()
|
||||
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
|
||||
// out: size_t index into m_Groups
|
||||
// Loads the given XML file and returns an index for later use
|
||||
///////////////////////////////////////////
|
||||
size_t AddGroup(const char *XMLFile);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: size_t index into m_Groups
|
||||
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
std::vector<CSoundGroup *>::iterator RemoveGroup(size_t index);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: std::vector<CSoundGroup *>::iterator - item to remove
|
||||
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
std::vector<CSoundGroup *>::iterator RemoveGroup(std::vector<CSoundGroup *>::iterator iter);
|
||||
|
||||
|
||||
private:
|
||||
CSoundGroupMgr();
|
||||
CSoundGroupMgr(const CSoundGroupMgr &ref);
|
||||
CSoundGroupMgr &operator=(const CSoundGroupMgr &ref);
|
||||
|
||||
};
|
||||
|
||||
#define g_soundGroupMgr CSoundGroupMgr::GetInstance()
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroupMgr.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Manages and updates SoundGroups
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
// license: GPL; see sound/license.txt
|
||||
|
||||
#include "SoundGroup.h"
|
||||
#include <vector>
|
||||
|
||||
class CSoundGroupMgr
|
||||
{
|
||||
public:
|
||||
std::vector <CSoundGroup *> m_Groups; // a collection of sound groups
|
||||
static CSoundGroupMgr *m_pInstance; // our static instance of the manager
|
||||
static CSoundGroupMgr *GetInstance();
|
||||
static void DeleteInstance();
|
||||
|
||||
///////////////////////////////////////////
|
||||
// UpdateSoundGroups()
|
||||
// updates all soundgroups, call in Frame()
|
||||
///////////////////////////////////////////
|
||||
void UpdateSoundGroups(float TimeSinceLastFrame);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// PlayNext()
|
||||
// in: size_t index - index into m_Groups
|
||||
// Plays the next queued sound in an indexed group
|
||||
///////////////////////////////////////////
|
||||
void PlayNext(size_t index, const CVector3D& position);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// AddGroup()
|
||||
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
|
||||
// out: size_t index into m_Groups
|
||||
// Loads the given XML file and returns an index for later use
|
||||
///////////////////////////////////////////
|
||||
size_t AddGroup(const char *XMLFile);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: size_t index into m_Groups
|
||||
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
std::vector<CSoundGroup *>::iterator RemoveGroup(size_t index);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// RemoveGroup()
|
||||
// in: std::vector<CSoundGroup *>::iterator - item to remove
|
||||
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
|
||||
// Removes and Releases a given soundgroup
|
||||
///////////////////////////////////////////
|
||||
std::vector<CSoundGroup *>::iterator RemoveGroup(std::vector<CSoundGroup *>::iterator iter);
|
||||
|
||||
|
||||
private:
|
||||
CSoundGroupMgr();
|
||||
CSoundGroupMgr(const CSoundGroupMgr &ref);
|
||||
CSoundGroupMgr &operator=(const CSoundGroupMgr &ref);
|
||||
|
||||
};
|
||||
|
||||
#define g_soundGroupMgr CSoundGroupMgr::GetInstance()
|
||||
|
Loading…
Reference in New Issue
Block a user