forked from 0ad/0ad
Fix serialize/deserialize API asymmetry.
Add serialization support to more components. This was SVN commit r8122.
This commit is contained in:
parent
a29bb003f2
commit
8a98102195
@ -126,10 +126,10 @@ const u8* CSimulationMessage::Deserialize(const u8* pStart, const u8* pEnd)
|
||||
const u8* pos = CNetMessage::Deserialize(pStart, pEnd);
|
||||
std::istringstream stream(std::string(pos, pEnd));
|
||||
CStdDeserializer deserializer(m_ScriptInterface, stream);
|
||||
deserializer.NumberU32_Unbounded(m_Client);
|
||||
deserializer.NumberI32_Unbounded(m_Player);
|
||||
deserializer.NumberU32_Unbounded(m_Turn);
|
||||
deserializer.ScriptVal(m_Data);
|
||||
deserializer.NumberU32_Unbounded("client", m_Client);
|
||||
deserializer.NumberI32_Unbounded("player", m_Player);
|
||||
deserializer.NumberU32_Unbounded("turn", m_Turn);
|
||||
deserializer.ScriptVal("command", m_Data);
|
||||
return pEnd;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ const u8* CGameSetupMessage::Deserialize(const u8* pStart, const u8* pEnd)
|
||||
const u8* pos = CNetMessage::Deserialize(pStart, pEnd);
|
||||
std::istringstream stream(std::string(pos, pEnd));
|
||||
CStdDeserializer deserializer(m_ScriptInterface, stream);
|
||||
deserializer.ScriptVal(m_Data);
|
||||
deserializer.ScriptVal("command", m_Data);
|
||||
return pEnd;
|
||||
}
|
||||
|
||||
|
@ -264,6 +264,15 @@ void CNetLocalTurnManager::NotifyFinishedOwnCommands(u32 turn)
|
||||
|
||||
void CNetLocalTurnManager::NotifyFinishedUpdate(u32 UNUSED(turn))
|
||||
{
|
||||
#if 0 // this hurts performance and is only useful for verifying log replays
|
||||
std::string hash;
|
||||
{
|
||||
PROFILE("state hash check");
|
||||
bool ok = m_Simulation2.ComputeStateHash(hash);
|
||||
debug_assert(ok);
|
||||
}
|
||||
m_Replay.Hash(hash);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CNetLocalTurnManager::OnSimulationMessage(CSimulationMessage* UNUSED(msg))
|
||||
|
@ -63,13 +63,13 @@ public:
|
||||
JSContext* cx = context.GetScriptInterface().GetContext();
|
||||
|
||||
u32 numCmds;
|
||||
deserialize.NumberU32_Unbounded(numCmds);
|
||||
deserialize.NumberU32_Unbounded("num commands", numCmds);
|
||||
for (size_t i = 0; i < numCmds; ++i)
|
||||
{
|
||||
i32 player;
|
||||
jsval data;
|
||||
deserialize.NumberI32_Unbounded(player);
|
||||
deserialize.ScriptVal(data);
|
||||
deserialize.NumberI32_Unbounded("player", player);
|
||||
deserialize.ScriptVal("data", data);
|
||||
SimulationCommand c = { player, CScriptValRooted(cx, data) };
|
||||
m_LocalQueue.push_back(c);
|
||||
}
|
||||
|
@ -62,8 +62,8 @@ public:
|
||||
virtual void Deserialize(const CSimContext& context, const CParamNode& paramNode, IDeserializer& deserialize)
|
||||
{
|
||||
Init(context, paramNode);
|
||||
deserialize.NumberFloat_Unbounded(m_SpeedX);
|
||||
deserialize.NumberFloat_Unbounded(m_SpeedZ);
|
||||
deserialize.NumberFloat_Unbounded("speed x", m_SpeedX);
|
||||
deserialize.NumberFloat_Unbounded("speed z", m_SpeedZ);
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global))
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
|
||||
virtual void Deserialize(const CSimContext& UNUSED(context), const CParamNode& UNUSED(paramNode), IDeserializer& deserialize)
|
||||
{
|
||||
deserialize.NumberI32_Unbounded(m_Owner);
|
||||
deserialize.NumberI32_Unbounded("owner", m_Owner);
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg, bool UNUSED(global))
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "simulation2/MessageTypes.h"
|
||||
#include "simulation2/components/ICmpObstructionManager.h"
|
||||
#include "simulation2/components/ICmpWaterManager.h"
|
||||
#include "simulation2/serialization/SerializeTemplates.h"
|
||||
|
||||
// Default cost to move a single tile is a fairly arbitrary number, which should be big
|
||||
// enough to be precise when multiplied/divided and small enough to never overflow when
|
||||
@ -126,6 +127,55 @@ void CCmpPathfinder::Deinit(const CSimContext& UNUSED(context))
|
||||
delete m_ObstructionGrid;
|
||||
}
|
||||
|
||||
struct SerializeLongRequest
|
||||
{
|
||||
template<typename S>
|
||||
void operator()(S& serialize, const char* UNUSED(name), AsyncLongPathRequest& value)
|
||||
{
|
||||
serialize.NumberU32_Unbounded("ticket", value.ticket);
|
||||
serialize.NumberFixed_Unbounded("x0", value.x0);
|
||||
serialize.NumberFixed_Unbounded("z0", value.z0);
|
||||
SerializeGoal()(serialize, "goal", value.goal);
|
||||
serialize.NumberU8_Unbounded("pass class", value.passClass);
|
||||
serialize.NumberU8_Unbounded("cost class", value.costClass);
|
||||
serialize.NumberU32_Unbounded("notify", value.notify);
|
||||
}
|
||||
};
|
||||
|
||||
struct SerializeShortRequest
|
||||
{
|
||||
template<typename S>
|
||||
void operator()(S& serialize, const char* UNUSED(name), AsyncShortPathRequest& value)
|
||||
{
|
||||
serialize.NumberU32_Unbounded("ticket", value.ticket);
|
||||
serialize.NumberFixed_Unbounded("x0", value.x0);
|
||||
serialize.NumberFixed_Unbounded("z0", value.z0);
|
||||
serialize.NumberFixed_Unbounded("r", value.r);
|
||||
serialize.NumberFixed_Unbounded("range", value.range);
|
||||
SerializeGoal()(serialize, "goal", value.goal);
|
||||
serialize.NumberU8_Unbounded("pass class", value.passClass);
|
||||
serialize.Bool("avoid moving units", value.avoidMovingUnits);
|
||||
serialize.NumberU32_Unbounded("group", value.group);
|
||||
serialize.NumberU32_Unbounded("notify", value.notify);
|
||||
}
|
||||
};
|
||||
|
||||
void CCmpPathfinder::Serialize(ISerializer& serialize)
|
||||
{
|
||||
SerializeVector<SerializeLongRequest>()(serialize, "long requests", m_AsyncLongPathRequests);
|
||||
SerializeVector<SerializeShortRequest>()(serialize, "short requests", m_AsyncShortPathRequests);
|
||||
serialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket);
|
||||
}
|
||||
|
||||
void CCmpPathfinder::Deserialize(const CSimContext& context, const CParamNode& paramNode, IDeserializer& deserialize)
|
||||
{
|
||||
Init(context, paramNode);
|
||||
|
||||
SerializeVector<SerializeLongRequest>()(deserialize, "long requests", m_AsyncLongPathRequests);
|
||||
SerializeVector<SerializeShortRequest>()(deserialize, "short requests", m_AsyncShortPathRequests);
|
||||
deserialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket);
|
||||
}
|
||||
|
||||
void CCmpPathfinder::HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
|
@ -167,12 +167,12 @@ public:
|
||||
|
||||
std::vector<AsyncLongPathRequest> m_AsyncLongPathRequests;
|
||||
std::vector<AsyncShortPathRequest> m_AsyncShortPathRequests;
|
||||
u32 m_NextAsyncTicket; // unique IDs for asynchronous path requests
|
||||
|
||||
u16 m_MapSize; // tiles per side
|
||||
Grid<TerrainTile>* m_Grid; // terrain/passability information
|
||||
Grid<u8>* m_ObstructionGrid; // cached obstruction information (TODO: we shouldn't bother storing this, it's redundant with LSBs of m_Grid)
|
||||
bool m_TerrainDirty; // indicates if m_Grid has been updated since terrain changed
|
||||
u32 m_NextAsyncTicket; // unique IDs for asynchronous path requests
|
||||
|
||||
// Debugging - output from last pathfind operation:
|
||||
Grid<PathfindTile>* m_DebugGrid;
|
||||
@ -188,25 +188,15 @@ public:
|
||||
return "<a:component type='system'/><empty/>";
|
||||
}
|
||||
|
||||
virtual void Init(const CSimContext& UNUSED(context), const CParamNode& paramNode);
|
||||
virtual void Init(const CSimContext& context, const CParamNode& paramNode);
|
||||
|
||||
virtual void Deinit(const CSimContext& UNUSED(context));
|
||||
virtual void Deinit(const CSimContext& context);
|
||||
|
||||
virtual void Serialize(ISerializer& UNUSED(serialize))
|
||||
{
|
||||
// TODO: do something here
|
||||
// (Do we need to serialise the pathfinder state, or is it fine to regenerate it from
|
||||
// the original entities after deserialisation?)
|
||||
}
|
||||
virtual void Serialize(ISerializer& serialize);
|
||||
|
||||
virtual void Deserialize(const CSimContext& context, const CParamNode& paramNode, IDeserializer& UNUSED(deserialize))
|
||||
{
|
||||
Init(context, paramNode);
|
||||
virtual void Deserialize(const CSimContext& context, const CParamNode& paramNode, IDeserializer& deserialize);
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global));
|
||||
virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool global);
|
||||
|
||||
virtual u8 GetPassabilityClass(const std::string& name);
|
||||
|
||||
|
@ -156,18 +156,18 @@ public:
|
||||
{
|
||||
Init(context, paramNode);
|
||||
|
||||
deserialize.Bool(m_InWorld);
|
||||
deserialize.Bool("in world", m_InWorld);
|
||||
if (m_InWorld)
|
||||
{
|
||||
deserialize.NumberFixed_Unbounded(m_X);
|
||||
deserialize.NumberFixed_Unbounded(m_Z);
|
||||
deserialize.NumberFixed_Unbounded(m_LastX);
|
||||
deserialize.NumberFixed_Unbounded(m_LastZ);
|
||||
deserialize.NumberFixed_Unbounded("x", m_X);
|
||||
deserialize.NumberFixed_Unbounded("z", m_Z);
|
||||
deserialize.NumberFixed_Unbounded("last x", m_LastX);
|
||||
deserialize.NumberFixed_Unbounded("last z", m_LastZ);
|
||||
}
|
||||
deserialize.NumberFixed_Unbounded(m_RotX);
|
||||
deserialize.NumberFixed_Unbounded(m_RotY);
|
||||
deserialize.NumberFixed_Unbounded(m_RotZ);
|
||||
deserialize.NumberFixed_Unbounded(m_YOffset);
|
||||
deserialize.NumberFixed_Unbounded("rot x", m_RotX);
|
||||
deserialize.NumberFixed_Unbounded("rot y", m_RotY);
|
||||
deserialize.NumberFixed_Unbounded("rot z", m_RotZ);
|
||||
deserialize.NumberFixed_Unbounded("altitude", m_YOffset);
|
||||
// TODO: should there be range checks on all these values?
|
||||
|
||||
m_InterpolatedRotY = m_RotY.ToFloat();
|
||||
|
@ -89,13 +89,13 @@ public:
|
||||
Init(context, paramNode);
|
||||
|
||||
u32 numEntities;
|
||||
deserialize.NumberU32_Unbounded(numEntities);
|
||||
deserialize.NumberU32_Unbounded("num entities", numEntities);
|
||||
for (u32 i = 0; i < numEntities; ++i)
|
||||
{
|
||||
entity_id_t ent;
|
||||
std::string templateName;
|
||||
deserialize.NumberU32_Unbounded(ent);
|
||||
deserialize.StringASCII(templateName, 0, 256);
|
||||
deserialize.NumberU32_Unbounded("id", ent);
|
||||
deserialize.StringASCII("template", templateName, 0, 256);
|
||||
m_LatestTemplates[ent] = templateName;
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
|
||||
virtual void Deserialize(const CSimContext& UNUSED(context), const CParamNode& UNUSED(paramNode), IDeserializer& deserialize)
|
||||
{
|
||||
deserialize.NumberI32_Unbounded(m_x);
|
||||
deserialize.NumberI32_Unbounded("x", m_x);
|
||||
}
|
||||
|
||||
virtual int GetX()
|
||||
@ -121,7 +121,7 @@ public:
|
||||
|
||||
virtual void Deserialize(const CSimContext& UNUSED(context), const CParamNode& UNUSED(paramNode), IDeserializer& deserialize)
|
||||
{
|
||||
deserialize.NumberI32_Unbounded(m_x);
|
||||
deserialize.NumberI32_Unbounded("x", m_x);
|
||||
}
|
||||
|
||||
virtual int GetX()
|
||||
@ -182,7 +182,7 @@ public:
|
||||
|
||||
virtual void Deserialize(const CSimContext& UNUSED(context), const CParamNode& UNUSED(paramNode), IDeserializer& deserialize)
|
||||
{
|
||||
deserialize.NumberI32_Unbounded(m_x);
|
||||
deserialize.NumberI32_Unbounded("x", m_x);
|
||||
}
|
||||
|
||||
virtual int GetX()
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "simulation2/MessageTypes.h"
|
||||
#include "simulation2/helpers/Geometry.h"
|
||||
#include "simulation2/helpers/Render.h"
|
||||
#include "simulation2/serialization/SerializeTemplates.h"
|
||||
|
||||
#include "graphics/Overlay.h"
|
||||
#include "graphics/Terrain.h"
|
||||
@ -74,7 +75,7 @@ public:
|
||||
|
||||
entity_pos_t m_Radius;
|
||||
|
||||
enum
|
||||
enum State
|
||||
{
|
||||
STATE_IDLE, // not moving at all
|
||||
STATE_STOPPING, // will go IDLE next turn (this delay fixes animation timings)
|
||||
@ -86,7 +87,8 @@ public:
|
||||
// Entities that represent individual units or formation controllers:
|
||||
// ('target' is m_FinalGoal)
|
||||
STATE_INDIVIDUAL_PATH_COMPUTING, // waiting for a path to target
|
||||
STATE_INDIVIDUAL_PATH_FOLLOWING // following the computed path to target
|
||||
STATE_INDIVIDUAL_PATH_FOLLOWING, // following the computed path to target
|
||||
STATE_MAX
|
||||
};
|
||||
int m_State;
|
||||
|
||||
@ -97,7 +99,6 @@ public:
|
||||
|
||||
fixed m_Speed;
|
||||
|
||||
// These values contain undefined junk if !HasTarget:
|
||||
ICmpPathfinder::Path m_LongPath;
|
||||
ICmpPathfinder::Path m_ShortPath;
|
||||
entity_pos_t m_ShortTargetX, m_ShortTargetZ;
|
||||
@ -157,10 +158,6 @@ public:
|
||||
m_RunSpeed = m_WalkSpeed;
|
||||
}
|
||||
|
||||
CmpPtr<ICmpObstruction> cmpObstruction(context, GetEntityId());
|
||||
if (!cmpObstruction.null())
|
||||
m_Radius = cmpObstruction->GetUnitRadius();
|
||||
|
||||
CmpPtr<ICmpPathfinder> cmpPathfinder(context, SYSTEM_ENTITY);
|
||||
if (!cmpPathfinder.null())
|
||||
{
|
||||
@ -168,10 +165,18 @@ public:
|
||||
m_CostClass = cmpPathfinder->GetCostClass(paramNode.GetChild("CostClass").ToASCIIString());
|
||||
}
|
||||
|
||||
CmpPtr<ICmpObstruction> cmpObstruction(context, GetEntityId());
|
||||
if (!cmpObstruction.null())
|
||||
m_Radius = cmpObstruction->GetUnitRadius();
|
||||
|
||||
m_State = STATE_IDLE;
|
||||
|
||||
m_ExpectedPathTicket = 0;
|
||||
|
||||
m_TargetEntity = 0;
|
||||
|
||||
m_FinalGoal.type = ICmpPathfinder::Goal::POINT;
|
||||
|
||||
m_DebugOverlayEnabled = false;
|
||||
}
|
||||
|
||||
@ -181,24 +186,46 @@ public:
|
||||
|
||||
virtual void Serialize(ISerializer& serialize)
|
||||
{
|
||||
// serialize.Bool("has target", m_HasTarget);
|
||||
// if (m_HasTarget)
|
||||
{
|
||||
// TODO: m_Path
|
||||
// TODO: m_FinalTargetAngle
|
||||
}
|
||||
serialize.NumberFixed_Unbounded("radius", m_Radius);
|
||||
|
||||
// TODO: m_State
|
||||
serialize.NumberU8("state", m_State, 0, STATE_MAX-1);
|
||||
|
||||
serialize.NumberU32_Unbounded("ticket", m_ExpectedPathTicket);
|
||||
|
||||
serialize.NumberU32_Unbounded("target entity", m_TargetEntity);
|
||||
serialize.NumberFixed_Unbounded("target offset x", m_TargetOffsetX);
|
||||
serialize.NumberFixed_Unbounded("target offset z", m_TargetOffsetZ);
|
||||
serialize.NumberFixed_Unbounded("speed", m_Speed);
|
||||
|
||||
SerializeVector<SerializeWaypoint>()(serialize, "long path", m_LongPath.m_Waypoints);
|
||||
SerializeVector<SerializeWaypoint>()(serialize, "short path", m_ShortPath.m_Waypoints);
|
||||
serialize.NumberFixed_Unbounded("short target x", m_ShortTargetX);
|
||||
serialize.NumberFixed_Unbounded("short target z", m_ShortTargetZ);
|
||||
SerializeGoal()(serialize, "goal", m_FinalGoal);
|
||||
}
|
||||
|
||||
virtual void Deserialize(const CSimContext& context, const CParamNode& paramNode, IDeserializer& deserialize)
|
||||
{
|
||||
Init(context, paramNode);
|
||||
|
||||
// deserialize.Bool(m_HasTarget);
|
||||
// if (m_HasTarget)
|
||||
{
|
||||
}
|
||||
deserialize.NumberFixed_Unbounded("radius", m_Radius);
|
||||
|
||||
u8 state;
|
||||
deserialize.NumberU8("state", state, 0, STATE_MAX-1);
|
||||
m_State = (State)state;
|
||||
|
||||
deserialize.NumberU32_Unbounded("ticket", m_ExpectedPathTicket);
|
||||
|
||||
deserialize.NumberU32_Unbounded("target entity", m_TargetEntity);
|
||||
deserialize.NumberFixed_Unbounded("target offset x", m_TargetOffsetX);
|
||||
deserialize.NumberFixed_Unbounded("target offset z", m_TargetOffsetZ);
|
||||
deserialize.NumberFixed_Unbounded("speed", m_Speed);
|
||||
|
||||
SerializeVector<SerializeWaypoint>()(deserialize, "long path", m_LongPath.m_Waypoints);
|
||||
SerializeVector<SerializeWaypoint>()(deserialize, "short path", m_ShortPath.m_Waypoints);
|
||||
deserialize.NumberFixed_Unbounded("short target x", m_ShortTargetX);
|
||||
deserialize.NumberFixed_Unbounded("short target z", m_ShortTargetZ);
|
||||
SerializeGoal()(deserialize, "goal", m_FinalGoal);
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg, bool UNUSED(global))
|
||||
|
@ -46,7 +46,7 @@ class ICmpPathfinder : public IComponent
|
||||
public:
|
||||
struct Goal
|
||||
{
|
||||
enum {
|
||||
enum Type {
|
||||
POINT,
|
||||
CIRCLE,
|
||||
SQUARE
|
||||
|
@ -82,7 +82,7 @@ void CComponentTypeScript::Deserialize(const CSimContext& UNUSED(context), const
|
||||
|
||||
// Use ScriptObjectAppend so we don't lose the carefully-constructed
|
||||
// prototype/parent of this object
|
||||
deserialize.ScriptObjectAppend(m_Instance);
|
||||
deserialize.ScriptObjectAppend("object", m_Instance);
|
||||
|
||||
m_ScriptInterface.SetProperty(m_Instance, "entity", (int)ent, true);
|
||||
m_ScriptInterface.SetProperty(m_Instance, "template", paramNode, true);
|
||||
|
@ -39,68 +39,68 @@ T IDeserializer::Number_(T lower, T upper)
|
||||
return value;
|
||||
}
|
||||
|
||||
void IDeserializer::NumberU8(uint8_t& out, uint8_t lower, uint8_t upper)
|
||||
void IDeserializer::NumberU8(const char* UNUSED(name), uint8_t& out, uint8_t lower, uint8_t upper)
|
||||
{
|
||||
out = Number_(lower, upper);
|
||||
}
|
||||
|
||||
void IDeserializer::NumberI32(int32_t& out, int32_t lower, int32_t upper)
|
||||
void IDeserializer::NumberI32(const char* UNUSED(name), int32_t& out, int32_t lower, int32_t upper)
|
||||
{
|
||||
out = (i32)to_le32((u32)Number_(lower, upper));
|
||||
}
|
||||
|
||||
void IDeserializer::NumberU32(uint32_t& out, uint32_t lower, uint32_t upper)
|
||||
void IDeserializer::NumberU32(const char* UNUSED(name), uint32_t& out, uint32_t lower, uint32_t upper)
|
||||
{
|
||||
out = to_le32(Number_(lower, upper));
|
||||
}
|
||||
|
||||
void IDeserializer::NumberU8_Unbounded(uint8_t& out)
|
||||
void IDeserializer::NumberU8_Unbounded(const char* UNUSED(name), uint8_t& out)
|
||||
{
|
||||
Get((u8*)&out, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void IDeserializer::NumberI32_Unbounded(int32_t& out)
|
||||
void IDeserializer::NumberI32_Unbounded(const char* UNUSED(name), int32_t& out)
|
||||
{
|
||||
int32_t value;
|
||||
Get((u8*)&value, sizeof(int32_t));
|
||||
out = (i32)to_le32((u32)value);
|
||||
}
|
||||
|
||||
void IDeserializer::NumberU32_Unbounded(uint32_t& out)
|
||||
void IDeserializer::NumberU32_Unbounded(const char* UNUSED(name), uint32_t& out)
|
||||
{
|
||||
uint32_t value;
|
||||
Get((u8*)&value, sizeof(uint32_t));
|
||||
out = to_le32(value);
|
||||
}
|
||||
|
||||
void IDeserializer::NumberFloat_Unbounded(float& out)
|
||||
void IDeserializer::NumberFloat_Unbounded(const char* UNUSED(name), float& out)
|
||||
{
|
||||
Get((u8*)&out, sizeof(float));
|
||||
}
|
||||
|
||||
void IDeserializer::NumberDouble_Unbounded(double& out)
|
||||
void IDeserializer::NumberDouble_Unbounded(const char* UNUSED(name), double& out)
|
||||
{
|
||||
Get((u8*)&out, sizeof(double));
|
||||
}
|
||||
|
||||
void IDeserializer::NumberFixed_Unbounded(fixed& out)
|
||||
void IDeserializer::NumberFixed_Unbounded(const char* name, fixed& out)
|
||||
{
|
||||
int32_t n;
|
||||
NumberI32_Unbounded(n);
|
||||
NumberI32_Unbounded(name, n);
|
||||
out.SetInternalValue(n);
|
||||
}
|
||||
|
||||
void IDeserializer::Bool(bool& out)
|
||||
void IDeserializer::Bool(const char* name, bool& out)
|
||||
{
|
||||
uint8_t i;
|
||||
NumberU8(i, 0, 1);
|
||||
NumberU8(name, i, 0, 1);
|
||||
out = (i != 0);
|
||||
}
|
||||
|
||||
void IDeserializer::StringASCII(std::string& out, uint32_t minlength, uint32_t maxlength)
|
||||
void IDeserializer::StringASCII(const char* UNUSED(name), std::string& out, uint32_t minlength, uint32_t maxlength)
|
||||
{
|
||||
uint32_t len;
|
||||
NumberU32(len, minlength, maxlength);
|
||||
NumberU32("string length", len, minlength, maxlength);
|
||||
out.resize(len); // TODO: should check len <= bytes remaining in stream
|
||||
Get((u8*)out.data(), len);
|
||||
|
||||
@ -109,11 +109,11 @@ void IDeserializer::StringASCII(std::string& out, uint32_t minlength, uint32_t m
|
||||
throw PSERROR_Deserialize_InvalidCharInString();
|
||||
}
|
||||
|
||||
void IDeserializer::String(std::wstring& out, uint32_t minlength, uint32_t maxlength)
|
||||
void IDeserializer::String(const char* UNUSED(name), std::wstring& out, uint32_t minlength, uint32_t maxlength)
|
||||
{
|
||||
std::string str;
|
||||
uint32_t len;
|
||||
NumberU32_Unbounded(len);
|
||||
NumberU32_Unbounded("string length", len);
|
||||
str.resize(len); // TODO: should check len <= bytes remaining in stream
|
||||
Get((u8*)str.data(), len);
|
||||
|
||||
@ -126,7 +126,7 @@ void IDeserializer::String(std::wstring& out, uint32_t minlength, uint32_t maxle
|
||||
throw PSERROR_Deserialize_OutOfBounds();
|
||||
}
|
||||
|
||||
void IDeserializer::RawBytes(u8* data, size_t len)
|
||||
void IDeserializer::RawBytes(const char* UNUSED(name), u8* data, size_t len)
|
||||
{
|
||||
Get(data, len);
|
||||
}
|
||||
@ -140,7 +140,7 @@ int IDeserializer::GetVersion() const
|
||||
void IDeserializer::ReadString(std::string& out)
|
||||
{
|
||||
uint32_t len;
|
||||
NumberU32_Unbounded(len);
|
||||
NumberU32_Unbounded("string length", len);
|
||||
out.resize(len); // TODO: should check len <= bytes remaining in stream
|
||||
Get((u8*)out.data(), len);
|
||||
}
|
||||
|
@ -36,29 +36,31 @@ class IDeserializer
|
||||
public:
|
||||
virtual ~IDeserializer();
|
||||
|
||||
virtual void NumberU8(uint8_t& out, uint8_t lower, uint8_t upper);
|
||||
virtual void NumberI32(int32_t& out, int32_t lower, int32_t upper);
|
||||
virtual void NumberU32(uint32_t& out, uint32_t lower, uint32_t upper);
|
||||
virtual void NumberU8_Unbounded(uint8_t& out);
|
||||
virtual void NumberI32_Unbounded(int32_t& out);
|
||||
virtual void NumberU32_Unbounded(uint32_t& out);
|
||||
virtual void NumberFloat_Unbounded(float& out);
|
||||
virtual void NumberDouble_Unbounded(double& out);
|
||||
virtual void NumberFixed_Unbounded(fixed& out);
|
||||
virtual void Bool(bool& out);
|
||||
virtual void StringASCII(std::string& out, uint32_t minlength, uint32_t maxlength);
|
||||
virtual void String(std::wstring& out, uint32_t minlength, uint32_t maxlength);
|
||||
virtual void NumberU8(const char* name, uint8_t& out, uint8_t lower, uint8_t upper);
|
||||
virtual void NumberI32(const char* name, int32_t& out, int32_t lower, int32_t upper);
|
||||
virtual void NumberU32(const char* name, uint32_t& out, uint32_t lower, uint32_t upper);
|
||||
virtual void NumberU8_Unbounded(const char* name, uint8_t& out);
|
||||
virtual void NumberI32_Unbounded(const char* name, int32_t& out);
|
||||
virtual void NumberU32_Unbounded(const char* name, uint32_t& out);
|
||||
virtual void NumberFloat_Unbounded(const char* name, float& out);
|
||||
virtual void NumberDouble_Unbounded(const char* name, double& out);
|
||||
virtual void NumberFixed_Unbounded(const char* name, fixed& out);
|
||||
virtual void Bool(const char* name, bool& out);
|
||||
virtual void StringASCII(const char* name, std::string& out, uint32_t minlength, uint32_t maxlength);
|
||||
virtual void String(const char* name, std::wstring& out, uint32_t minlength, uint32_t maxlength);
|
||||
|
||||
/// Deserialize a jsval, replacing 'out'
|
||||
virtual void ScriptVal(jsval& out) = 0;
|
||||
virtual void ScriptVal(const char* name, jsval& out) = 0;
|
||||
virtual void ScriptVal(const char* name, CScriptVal& out) = 0;
|
||||
virtual void ScriptVal(const char* name, CScriptValRooted& out) = 0;
|
||||
|
||||
/// Deserialize an object jsval, appending properties to object 'obj'
|
||||
virtual void ScriptObjectAppend(jsval& obj) = 0;
|
||||
virtual void ScriptObjectAppend(const char* name, jsval& obj) = 0;
|
||||
|
||||
/// Deserialize a JSString
|
||||
virtual void ScriptString(JSString*& out) = 0;
|
||||
virtual void ScriptString(const char* name, JSString*& out) = 0;
|
||||
|
||||
virtual void RawBytes(u8* data, size_t len);
|
||||
virtual void RawBytes(const char* name, u8* data, size_t len);
|
||||
|
||||
// Features for simulation-state serialisation:
|
||||
virtual int GetVersion() const;
|
||||
|
96
source/simulation2/serialization/SerializeTemplates.h
Normal file
96
source/simulation2/serialization/SerializeTemplates.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper templates for serializing/deserializing common objects.
|
||||
*/
|
||||
|
||||
template<typename ELEM>
|
||||
struct SerializeVector
|
||||
{
|
||||
template<typename T>
|
||||
void operator()(ISerializer& serialize, const char* name, std::vector<T>& value)
|
||||
{
|
||||
size_t len = value.size();
|
||||
serialize.NumberU32_Unbounded("length", (u32)len);
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
ELEM()(serialize, name, value[i]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void operator()(IDeserializer& deserialize, const char* name, std::vector<T>& value)
|
||||
{
|
||||
u32 len;
|
||||
deserialize.NumberU32_Unbounded("length", len);
|
||||
value.reserve(len); // TODO: watch out for out-of-memory
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
T el;
|
||||
ELEM()(deserialize, name, el);
|
||||
value.push_back(el);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct SerializeWaypoint
|
||||
{
|
||||
void operator()(ISerializer& serialize, const char* UNUSED(name), const ICmpPathfinder::Waypoint& value)
|
||||
{
|
||||
serialize.NumberFixed_Unbounded("waypoint x", value.x);
|
||||
serialize.NumberFixed_Unbounded("waypoint z", value.z);
|
||||
}
|
||||
|
||||
void operator()(IDeserializer& deserialize, const char* UNUSED(name), ICmpPathfinder::Waypoint& value)
|
||||
{
|
||||
deserialize.NumberFixed_Unbounded("waypoint x", value.x);
|
||||
deserialize.NumberFixed_Unbounded("waypoint z", value.z);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, T max>
|
||||
struct SerializeU8_Enum
|
||||
{
|
||||
void operator()(ISerializer& serialize, const char* name, T value)
|
||||
{
|
||||
serialize.NumberU8(name, value, 0, max);
|
||||
}
|
||||
|
||||
void operator()(IDeserializer& deserialize, const char* name, T& value)
|
||||
{
|
||||
u8 val;
|
||||
deserialize.NumberU8(name, val, 0, max);
|
||||
value = (T)val;
|
||||
}
|
||||
};
|
||||
|
||||
struct SerializeGoal
|
||||
{
|
||||
template<typename S>
|
||||
void operator()(S& serialize, const char* UNUSED(name), ICmpPathfinder::Goal& value)
|
||||
{
|
||||
SerializeU8_Enum<ICmpPathfinder::Goal::Type, ICmpPathfinder::Goal::SQUARE>()(serialize, "type", value.type);
|
||||
serialize.NumberFixed_Unbounded("goal x", value.x);
|
||||
serialize.NumberFixed_Unbounded("goal z", value.z);
|
||||
serialize.NumberFixed_Unbounded("goal u x", value.u.X);
|
||||
serialize.NumberFixed_Unbounded("goal u z", value.u.Y);
|
||||
serialize.NumberFixed_Unbounded("goal v x", value.v.X);
|
||||
serialize.NumberFixed_Unbounded("goal v z", value.v.Y);
|
||||
serialize.NumberFixed_Unbounded("goal hw", value.hw);
|
||||
serialize.NumberFixed_Unbounded("goal hh", value.hh);
|
||||
}
|
||||
};
|
@ -76,7 +76,7 @@ jsval CStdDeserializer::ReadScriptVal(JSObject* appendParent)
|
||||
JSContext* cx = m_ScriptInterface.GetContext();
|
||||
|
||||
uint8_t type;
|
||||
NumberU8_Unbounded(type);
|
||||
NumberU8_Unbounded("type", type);
|
||||
switch (type)
|
||||
{
|
||||
case SCRIPT_TYPE_VOID:
|
||||
@ -103,7 +103,7 @@ jsval CStdDeserializer::ReadScriptVal(JSObject* appendParent)
|
||||
AddScriptBackref(obj);
|
||||
|
||||
uint32_t numProps;
|
||||
NumberU32_Unbounded(numProps);
|
||||
NumberU32_Unbounded("num props", numProps);
|
||||
|
||||
for (uint32_t i = 0; i < numProps; ++i)
|
||||
{
|
||||
@ -122,19 +122,19 @@ jsval CStdDeserializer::ReadScriptVal(JSObject* appendParent)
|
||||
case SCRIPT_TYPE_STRING:
|
||||
{
|
||||
JSString* str;
|
||||
ScriptString(str);
|
||||
ScriptString("string", str);
|
||||
return STRING_TO_JSVAL(str);
|
||||
}
|
||||
case SCRIPT_TYPE_INT:
|
||||
{
|
||||
int32_t value;
|
||||
NumberI32(value, JSVAL_INT_MIN, JSVAL_INT_MAX);
|
||||
NumberI32("value", value, JSVAL_INT_MIN, JSVAL_INT_MAX);
|
||||
return INT_TO_JSVAL(value);
|
||||
}
|
||||
case SCRIPT_TYPE_DOUBLE:
|
||||
{
|
||||
double value;
|
||||
NumberDouble_Unbounded(value);
|
||||
NumberDouble_Unbounded("value", value);
|
||||
jsval rval;
|
||||
if (!JS_NewNumberValue(cx, value, &rval))
|
||||
throw PSERROR_Deserialize_ScriptError("JS_NewNumberValue failed");
|
||||
@ -143,13 +143,13 @@ jsval CStdDeserializer::ReadScriptVal(JSObject* appendParent)
|
||||
case SCRIPT_TYPE_BOOLEAN:
|
||||
{
|
||||
uint8_t value;
|
||||
NumberU8(value, 0, 1);
|
||||
NumberU8("value", value, 0, 1);
|
||||
return BOOLEAN_TO_JSVAL(value ? JS_TRUE : JS_FALSE);
|
||||
}
|
||||
case SCRIPT_TYPE_BACKREF:
|
||||
{
|
||||
u32 tag;
|
||||
NumberU32_Unbounded(tag);
|
||||
NumberU32_Unbounded("tag", tag);
|
||||
JSObject* obj = GetScriptBackref(tag);
|
||||
if (!obj)
|
||||
throw PSERROR_Deserialize_ScriptError("Invalid backref tag");
|
||||
@ -163,12 +163,12 @@ jsval CStdDeserializer::ReadScriptVal(JSObject* appendParent)
|
||||
void CStdDeserializer::ReadStringUTF16(utf16string& str)
|
||||
{
|
||||
uint32_t len;
|
||||
NumberU32_Unbounded(len);
|
||||
NumberU32_Unbounded("string length", len);
|
||||
str.resize(len); // TODO: should check len*2 <= bytes remaining in stream, before resizing
|
||||
Get((u8*)str.data(), len*2);
|
||||
}
|
||||
|
||||
void CStdDeserializer::ScriptString(JSString*& out)
|
||||
void CStdDeserializer::ScriptString(const char* UNUSED(name), JSString*& out)
|
||||
{
|
||||
utf16string str;
|
||||
ReadStringUTF16(str);
|
||||
@ -182,22 +182,22 @@ void CStdDeserializer::ScriptString(JSString*& out)
|
||||
throw PSERROR_Deserialize_ScriptError("JS_NewUCStringCopyN failed");
|
||||
}
|
||||
|
||||
void CStdDeserializer::ScriptVal(jsval& out)
|
||||
void CStdDeserializer::ScriptVal(const char* UNUSED(name), jsval& out)
|
||||
{
|
||||
out = ReadScriptVal(NULL);
|
||||
}
|
||||
|
||||
void CStdDeserializer::ScriptVal(CScriptVal& out)
|
||||
void CStdDeserializer::ScriptVal(const char* UNUSED(name), CScriptVal& out)
|
||||
{
|
||||
out = ReadScriptVal(NULL);
|
||||
}
|
||||
|
||||
void CStdDeserializer::ScriptVal(CScriptValRooted& out)
|
||||
void CStdDeserializer::ScriptVal(const char* UNUSED(name), CScriptValRooted& out)
|
||||
{
|
||||
out = CScriptValRooted(m_ScriptInterface.GetContext(), ReadScriptVal(NULL));
|
||||
}
|
||||
|
||||
void CStdDeserializer::ScriptObjectAppend(jsval& obj)
|
||||
void CStdDeserializer::ScriptObjectAppend(const char* UNUSED(name), jsval& obj)
|
||||
{
|
||||
if (!JSVAL_IS_OBJECT(obj))
|
||||
throw PSERROR_Deserialize_ScriptError();
|
||||
|
@ -31,11 +31,11 @@ public:
|
||||
CStdDeserializer(ScriptInterface& scriptInterface, std::istream& stream);
|
||||
virtual ~CStdDeserializer();
|
||||
|
||||
virtual void ScriptVal(jsval& out);
|
||||
virtual void ScriptVal(CScriptVal& out);
|
||||
virtual void ScriptVal(CScriptValRooted& out);
|
||||
virtual void ScriptObjectAppend(jsval& obj);
|
||||
virtual void ScriptString(JSString*& out);
|
||||
virtual void ScriptVal(const char* name, jsval& out);
|
||||
virtual void ScriptVal(const char* name, CScriptVal& out);
|
||||
virtual void ScriptVal(const char* name, CScriptValRooted& out);
|
||||
virtual void ScriptObjectAppend(const char* name, jsval& obj);
|
||||
virtual void ScriptString(const char* name, JSString*& out);
|
||||
|
||||
protected:
|
||||
virtual void Get(u8* data, size_t len);
|
||||
|
@ -236,13 +236,13 @@ bool CComponentManager::DeserializeState(std::istream& stream)
|
||||
ResetState();
|
||||
|
||||
std::string rng;
|
||||
deserializer.StringASCII(rng, 0, 32);
|
||||
deserializer.StringASCII("rng", rng, 0, 32);
|
||||
DeserializeRNG(rng, m_RNG);
|
||||
|
||||
deserializer.NumberU32_Unbounded(m_NextEntityId); // TODO: use sensible bounds
|
||||
deserializer.NumberU32_Unbounded("next entity id", m_NextEntityId); // TODO: use sensible bounds
|
||||
|
||||
uint32_t numComponentTypes;
|
||||
deserializer.NumberU32_Unbounded(numComponentTypes);
|
||||
deserializer.NumberU32_Unbounded("num component types", numComponentTypes);
|
||||
|
||||
ICmpTemplateManager* templateManager = NULL;
|
||||
CParamNode noParam;
|
||||
@ -250,7 +250,7 @@ bool CComponentManager::DeserializeState(std::istream& stream)
|
||||
for (size_t i = 0; i < numComponentTypes; ++i)
|
||||
{
|
||||
std::string ctname;
|
||||
deserializer.StringASCII(ctname, 0, 255);
|
||||
deserializer.StringASCII("name", ctname, 0, 255);
|
||||
|
||||
ComponentTypeId ctid = LookupCID(ctname);
|
||||
if (ctid == CID__Invalid)
|
||||
@ -260,12 +260,12 @@ bool CComponentManager::DeserializeState(std::istream& stream)
|
||||
}
|
||||
|
||||
uint32_t numComponents;
|
||||
deserializer.NumberU32_Unbounded(numComponents);
|
||||
deserializer.NumberU32_Unbounded("num components", numComponents);
|
||||
|
||||
for (size_t j = 0; j < numComponents; ++j)
|
||||
{
|
||||
entity_id_t ent;
|
||||
deserializer.NumberU32_Unbounded(ent);
|
||||
deserializer.NumberU32_Unbounded("entity id", ent);
|
||||
IComponent* component = ConstructComponent(ent, ctid);
|
||||
if (!component)
|
||||
return false;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define INCLUDED_MESSAGE
|
||||
|
||||
#include "scriptinterface/ScriptTypes.h"
|
||||
#include "scriptinterface/ScriptVal.h"
|
||||
|
||||
class CMessage
|
||||
{
|
||||
@ -31,6 +32,9 @@ public:
|
||||
virtual const char* GetScriptHandlerName() const = 0;
|
||||
virtual const char* GetScriptGlobalHandlerName() const = 0;
|
||||
virtual jsval ToJSVal(ScriptInterface&) const = 0;
|
||||
jsval ToJSValCached(ScriptInterface&) const;
|
||||
private:
|
||||
mutable CScriptValRooted m_Cached;
|
||||
};
|
||||
// TODO: GetType could be replaced with a plain member variable to avoid some
|
||||
// virtual calls, if that turns out to be worthwhile
|
||||
|
@ -153,11 +153,11 @@ public:
|
||||
CStdDeserializer deserialize(script, stream);
|
||||
int32_t n;
|
||||
|
||||
deserialize.NumberI32_Unbounded(n);
|
||||
deserialize.NumberI32_Unbounded("x", n);
|
||||
TS_ASSERT_EQUALS(n, -123);
|
||||
deserialize.NumberI32_Unbounded(n);
|
||||
deserialize.NumberI32_Unbounded("y", n);
|
||||
TS_ASSERT_EQUALS(n, 1234);
|
||||
deserialize.NumberI32(n, 0, 65535);
|
||||
deserialize.NumberI32("z", n, 0, 65535);
|
||||
TS_ASSERT_EQUALS(n, 12345);
|
||||
|
||||
TS_ASSERT(stream.good());
|
||||
@ -184,37 +184,37 @@ public:
|
||||
std::wstring wstr;
|
||||
u8 cbuf[256];
|
||||
|
||||
deserialize.NumberU8_Unbounded(u8v);
|
||||
deserialize.NumberU8_Unbounded("u8", u8v);
|
||||
TS_ASSERT_EQUALS(u8v, 255);
|
||||
deserialize.NumberI32_Unbounded(i32v);
|
||||
deserialize.NumberI32_Unbounded("i32", i32v);
|
||||
TS_ASSERT_EQUALS(i32v, -123);
|
||||
deserialize.NumberU32_Unbounded(u32v);
|
||||
deserialize.NumberU32_Unbounded("u32", u32v);
|
||||
TS_ASSERT_EQUALS(u32v, 4294967173u);
|
||||
deserialize.NumberFloat_Unbounded(flt);
|
||||
deserialize.NumberFloat_Unbounded("float", flt);
|
||||
TS_ASSERT_EQUALS(flt, 1e+30f);
|
||||
deserialize.NumberDouble_Unbounded(dbl);
|
||||
deserialize.NumberDouble_Unbounded("double", dbl);
|
||||
TS_ASSERT_EQUALS(dbl, 1e+300);
|
||||
deserialize.NumberFixed_Unbounded(fxd);
|
||||
deserialize.NumberFixed_Unbounded("fixed", fxd);
|
||||
TS_ASSERT_EQUALS(fxd.ToDouble(), 1234.5);
|
||||
|
||||
deserialize.Bool(bl);
|
||||
deserialize.Bool("t", bl);
|
||||
TS_ASSERT_EQUALS(bl, true);
|
||||
deserialize.Bool(bl);
|
||||
deserialize.Bool("f", bl);
|
||||
TS_ASSERT_EQUALS(bl, false);
|
||||
|
||||
deserialize.StringASCII(str, 0, 255);
|
||||
deserialize.StringASCII("string", str, 0, 255);
|
||||
TS_ASSERT_STR_EQUALS(str, "example");
|
||||
deserialize.StringASCII(str, 0, 255);
|
||||
deserialize.StringASCII("string 2", str, 0, 255);
|
||||
TS_ASSERT_STR_EQUALS(str, "example\"\\\"");
|
||||
deserialize.StringASCII(str, 0, 255);
|
||||
deserialize.StringASCII("string 3", str, 0, 255);
|
||||
TS_ASSERT_STR_EQUALS(str, "example\n\ntest");
|
||||
|
||||
wchar_t testw[] = { 't', 0xEA, 's', 't', 0 };
|
||||
deserialize.String(wstr, 0, 255);
|
||||
deserialize.String("string 4", wstr, 0, 255);
|
||||
TS_ASSERT_WSTR_EQUALS(wstr, testw);
|
||||
|
||||
cbuf[6] = 0x42; // sentinel
|
||||
deserialize.RawBytes(cbuf, 6);
|
||||
deserialize.RawBytes("raw bytes", cbuf, 6);
|
||||
TS_ASSERT_SAME_DATA(cbuf, (const u8*)"\0\1\2\3\x0f\x10\x42", 7);
|
||||
|
||||
TS_ASSERT(stream.good());
|
||||
@ -297,7 +297,7 @@ public:
|
||||
CStdDeserializer deserialize(script, stream);
|
||||
|
||||
jsval newobj;
|
||||
deserialize.ScriptVal(newobj);
|
||||
deserialize.ScriptVal("script", newobj);
|
||||
TS_ASSERT(stream.good());
|
||||
TS_ASSERT_EQUALS(stream.peek(), EOF);
|
||||
|
||||
@ -326,7 +326,7 @@ public:
|
||||
CStdDeserializer deserialize(script, stream);
|
||||
|
||||
jsval newobj;
|
||||
deserialize.ScriptVal(newobj);
|
||||
deserialize.ScriptVal("script", newobj);
|
||||
TSM_ASSERT(msg, stream.good());
|
||||
TSM_ASSERT_EQUALS(msg, stream.peek(), EOF);
|
||||
|
||||
@ -436,7 +436,7 @@ public:
|
||||
CStdDeserializer deserialize(script, stream);
|
||||
|
||||
jsval newobj;
|
||||
deserialize.ScriptVal(newobj);
|
||||
deserialize.ScriptVal("script", newobj);
|
||||
TS_ASSERT(stream.good());
|
||||
TS_ASSERT_EQUALS(stream.peek(), EOF);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user