tibia-rme/source/lua/lua_api_map.cpp
Humberto Gontijo c136a75263
fix: make macOS build with modern sol2 and wxGL (#201)
Bug Fixes:
- Improved Lua scripting: Lua-visible nil is now consistent for missing/empty values across storage, JSON parsing, item/map/tile APIs, dialogs, app properties, and overlay hover.
- Improved macOS graphics reliability (OpenGL context/linking) and safer background/thread handling for streaming and SQLite bootstrap.
- Fixed client asset loading paths and improved SQLite migration input paths.

UI Improvements:
- Replaced “Missing …” modal dialogs with inline text boxes.
- Made “Client directory” editable; added macOS app-picker browse flow.

CI:
- Added compile-scoped macOS builds via reusable workflow and a new build-macos job.
2026-07-29 19:44:25 -03:00

189 lines
5.4 KiB
C++

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
// Remere's Map Editor is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Remere's Map Editor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////
#include "main.h"
#include "lua_api_map.h"
#include "../map.h"
#include "../basemap.h"
#include "../tile.h"
#include "../position.h"
#include "../gui.h"
#include "../editor.h"
namespace LuaAPI {
// Custom iterator for Map tiles to use in Lua for-loops
class LuaMapTileIterator {
public:
explicit LuaMapTileIterator(Map* map) :
map(map) {
if (map) {
iter = map->begin();
endIter = map->end();
}
}
std::tuple<sol::object, sol::object> next(sol::this_state ts) {
sol::state_view lua(ts);
if (!map) {
return std::make_tuple(sol::lua_nil, sol::lua_nil);
}
// Find next valid tile
while (iter != endIter) {
TileLocation* loc = *iter;
++iter;
if (loc && loc->get()) {
Tile* tile = loc->get();
return std::make_tuple(
sol::make_object(lua, tile),
sol::make_object(lua, tile)
);
}
}
return std::make_tuple(sol::lua_nil, sol::lua_nil);
}
private:
Map* map;
MapIterator iter;
MapIterator endIter;
bool started = false;
};
// Iterator for Spawns
class LuaMapSpawnIterator {
public:
explicit LuaMapSpawnIterator(Map* map) :
map(map) {
if (map) {
iter = map->spawnsMonster.begin();
endIter = map->spawnsMonster.end();
}
}
Tile* next() {
if (!map) {
return nullptr;
}
if (iter != endIter) {
Position pos = *iter;
++iter;
return map->getTile(pos);
}
return nullptr;
}
private:
Map* map;
SpawnNpcPositionList::const_iterator iter;
SpawnNpcPositionList::const_iterator endIter;
};
void registerMap(sol::state &lua) {
// Register the iterator type
lua.new_usertype<LuaMapTileIterator>("MapTileIterator", sol::no_constructor, "next", &LuaMapTileIterator::next);
// Register Spawn iterator
lua.new_usertype<LuaMapSpawnIterator>("MapSpawnIterator", sol::no_constructor, "next", &LuaMapSpawnIterator::next);
// Register Map usertype
lua.new_usertype<Map>(
"Map",
// No public constructor - maps are obtained from app.map
sol::no_constructor,
// Properties (read-only)
"name", sol::property(&Map::getName),
"filename", sol::property(&Map::getFilename),
"description", sol::property(&Map::getMapDescription),
"width", sol::property(&Map::getWidth),
"height", sol::property(&Map::getHeight),
"houseFilename", sol::property(&Map::getHouseFilename),
"spawnFilename", sol::property(&Map::getSpawnFilename),
"hasFile", sol::property(&Map::hasFile),
"hasChanged", sol::property(&Map::hasChanged),
"tileCount", sol::property([](Map* map) -> uint64_t {
return map ? map->getTileCount() : 0;
}),
// Get tile methods
"getTile", sol::overload([](Map* map, int x, int y, int z) -> Tile* { return map ? map->getTile(x, y, z) : nullptr; }, [](Map* map, const Position &pos) -> Tile* { return map ? map->getTile(pos) : nullptr; }),
// Get or create tile (for adding content to empty positions)
"getOrCreateTile", [](Map* map, sol::variadic_args va) -> Tile* {
if (!map){ return nullptr;
}
Position pos;
if (va.size() == 1 && va[0].is<Position>()) {
pos = va[0].as<Position>();
} else if (va.size() == 3) {
pos.x = va[0].as<int>();
pos.y = va[1].as<int>();
pos.z = va[2].as<int>();
} else {
throw sol::error("getOrCreateTile expects (x, y, z) or (Position)");
}
TileLocation* loc = map->createTileL(pos);
Tile* tile = loc->get();
if (!tile) {
tile = map->allocator(loc);
map->setTile(pos, tile);
}
return tile; },
// Tiles iterator - allows: for tile in map.tiles do ... end
"tiles", sol::property([](Map* map, sol::this_state ts) {
sol::state_view lua(ts);
// Return an iterator function
auto iterator = std::make_shared<LuaMapTileIterator>(map);
// Return the iterator function that Lua will call repeatedly
return sol::make_object(lua, [iterator](sol::this_state ts) {
return iterator->next(ts);
});
}),
// Spawns iterator - allows: for tile in map.spawns do ... end
"spawns", sol::property([](Map* map, sol::this_state ts) {
sol::state_view lua(ts);
auto iterator = std::make_shared<LuaMapSpawnIterator>(map);
return sol::make_object(lua, [iterator]() -> Tile* {
return iterator->next();
});
}),
// String representation
sol::meta_function::to_string, [](Map* map) {
if (!map){ return std::string("Map(invalid)");
}
return "Map(\"" + map->getName() + "\", " +
std::to_string(map->getWidth()) + "x" +
std::to_string(map->getHeight()) + ")"; }
);
}
} // namespace LuaAPI