Fix serialize/deserialize API asymmetry.

Add serialization support to more components.

This was SVN commit r8122.
This commit is contained in:
Ykkrosh 2010-09-17 17:53:26 +00:00
parent a29bb003f2
commit 8a98102195
21 changed files with 317 additions and 139 deletions

View File

@ -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;
}

View File

@ -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))

View File

@ -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);
}

View File

@ -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))

View File

@ -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))

View File

@ -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())

View File

@ -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);

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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()

View File

@ -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))

View File

@ -46,7 +46,7 @@ class ICmpPathfinder : public IComponent
public:
struct Goal
{
enum {
enum Type {
POINT,
CIRCLE,
SQUARE

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View 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);
}
};

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);