• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 22799099095

07 Mar 2026 12:31PM UTC coverage: 50.345% (+0.02%) from 50.327%
22799099095

Pull #1895

github

web-flow
Merge 8febfd5c1 into d2a3730c9
Pull Request #1895: Ships: Fix crash when doing expedition between adjacent harbor places

234 of 308 new or added lines in 23 files covered. (75.97%)

15 existing lines in 2 files now uncovered.

23056 of 45796 relevant lines covered (50.35%)

43163.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.35
/libs/s25main/world/MapSerializer.cpp
1
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "world/MapSerializer.h"
6
#include "CatapultStone.h"
7
#include "Game.h"
8
#include "SerializedGameData.h"
9
#include "buildings/noBuildingSite.h"
10
#include "helpers/Range.h"
11
#include "lua/GameDataLoader.h"
12
#include "world/GameWorldBase.h"
13
#include "s25util/warningSuppression.h"
14
#include <mygettext/mygettext.h>
15

16
void MapSerializer::Serialize(const GameWorldBase& world, SerializedGameData& sgd)
6✔
17
{
18
    // Headinformationen
19
    helpers::pushPoint(sgd, world.GetSize());
6✔
20
    sgd.PushString(world.GetDescription().get(world.GetLandscapeType()).name);
6✔
21

22
    sgd.PushUnsignedInt(GameObject::GetObjIDCounter());
6✔
23

24
    // Alle Weltpunkte serialisieren
25
    const unsigned numPlayers = world.GetNumPlayers();
6✔
26
    for(const auto& node : world.nodes)
5,366✔
27
    {
28
        node.Serialize(sgd, numPlayers, world.GetDescription());
5,360✔
29
    }
30

31
    // Katapultsteine serialisieren
32
    sgd.PushObjectContainer(world.catapult_stones, true);
6✔
33
    // Meeresinformationen serialisieren
34
    sgd.PushUnsignedInt(world.seas.size());
6✔
35
    for(const auto& sea : world.seas)
6✔
36
    {
37
        sgd.PushUnsignedInt(sea.nodes_count);
×
38
    }
39
    // Hafenpositionen serialisieren
40
    sgd.PushUnsignedInt(world.harbor_pos.size());
6✔
41
    for(const auto& curHarborPos : world.harbor_pos)
6✔
42
    {
UNCOV
43
        helpers::pushPoint(sgd, curHarborPos.pos);
×
UNCOV
44
        helpers::pushContainer(sgd, curHarborPos.seaIds);
×
UNCOV
45
        for(const auto& curNeighbors : curHarborPos.neighbors)
×
46
        {
UNCOV
47
            sgd.PushUnsignedInt(curNeighbors.size());
×
48

UNCOV
49
            for(const auto& c : curNeighbors)
×
50
            {
NEW
51
                sgd.PushUnsignedInt(c.id.value());
×
52
                sgd.PushUnsignedInt(c.distance);
×
53
            }
54
        }
55
    }
56

57
    sgd.PushObjectContainer(world.harbor_building_sites_from_sea, true);
6✔
58

59
    if(!world.HasLua())
6✔
60
        sgd.PushLongString("");
4✔
61
    else
62
    {
63
        sgd.PushLongString(world.GetLua().getScript());
2✔
64
        Serializer luaSaveState;
4✔
65
        try
66
        {
67
            if(!world.GetLua().Serialize(luaSaveState))
2✔
68
                throw SerializedGameData::Error(_("Failed to save lua state!"));
×
69
        } catch(const std::exception& e)
×
70
        {
71
            throw SerializedGameData::Error(std::string(_("Failed to save lua state!")) + _("Error: ") + e.what());
×
72
        }
73
        sgd.PushUnsignedInt(0xC0DEBA5E); // Start Lua identifier
2✔
74
        sgd.PushUnsignedInt(luaSaveState.GetLength());
2✔
75
        sgd.PushRawData(luaSaveState.GetData(), luaSaveState.GetLength());
2✔
76
        sgd.PushUnsignedInt(0xC001C0DE); // End Lua identifier
2✔
77
    }
78
}
6✔
79

80
void MapSerializer::Deserialize(GameWorldBase& world, SerializedGameData& sgd, Game& game,
3✔
81
                                ILocalGameState& localgameState)
