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

Return-To-The-Roots / s25client / 14539130160

18 Apr 2025 05:32PM UTC coverage: 50.281% (-0.007%) from 50.288%
14539130160

Pull #1750

github

web-flow
Merge ec6a25ca8 into c8cf430f2
Pull Request #1750: Fix size of Settings window

11 of 29 new or added lines in 15 files covered. (37.93%)

2 existing lines in 1 file now uncovered.

22354 of 44458 relevant lines covered (50.28%)

34974.45 hits per line

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

94.03
/libs/libGamedata/lua/GameDataLoader.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 "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
{
25
    Register(lua);
205✔
26

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

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

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

37
bool GameDataLoader::Load()
205✔
38
{
39
    curFile_ = basePath_ / "default.lua";
410✔
40
    curIncludeDepth_ = 0;
205✔
41
    try
42
    {
43
        return loadScript(curFile_);
205✔
NEW
44
    } catch(const std::exception& e)
×
45
    {
46
        LOG.write("Failed to load game data!\nReason: %1%\nCurrent file being processed: %2%\n") % e.what() % curFile_;
×
47
        return false;
×
48
    }
49
}
50

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

59
class LuaIncludeError : public std::runtime_error
60
{
61
public:
62
    using std::runtime_error::runtime_error;
63
};
64

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

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

105
void GameDataLoader::AddLandscape(const kaguya::LuaTable& data)
595✔
106
{
107
    worldDesc_.landscapes.add(LandscapeDesc(data, worldDesc_));
595✔
108
}
595✔
109

110
void GameDataLoader::AddTerrainEdge(const kaguya::LuaTable& data)
2,773✔
111
{
112
    worldDesc_.edges.add(EdgeDesc(data, worldDesc_));
2,773✔
113
}
2,773✔
114

115
void GameDataLoader::AddTerrain(const kaguya::LuaTable& data)
13,863✔
116
{
117
    worldDesc_.terrain.add(TerrainDesc(data, worldDesc_));
13,863✔
118
}
13,863✔
119

120
void loadGameData(WorldDescription& worldDesc)
183✔
121

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