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

Return-To-The-Roots / s25client / 14703950502

28 Apr 2025 08:48AM UTC coverage: 50.335% (+0.04%) from 50.297%
14703950502

Pull #1766

github

web-flow
Merge 0a30062a7 into 547649373
Pull Request #1766: Fix random failures in network tests

22378 of 44458 relevant lines covered (50.34%)

35641.75 hits per line

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

98.51
/libs/libGamedata/lua/GameDataLoader.cpp
1
// Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "GameDataLoader.h"
6
#include "CheckedLuaTable.h"
7
#include "RttrConfig.h"
8
#include "files.h"
9
#include "helpers/containerUtils.h"
10
#include "helpers/format.hpp"
11
#include "gameData/EdgeDesc.h"
12
#include "gameData/LandscapeDesc.h"
13
#include "gameData/TerrainDesc.h"
14
#include "gameData/WorldDescription.h"
15
#include "s25util/Log.h"
16
#include <kaguya/kaguya.hpp>
17
#include <boost/filesystem.hpp>
18
#include <stdexcept>
19

20
namespace bfs = boost::filesystem;
21

22
GameDataLoader::GameDataLoader(WorldDescription& worldDesc, const boost::filesystem::path& basePath)
205✔
23
    : worldDesc_(worldDesc), basePath_(basePath.lexically_normal().make_preferred()), curIncludeDepth_(0),
410✔
24
      errorInIncludeFile_(false)
615✔
25
{
26
    Register(lua);
205✔
27

28
    lua["rttr"] = this;
205✔
29
    lua["include"] = kaguya::function([this](const std::string& file) { Include(file); });
815✔
30
}
205✔
31

32
GameDataLoader::GameDataLoader(WorldDescription& worldDesc)
198✔
33
    : GameDataLoader(worldDesc, RTTRCONFIG.ExpandPath(s25::folders::gamedata) / "world")
396✔
34
{}
198✔
35

36
GameDataLoader::~GameDataLoader() = default;
205✔
37

38
bool GameDataLoader::Load()
205✔
39
{
40
    curFile_ = basePath_ / "default.lua";
410✔
41
    curIncludeDepth_ = 0;
205✔
42
    errorInIncludeFile_ = false;
205✔
43
    if(!loadScript(curFile_))
205✔
44
        return false;
5✔
45
    return !errorInIncludeFile_;
200✔
46
}
47

48
void GameDataLoader::Register(kaguya::State& state)
205✔
49
{
50
    state["RTTRGameData"].setClass(kaguya::UserdataMetatable<GameDataLoader, LuaInterfaceBase>()
410✔
51
                                     .addFunction("AddLandscape", &GameDataLoader::AddLandscape)
205✔
52
                                     .addFunction("AddTerrainEdge", &GameDataLoader::AddTerrainEdge)
205✔
53
                                     .addFunction("AddTerrain", &GameDataLoader::AddTerrain));
205✔
54
}
205✔
55

56
class LuaIncludeError : public std::runtime_error
57
{
58
public:
59
    using std::runtime_error::runtime_error;
60
};
61

62
void GameDataLoader::Include(const std::string& filepath)
610✔
63
{
64
    try
65
    {
66
        constexpr int maxIncludeDepth = 10;
610✔
67
        // Protect against cycles and stack overflows
68
        if(curIncludeDepth_ >= maxIncludeDepth)
610✔
69
            throw LuaIncludeError(helpers::format("Maximum include depth of %1% is reached!", maxIncludeDepth));
1✔
70
        const auto isAllowedChar = [](const char c) {
8,248✔
71
            return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '/'
8,248✔
72
                   || c == '.';
16,496✔
73
        };
74
        if(helpers::contains_if(filepath, [isAllowedChar](const char c) { return !isAllowedChar(c); }))
8,857✔
75
            throw LuaIncludeError("It contains disallowed chars. Allowed: alpha-numeric, underscore, slash and dot.");
1✔
76
        if(bfs::path(filepath).is_absolute())
608✔
77
            throw LuaIncludeError("Path to file must be relative to current file");
1✔
78
        bfs::path absFilePath = bfs::absolute(filepath, curFile_.parent_path());
1,821✔
79
        if(!bfs::is_regular_file(absFilePath))
607✔
80
            throw LuaIncludeError("File not found!");
1✔
81

82
        // Normalize for below check against basePath
83
        absFilePath = absFilePath.lexically_normal().make_preferred();
606✔
84
        if(absFilePath.extension() != ".lua")
1,212✔
85
            throw LuaIncludeError("File must have .lua as the extension!");
1✔
86
        if(absFilePath.string().find(basePath_.string()) != 0)
605✔
87
            throw LuaIncludeError("File is outside the lua data directory!");
1✔
88
        const auto oldCurFile = curFile_;
604✔
89
        curFile_ = absFilePath;
604✔
90
        ++curIncludeDepth_;
604✔
91
        errorInIncludeFile_ |= !loadScript(absFilePath);
604✔
92
        curFile_ = oldCurFile;
604✔
93
        RTTR_Assert(curIncludeDepth_ > 0);
604✔
94
        --curIncludeDepth_;
604✔
95
    } catch(const LuaIncludeError& e)
12✔
96
    {
97
        throw std::runtime_error(helpers::format("Include file '%1%' cannot be included: %2%", filepath, e.what()));
6✔
98
    }
99
}
604✔
100

101
void GameDataLoader::AddLandscape(const kaguya::LuaTable& data)
595✔
102
{
103
    worldDesc_.landscapes.add(LandscapeDesc(data, worldDesc_));
595✔
104
}
595✔
105

106
void GameDataLoader::AddTerrainEdge(const kaguya::LuaTable& data)
2,773✔
107
{
108
    worldDesc_.edges.add(EdgeDesc(data, worldDesc_));
2,773✔
109
}
2,773✔
110

111
void GameDataLoader::AddTerrain(const kaguya::LuaTable& data)
13,863✔
112
{
113
    worldDesc_.terrain.add(TerrainDesc(data, worldDesc_));
13,863✔
114
}
13,863✔
115

116
void loadGameData(WorldDescription& worldDesc)
183✔
117

118
{
119
    GameDataLoader gdLoader(worldDesc);
366✔
120
    if(!gdLoader.Load())
183✔
121
        throw std::runtime_error("Failed to load game data");
×
122
}
183✔
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