Skip to content

Commit 63689a6

Browse files
committed
Verify validity of env objects added via LUA
See #1464
1 parent 409b50a commit 63689a6

File tree

6 files changed

+120
-39
lines changed

6 files changed

+120
-39
lines changed

libs/s25main/Loader.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,47 @@ void Loader::LoadDummyGUIFiles()
343343
}
344344
}
345345

346+
void Loader::LoadDummyMapFiles()
347+
{
348+
libsiedler2::Archiv& map = files_["map_0_z"].archive;
349+
if(!map.empty())
350+
return;
351+
const auto pushRange = [&map](unsigned from, unsigned to) {
352+
map.alloc_inc(to - map.size() + 1);
353+
libsiedler2::PixelBufferBGRA buffer(1, 1);
354+
for(unsigned i = from; i <= to; i++)
355+
{
356+
auto bmp = std::make_unique<glArchivItem_Bitmap_Raw>();
357+
bmp->create(buffer);
358+
map.set(i, std::move(bmp));
359+
};
360+
};
361+
map_gfx = &map;
362+
363+
// Some ID ranges as found in map_0_z.lst
364+
pushRange(20, 23);
365+
pushRange(40, 46);
366+
pushRange(50, 55);
367+
pushRange(59, 67);
368+
pushRange(200, 282);
369+
pushRange(290, 334);
370+
pushRange(350, 432);
371+
pushRange(440, 484);
372+
pushRange(500, 527);
373+
374+
for(int j = 0; j <= 5; j++)
375+
{
376+
libsiedler2::Archiv& bobs = files_[ResourceId("mis" + std::to_string(j) + "bobs")].archive;
377+
libsiedler2::PixelBufferBGRA buffer(1, 1);
378+
for(unsigned i = 0; i <= 10; i++)
379+
{
380+
auto bmp = std::make_unique<glArchivItem_Bitmap_Raw>();
381+
bmp->create(buffer);
382+
bobs.push(std::move(bmp));
383+
}
384+
}
385+
}
386+
346387
namespace {
347388
struct NationResourcesSource
348389
{

libs/s25main/Loader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class Loader
8585

8686
/// Creates archives with empty files for the GUI (for testing purposes)
8787
void LoadDummyGUIFiles();
88+
void LoadDummyMapFiles();
8889
/// Load a file and save it into the loader repo
8990
bool Load(const boost::filesystem::path& path, const libsiedler2::ArchivItem_Palette* palette = nullptr);
9091
bool Load(const ResourceId& resId, const libsiedler2::ArchivItem_Palette* palette = nullptr);

libs/s25main/lua/LuaWorld.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,21 @@ void LuaWorld::Register(kaguya::State& state)
3636
.addFunction("AddAnimal", &LuaWorld::AddAnimal));
3737
}
3838