82
{
83
    // Initialisierungen
84
    GameDataLoader gdLoader(world.GetDescriptionWriteable());
6✔
85
    if(!gdLoader.Load())
3✔
86
        throw SerializedGameData::Error(_("Failed to load game data!"));
×
87

88
    // Headinformationen
89
    const auto size = helpers::popPoint<MapExtent>(sgd);
3✔
90
    DescIdx<LandscapeDesc> lt;
3✔
91
    if(sgd.GetGameDataVersion() < 3)
3✔
92
    {
93
        uint8_t gfxSet = sgd.PopUnsignedChar();
×
94
        lt = world.GetDescription().landscapes.find([gfxSet](const LandscapeDesc& l) { return l.s2Id == gfxSet; });
×
95
    } else
96
    {
97
        std::string sLandscape = sgd.PopString();
6✔
98
        lt = world.GetDescription().landscapes.getIndex(sLandscape);
3✔
99
        if(!lt)
3✔
100
            throw SerializedGameData::Error(std::string("Invalid landscape: ") + sLandscape);
×
101
    }
102
    world.Init(size, lt);
3✔
103
    GameObject::ResetCounters(sgd.PopUnsignedInt());
3✔
104

105
    std::vector<DescIdx<TerrainDesc>> landscapeTerrains;
6✔
106
    if(sgd.GetGameDataVersion() < 3)
3✔
107
    {
108
        // Assumes the order of the terrain in the description file is the same as in the prior RTTR versions
109
        landscapeTerrains =
110
          world.GetDescription().terrain.findAll([lt](const TerrainDesc& t) { return t.landscape == lt; });
×
111
    }
112
    // Alle Weltpunkte
113
    MapPoint curPos(0, 0);
3✔
114
    const unsigned numPlayers = world.GetNumPlayers();
3✔
115
    for(auto& node : world.nodes)
2,683✔
116
    {
117
        node.Deserialize(sgd, numPlayers, world.GetDescription(), landscapeTerrains);
2,680✔
118
        curPos.x++;
2,680✔
119
        if(curPos.x >= world.GetWidth())
2,680✔
120
        {
121
            curPos.x = 0;
74✔
122
            curPos.y++;
74✔
123
        }
124
    }
125

126
    sgd.PopObjectContainer(world.catapult_stones, GO_Type::Catapultstone);
3✔
127

128
    world.seas.resize(sgd.PopUnsignedInt());
3✔
129
    for(auto& sea : world.seas)
3✔
UNCOV
130
        sea.nodes_count = sgd.PopUnsignedInt();
×
131

132
    // Deserialize harbor data
133
    const unsigned numHarborPositions = sgd.PopUnsignedInt();
3✔
134
    world.harbor_pos.clear();
3✔
135
    world.harbor_pos.reserve(numHarborPositions);
3✔
136
    for(const auto i : helpers::range<unsigned>(numHarborPositions))
12✔
137
    {
138
        RTTR_UNUSED(i);
UNCOV
139
        world.harbor_pos.emplace_back(sgd.PopMapPoint());
×
UNCOV
140
        auto& curHarborPos = world.harbor_pos.back();
×
UNCOV
141
        helpers::popContainer(sgd, curHarborPos.seaIds);
×
UNCOV
142
        for(auto& neighbor : curHarborPos.neighbors)
×
143
        {
UNCOV
144
            const unsigned numNeighbors = sgd.PopUnsignedInt();
×
UNCOV
145
            neighbor.reserve(numNeighbors);
×
UNCOV
146
            for(const auto j : helpers::range<unsigned>(numNeighbors))
×
147
            {
148
                RTTR_UNUSED(j);
NEW
149
                const auto id = HarborId(sgd.PopUnsignedInt());
×
150
                const auto distance = sgd.PopUnsignedInt();
×
151
                neighbor.emplace_back(id, distance);
×
152
            }
153
        }
154
    }
155
    if(sgd.GetGameDataVersion() < 13 && !world.harbor_pos.empty())
3✔
NEW
156
        world.harbor_pos.erase(world.harbor_pos.begin());
×
157

158
    sgd.PopObjectContainer(world.harbor_building_sites_from_sea, GO_Type::Buildingsite);
3✔
159

160
    const std::string luaScript = sgd.PopLongString();
6✔
161
    if(!luaScript.empty())
3✔
162
    {
163
        if(sgd.PopUnsignedInt() != 0xC0DEBA5E)
1✔
164
            throw SerializedGameData::Error(_("Invalid id for lua data"));
×
165
        // If there is a script, there is also save data. Store reference to that
166
        const auto luaSaveSize = sgd.PopUnsignedInt();
1✔
167
        Serializer luaSaveState(sgd.PopAndDiscard(luaSaveSize), luaSaveSize);
2✔
168
        if(sgd.PopUnsignedInt() != 0xC001C0DE)
1✔
169
            throw SerializedGameData::Error(_("Invalid end-id for lua data"));
×
170

171
        // Now init and load lua
172
        auto lua = std::make_unique<LuaInterfaceGame>(game, localgameState);
1✔
173
        if(!lua->loadScriptString(luaScript))
1✔
174
            throw SerializedGameData::Error(_("Lua script failed to load."));
×
175
        if(!lua->CheckScriptVersion())
1✔
176
            throw SerializedGameData::Error(_("Wrong version for lua script."));
×
177
        try
178
        {
179
            if(!lua->Deserialize(luaSaveState))
1✔
180
                throw SerializedGameData::Error(_("Lua load callback returned failure!"));
×
181
        } catch(const std::exception& e)
×
182
        {
183
            throw SerializedGameData::Error(std::string(_("Failed to load lua state!")) + _("Error: ") + e.what());
×
184
        }
185
        game.SetLua(std::move(lua));
1✔
186
    }
187
    world.CreateTradeGraphs();
3✔
188
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc