Fix an OOS on rejoin when a ptolemian lighthouse revealing the shoreline was built prior. Patch by Itms and wraitii, fixes #4277.

Serialize the mapsize in the pathfinder and the reveal shoreline flag in
the range manager.
Reload the rangemanager data after other components have been
deserialized.
Use the SerializeCommon pattern in the pathfinder to avoid code
duplication.
Move the shoreline logic from the Vision component to the range manager.
Remove unused interface mocks from the rangemanager test following
b05879e151.

This was SVN commit r18879.
This commit is contained in:
elexis 2016-10-28 15:34:24 +00:00
parent b70af394df
commit 5a384f4eaf
6 changed files with 62 additions and 26 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2016 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -135,22 +135,26 @@ struct SerializeShortRequest
}
};
void CCmpPathfinder::Serialize(ISerializer& serialize)
template<typename S>
void CCmpPathfinder::SerializeCommon(S& serialize)
{
SerializeVector<SerializeLongRequest>()(serialize, "long requests", m_AsyncLongPathRequests);
SerializeVector<SerializeShortRequest>()(serialize, "short requests", m_AsyncShortPathRequests);
serialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket);
serialize.NumberU16_Unbounded("same turn moves count", m_SameTurnMovesCount);
serialize.NumberU16_Unbounded("map size", m_MapSize);
}
void CCmpPathfinder::Serialize(ISerializer& serialize)
{
SerializeCommon(serialize);
}
void CCmpPathfinder::Deserialize(const CParamNode& paramNode, IDeserializer& deserialize)
{
Init(paramNode);
SerializeVector<SerializeLongRequest>()(deserialize, "long requests", m_AsyncLongPathRequests);
SerializeVector<SerializeShortRequest>()(deserialize, "short requests", m_AsyncShortPathRequests);
deserialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket);
deserialize.NumberU16_Unbounded("same turn moves count", m_SameTurnMovesCount);
SerializeCommon(deserialize);
}
void CCmpPathfinder::HandleMessage(const CMessage& msg, bool UNUSED(global))

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2016 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -193,6 +193,9 @@ public:
virtual void Deinit();
template<typename S>
void SerializeCommon(S& serialize);
virtual void Serialize(ISerializer& serialize);
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize);

View File

