From 5a384f4eafd96521f9e90a765151ffbe22755e4f Mon Sep 17 00:00:00 2001 From: elexis Date: Fri, 28 Oct 2016 15:34:24 +0000 Subject: [PATCH] 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. --- .../simulation2/components/CCmpPathfinder.cpp | 16 ++++--- .../components/CCmpPathfinder_Common.h | 5 ++- .../components/CCmpRangeManager.cpp | 42 +++++++++++++++---- source/simulation2/components/CCmpVision.cpp | 14 ++++--- source/simulation2/components/ICmpVision.h | 3 +- .../components/tests/test_RangeManager.h | 8 ++-- 6 files changed, 62 insertions(+), 26 deletions(-) diff --git a/source/simulation2/components/CCmpPathfinder.cpp b/source/simulation2/components/CCmpPathfinder.cpp index 5b6c0f3e61..e0e725fe51 100644 --- a/source/simulation2/components/CCmpPathfinder.cpp +++ b/source/simulation2/components/CCmpPathfinder.cpp @@ -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 +void CCmpPathfinder::SerializeCommon(S& serialize) { SerializeVector()(serialize, "long requests", m_AsyncLongPathRequests); SerializeVector()(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()(deserialize, "long requests", m_AsyncLongPathRequests); - SerializeVector()(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)) diff --git a/source/simulation2/components/CCmpPathfinder_Common.h b/source/simulation2/components/CCmpPathfinder_Common.h index 13a604988d..7fc97892e8 100644 --- a/source/simulation2/components/CCmpPathfinder_Common.h +++ b/source/simulation2/components/CCmpPathfinder_Common.h @@ -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 + void SerializeCommon(S& serialize); + virtual void Serialize(ISerializer& serialize); virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize); diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp index 69245d1dc2..c48d74127c 100644 --- a/source/simulation2/components/CCmpRangeManager.cpp +++ b/source/simulation2/components/CCmpRangeManager.cpp @@ -170,14 +170,19 @@ static std::map 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 (msg); @@ -473,7 +485,10 @@ public: // Store the LOS data, if any CmpPtr cmpVision(GetSimContext(), ent); if (cmpVision) + { entdata.visionRange = cmpVision->GetRange(); + entdata.revealShore = cmpVision->GetRevealShore() ? 1 : 0; + } CmpPtr 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); } } diff --git a/source/simulation2/components/CCmpVision.cpp b/source/simulation2/components/CCmpVision.cpp index 2bbd8abe44..81f673005b 100644 --- a/source/simulation2/components/CCmpVision.cpp +++ b/source/simulation2/components/CCmpVision.cpp @@ -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 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) diff --git a/source/simulation2/components/ICmpVision.h b/source/simulation2/components/ICmpVision.h index fed3163aff..05268fe3aa 100644 --- a/source/simulation2/components/ICmpVision.h +++ b/source/simulation2/components/ICmpVision.h @@ -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) }; diff --git a/source/simulation2/components/tests/test_RangeManager.h b/source/simulation2/components/tests/test_RangeManager.h index 5e5eaf9637..9f97fd2ebb 100644 --- a/source/simulation2/components/tests/test_RangeManager.h +++ b/source/simulation2/components/tests/test_RangeManager.h @@ -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);