39+
static bool isValidObject(unsigned file, unsigned id)
40+
{
41+
try
42+
{
43+
return noStaticObject::getTextures(file, id).bmp != nullptr;
44+
} catch(const std::runtime_error&)
45+
{
46+
return false;
47+
}
48+
}
49+
3950
bool LuaWorld::AddEnvObject(int x, int y, unsigned id, unsigned file /* = 0xFFFF */)
4051
{
52+
lua::assertTrue(isValidObject(file, id), "Invalid object (file/id)");
53+
4154
MapPoint pt = gw.MakeMapPoint(Position(x, y));
4255
noBase* obj = gw.GetNode(pt).obj;
4356
if(obj)
@@ -57,6 +70,7 @@ bool LuaWorld::AddEnvObject(int x, int y, unsigned id, unsigned file /* = 0xFFFF
5770
bool LuaWorld::AddStaticObject(int x, int y, unsigned id, unsigned file /* = 0xFFFF */, unsigned size /* = 1 */)
5871
{
5972
lua::assertTrue(size <= 2, "Invalid size");
73+
lua::assertTrue(isValidObject(file, id), "Invalid object (file/id)");
6074

6175
MapPoint pt = gw.MakeMapPoint(Position(x, y));
6276
noBase* obj = gw.GetNode(pt).obj;

libs/s25main/nodeObjs/noStaticObject.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,33 +75,39 @@ BlockingManner noStaticObject::GetBM() const
7575
*/
7676
void noStaticObject::Draw(DrawPoint drawPt)
7777
{
78-
ITexture *bitmap = nullptr, *shadow = nullptr;
79-
80-
if((file == 0xFFFF) && (id == 561))
78+
if(!textures.bmp)
8179
{
82-
LOADER.gateway_cache[GAMECLIENT.GetGlobalAnimation(4, 5, 4, 0) + 1].draw(drawPt);
83-
return;
84-
} else if(file == 0xFFFF)
80+
textures = getTextures(file, id);
81+
RTTR_Assert(textures.bmp);
82+
}
83+
84+
// Bild zeichnen
85+
textures.bmp->DrawFull(drawPt);
86+
87+
// Schatten zeichnen
88+
if(textures.shadow)
89+
textures.shadow->DrawFull(drawPt, COLOR_SHADOW);
90+
}
91+
92+
noStaticObject::Textures noStaticObject::getTextures(unsigned short file, unsigned short id)
93+
{
94+
Textures textures{};
95+
if(file == 0xFFFF)
8596
{
86-
bitmap = LOADER.GetMapTexture(id);
87-
shadow = LOADER.GetMapTexture(id + 100);
97+
if(id == 561)
98+
textures.bmp = &LOADER.gateway_cache[GAMECLIENT.GetGlobalAnimation(4, 5, 4, 0) + 1];
99+
else
100+
textures = {LOADER.GetMapTexture(id), LOADER.GetMapTexture(id + 100)};
88101
} else if(file < 7)
89102
{
90103
static const std::array<ResourceId, 7> files = {"mis0bobs", "mis1bobs", "mis2bobs", "mis3bobs",
91104
"mis4bobs", "mis5bobs", "charburner_bobs"};
92-
bitmap = LOADER.GetTextureN(files[file], id);
105+
textures.bmp = LOADER.GetTextureN(files[file], id);
93106
// Use only shadows where available
94107
if(file < 6)
95-
shadow = LOADER.GetTextureN(files[file], id + 1);
108+
textures.shadow = LOADER.GetTextureN(files[file], id + 1);
96109
} else
97110
throw std::runtime_error("Invalid file number for static object");
98111

99-
RTTR_Assert(bitmap);
100-
101-
// Bild zeichnen
102-
bitmap->DrawFull(drawPt);
103-
104-
// Schatten zeichnen
105-
if(shadow)
106-
shadow->DrawFull(drawPt, COLOR_SHADOW);
112+
return textures;
107113
}

libs/s25main/nodeObjs/noStaticObject.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55
#pragma once
66

77
#include "noCoordBase.h"
8+
#include "ogl/ITexture.h"
89
class SerializedGameData;
910

1011
class noStaticObject : public noCoordBase
1112
{
1213
public:
14+
struct Textures
15+
{
16+
ITexture *bmp, *shadow;
17+
};
18+
1319
noStaticObject(MapPoint pos, unsigned short id, unsigned short file = 0xFFFF, unsigned char size = 1,
1420
NodalObjectType type = NodalObjectType::Object);
1521
noStaticObject(SerializedGameData& sgd, unsigned obj_id);
@@ -30,8 +36,11 @@ class noStaticObject : public noCoordBase
3036
/// zeichnet das Objekt.
3137
void Draw(DrawPoint drawPt) override;
3238

39+
static Textures getTextures(unsigned short file, unsigned short id);
40+
3341
protected:
3442
unsigned short id;
3543
unsigned short file;
3644
unsigned char size;
45+
Textures textures{};
3746
};

tests/s25Main/lua/testLua.cpp

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// SPDX-License-Identifier: GPL-2.0-or-later
44

55
#include "GameWithLuaAccess.h"
6+
#include "Loader.h"
67
#include "PointOutput.h"
78
#include "RttrForeachPt.h"
89
#include "buildings/noBuildingSite.h"
@@ -557,53 +558,62 @@ BOOST_AUTO_TEST_CASE(World)
557558
{
558559
LogAccessor logAcc;
559560
initWorld();
561+
LOADER.LoadDummyMapFiles();
560562
executeLua("world = rttr:GetWorld()");
561563

562564
const MapPoint envPt(15, 12);
563565
const MapPoint hqPos(world.GetPlayer(1).GetHQPos());
564566
executeLua(boost::format("world:AddEnvObject(%1%, %2%, 500)") % envPt.x % envPt.y);
565567
const noEnvObject* obj = world.GetSpecObj<noEnvObject>(envPt);
566568
BOOST_TEST_REQUIRE(obj);
567-
BOOST_TEST_REQUIRE(obj->GetItemID() == 500u);
568-
BOOST_TEST_REQUIRE(obj->GetItemFile() == 0xFFFFu);
569+
BOOST_TEST(obj->GetItemID() == 500u);
570+
BOOST_TEST(obj->GetItemFile() == 0xFFFFu);
569571
// Replace and test wrap around (envPt2==envPt1)
570572
const Position envPt2(envPt.x + world.GetWidth(), envPt.y - world.GetHeight());
571573
BOOST_TEST_REQUIRE(world.MakeMapPoint(envPt2) == envPt);
572574
executeLua(boost::format("world:AddEnvObject(%1%, %2%, 1, 2)") % envPt2.x % envPt2.y);
573575
obj = world.GetSpecObj<noEnvObject>(envPt);
574576
BOOST_TEST_REQUIRE(obj);
575-
BOOST_TEST_REQUIRE(obj->GetItemID() == 1u);
576-
BOOST_TEST_REQUIRE(obj->GetItemFile() == 2u);
577+
BOOST_TEST(obj->GetItemID() == 1u);
578+
BOOST_TEST(obj->GetItemFile() == 2u);
577579

578580
// ID only
579581
const MapPoint envPt3(envPt.x + 5, envPt.y);
580582
executeLua(boost::format("world:AddStaticObject(%1%, %2%, 501)") % envPt3.x % envPt3.y);
581583
const noStaticObject* obj2 = world.GetSpecObj<noStaticObject>(envPt3);
582584
BOOST_TEST_REQUIRE(obj2);
583-
BOOST_TEST_REQUIRE(obj2->GetGOT() == GO_Type::Staticobject);
584-
BOOST_TEST_REQUIRE(obj2->GetItemID() == 501u);
585-
BOOST_TEST_REQUIRE(obj2->GetItemFile() == 0xFFFFu);
586-
BOOST_TEST_REQUIRE(obj2->GetSize() == 1u);
585+
BOOST_TEST(obj2->GetGOT() == GO_Type::Staticobject);
586+
BOOST_TEST(obj2->GetItemID() == 501u);
587+
BOOST_TEST(obj2->GetItemFile() == 0xFFFFu);
588+
BOOST_TEST(obj2->GetSize() == 1u);
587589
// ID and File (replace env obj)
588590
executeLua(boost::format("world:AddStaticObject(%1%, %2%, 5, 3)") % envPt2.x % envPt2.y);
589591
obj2 = world.GetSpecObj<noStaticObject>(envPt);
590592
BOOST_TEST_REQUIRE(obj2);
591-
BOOST_TEST_REQUIRE(obj2->GetGOT() == GO_Type::Staticobject);
592-
BOOST_TEST_REQUIRE(obj2->GetItemID() == 5u);
593-
BOOST_TEST_REQUIRE(obj2->GetItemFile() == 3u);
594-
BOOST_TEST_REQUIRE(obj2->GetSize() == 1u);
593+
BOOST_TEST(obj2->GetGOT() == GO_Type::Staticobject);
594+
BOOST_TEST(obj2->GetItemID() == 5u);
595+
BOOST_TEST(obj2->GetItemFile() == 3u);
596+
BOOST_TEST(obj2->GetSize() == 1u);
595597
// ID, File and Size (replace static obj)
596598
executeLua(boost::format("world:AddStaticObject(%1%, %2%, 5, 3, 2)") % envPt2.x % envPt2.y);
597599
obj2 = world.GetSpecObj<noStaticObject>(envPt);
598600
BOOST_TEST_REQUIRE(obj2);
599-
BOOST_TEST_REQUIRE(obj2->GetGOT() == GO_Type::Staticobject);
600-
BOOST_TEST_REQUIRE(obj2->GetItemID() == 5u);
601-
BOOST_TEST_REQUIRE(obj2->GetItemFile() == 3u);
602-
BOOST_TEST_REQUIRE(obj2->GetSize() == 2u);
601+
BOOST_TEST(obj2->GetGOT() == GO_Type::Staticobject);
602+
BOOST_TEST(obj2->GetItemID() == 5u);
603+
BOOST_TEST(obj2->GetItemFile() == 3u);
604+
BOOST_TEST(obj2->GetSize() == 2u);
603605
// Invalid Size
604-
BOOST_REQUIRE_THROW(executeLua(boost::format("world:AddStaticObject(%1%, %2%, 5, 3, 3)") % envPt2.x % envPt2.y),
605-
std::runtime_error);
606+
BOOST_CHECK_THROW(executeLua(boost::format("world:AddStaticObject(%1%, %2%, 5, 3, 3)") % envPt2.x % envPt2.y),
607+
std::runtime_error);
606608
RTTR_REQUIRE_LOG_CONTAINS("Invalid size", false);
609+
// Invalid File
610+
BOOST_CHECK_THROW(executeLua(boost::format("world:AddEnvObject(%1%, %2%, 5, 7)") % envPt2.x % envPt2.y),
611+
std::runtime_error);
612+
RTTR_REQUIRE_LOG_CONTAINS("Invalid object ", false);
613+
// Invalid Id
614+
BOOST_CHECK_THROW(executeLua(boost::format("world:AddEnvObject(%1%, %2%, 50000)") % envPt2.x % envPt2.y),
615+
std::runtime_error);
616+
RTTR_REQUIRE_LOG_CONTAINS("Invalid object ", false);
607617

608618
// Can't replace buildings
609619
executeLua(boost::format("world:AddEnvObject(%1%, %2%, 1, 2)") % hqPos.x % hqPos.y);
@@ -614,7 +624,7 @@ BOOST_AUTO_TEST_CASE(World)
614624
executeLua(boost::format("world:AddEnvObject(%1%, %2%, 5, 3)") % envPt2.x % envPt2.y);
615625
obj2 = world.GetSpecObj<noStaticObject>(envPt);
616626
BOOST_TEST_REQUIRE(obj2);
617-
BOOST_TEST_REQUIRE(obj2->GetGOT() == GO_Type::Envobject);
627+
BOOST_TEST(obj2->GetGOT() == GO_Type::Envobject);
618628

619629
MapPoint animalPos(20, 12);
620630
const auto figs = world.GetFigures(animalPos);
@@ -623,12 +633,12 @@ BOOST_AUTO_TEST_CASE(World)
623633
BOOST_TEST_REQUIRE(figs.size() == 1u);
624634
const noAnimal* animal = dynamic_cast<noAnimal*>(&*figs.begin());
625635
BOOST_TEST_REQUIRE(animal);
626-
BOOST_TEST_REQUIRE(animal->GetSpecies() == Species::Deer); //-V522
636+
BOOST_TEST(animal->GetSpecies() == Species::Deer); //-V522
627637
executeLua(boost::format("world:AddAnimal(%1%, %2%, SPEC_FOX)") % animalPos.x % animalPos.y);
628638
BOOST_TEST_REQUIRE(figs.size() == 2u);
629639
animal = dynamic_cast<noAnimal*>(&*(++figs.begin()));
630640
BOOST_TEST_REQUIRE(animal);
631-
BOOST_TEST_REQUIRE(animal->GetSpecies() == Species::Fox);
641+
BOOST_TEST(animal->GetSpecies() == Species::Fox);
632642
}
633643

634644
BOOST_AUTO_TEST_CASE(WorldEvents)

0 commit comments

Comments
 (0)