@ -170,14 +170,19 @@ static std::map<entity_id_t, EntityParabolicRangeOutline> ParabolicRangesOutline
*/
struct EntityData
{
EntityData() : visibilities(0), size(0), retainInFog(0), owner(-1), inWorld(0), flags(1), scriptedVisibility(0) { }
EntityData() :
visibilities(0), size(0),
owner(-1), retainInFog(0), inWorld(0), revealShore(0),
flags(1), scriptedVisibility(0)
{ }
entity_pos_t x, z;
entity_pos_t visionRange;
u32 visibilities; // 2-bit visibility, per player
u32 size;
u8 retainInFog; // boolean
i8 owner;
u8 retainInFog; // boolean
u8 inWorld; // boolean
u8 revealShore; // boolean
u8 flags; // See GetEntityFlagMask
u8 scriptedVisibility; // boolean, see ComputeLosVisibility
};
@ -236,11 +241,12 @@ struct SerializeEntityData
serialize.NumberFixed_Unbounded("vision", value.visionRange);
serialize.NumberU32_Unbounded("visibilities", value.visibilities);
serialize.NumberU32_Unbounded("size", value.size);
serialize.NumberU8("retain in fog", value.retainInFog, 0, 1);
serialize.NumberI8_Unbounded("owner", value.owner);
serialize.NumberU8("retain in fog", value.retainInFog, 0, 1);
serialize.NumberU8("in world", value.inWorld, 0, 1);
serialize.NumberU8("reveal shore", value.revealShore, 0, 1);
serialize.NumberU8_Unbounded("flags", value.flags);
serialize.NumberU8_Unbounded("scripted visibility", value.scriptedVisibility);
serialize.NumberU8("scripted visibility", value.scriptedVisibility, 0, 1);
}
};
@ -293,6 +299,8 @@ public:
componentManager.SubscribeGloballyToMessageType(MT_Destroy);
componentManager.SubscribeGloballyToMessageType(MT_VisionRangeChanged);
componentManager.SubscribeToMessageType(MT_Deserialized);
componentManager.SubscribeToMessageType(MT_Update);
componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
@ -440,17 +448,21 @@ public:
Init(paramNode);
SerializeCommon(deserialize);
// Reinitialise subdivisions and LOS data
m_Deserializing = true;
ResetDerivedData();
m_Deserializing = false;
}
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
{
switch (msg.GetType())
{
case MT_Deserialized:
{
// Reinitialize subdivisions and LOS data after all
// other components have been deserialized.
m_Deserializing = true;
ResetDerivedData();
m_Deserializing = false;
break;
}
case MT_Create:
{
const CMessageCreate& msgData = static_cast<const CMessageCreate&> (msg);
@ -473,7 +485,10 @@ public:
// Store the LOS data, if any
CmpPtr<ICmpVision> cmpVision(GetSimContext(), ent);
if (cmpVision)
{
entdata.visionRange = cmpVision->GetRange();
entdata.revealShore = cmpVision->GetRevealShore() ? 1 : 0;
}
CmpPtr<ICmpVisibility> cmpVisibility(GetSimContext(), ent);
if (cmpVisibility)
entdata.retainInFog = (cmpVisibility->GetRetainInFog() ? 1 : 0);
@ -561,6 +576,12 @@ public:
CFixedVector2D pos(it->second.x, it->second.z);
LosRemove(it->second.owner, it->second.visionRange, pos);
LosAdd(msgData.to, it->second.visionRange, pos);
if (it->second.revealShore)
{
RevealShore(it->second.owner, false);
RevealShore(msgData.to, true);
}
}
ENSURE(-128 <= msgData.to && msgData.to <= 127);
@ -751,6 +772,9 @@ public:
{
LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));
AddToTile(PosToLosTilesHelper(it->second.x, it->second.z), it->first);
if (it->second.revealShore)
RevealShore(it->second.owner, true);
}
}

View File

@ -40,6 +40,9 @@ public:
// Template state:
entity_pos_t m_Range, m_BaseRange;
// TODO: The reveal shore system should be replaced by a general
// system of "special" vision methods that are not ranges.
bool m_RevealShore;
static std::string GetSchema()
@ -90,12 +93,6 @@ public:
break;
ReloadRange();
if (!m_RevealShore)
break;
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
cmpRangeManager->RevealShore(msgData.from, false);
cmpRangeManager->RevealShore(msgData.to, true);
break;
}
case MT_ValueModification:
@ -137,6 +134,11 @@ public:
{
return m_Range;
}
virtual bool GetRevealShore()
{
return m_RevealShore;
}
};
REGISTER_COMPONENT_TYPE(Vision)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2014 Wildfire Games.
/* Copyright (C) 2016 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -29,6 +29,7 @@ class ICmpVision : public IComponent
{
public:
virtual entity_pos_t GetRange() = 0;
virtual bool GetRevealShore() = 0;
DECLARE_INTERFACE_TYPE(Vision)
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2016 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -31,8 +31,7 @@ public:
DEFAULT_MOCK_COMPONENT()
virtual entity_pos_t GetRange() { return entity_pos_t::FromInt(66); }
virtual bool GetRetainInFog() { return false; }
virtual bool GetAlwaysVisible() { return false; }
virtual bool GetRevealShore() { return false; }
};
class MockPosition : public ICmpPosition
@ -85,6 +84,9 @@ public:
CXeromyces::Terminate();
}
// TODO It would be nice to call Verify() with the shore revealing system
// but that means testing on an actual map, with water and land.
void test_basic()
{
ComponentTestHelper test(g_ScriptRuntime);