Skip to content

Commit

Permalink
Load actions.xml in Lua
Browse files Browse the repository at this point in the history
  • Loading branch information
ranisalt committed Nov 6, 2024
1 parent 8e9f360 commit 0637efe
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 193 deletions.
118 changes: 118 additions & 0 deletions data/scripts/actions/actions_xml.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
-- If you don't intend to use actions.xml, you can delete this file.
local function getIds(singleIdKey, fromIdKey, toIdKey)
return function(node)
local itemid = node:attribute(singleIdKey)
if itemid then
local ids = {}
for _, itemid in ipairs(itemid:split(";")) do ids[#ids + 1] = tonumber(itemid) end
return ids
end

local fromid = tonumber(node:attribute(fromIdKey))
if not fromid then return {} end

local toid = tonumber(node:attribute(toIdKey))
if not toid then
io.write("[Error] Missing attribute " .. toIdKey .. ", check data/actions/actions.xml.\n")
return {}
end

local ids = {}
for id = fromid, toid do ids[#ids + 1] = id end
return ids
end
end

local getItemIds = getIds("itemid", "fromid", "toid")
local getActionIds = getIds("actionid", "fromaid", "toaid")
local getUniqueIds = getIds("uniqueid", "fromuid", "touid")

local function configureActionEvent(node)
local action = Action()

local itemIds = getItemIds(node)
if #itemIds == 0 then
local uniqueIds = getUniqueIds(node)

if #uniqueIds == 0 then
local actionIds = getActionIds(node)

if #actionIds == 0 then
io.write("[Error] Missing attribute itemid or uniqueid or actionid, check 'data/actions/actions.xml'.\n")
return nil
end

action:aid(unpack(actionIds))
else
action:uid(unpack(uniqueIds))
end
else
action:id(unpack(itemIds))
end

local allowFarUse = tobool(node:attribute("allowfaruse"))
if allowFarUse ~= nil then action:allowFarUse(allowFarUse) end

local blockWalls = tobool(node:attribute("blockwalls"))
if blockWalls ~= nil then action:blockWalls(blockWalls) end

local checkFloor = tobool(node:attribute("checkfloor"))
if checkFloor ~= nil then action:checkFloor(checkFloor) end

local function_ = node:attribute("function")
local script = node:attribute("script")
if not function_ and not script then
io.write("[Warning] function or script attribute missing for action '" .. name .. "'.\n")
return nil
end

if function_ then
if function_ ~= "market" then
io.write("[Error] Invalid function attribute, check 'data/actions/actions.xml'.\n")
return nil
end

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey) return player:sendEnterMarket() end
end

if script then
local scriptFile = "data/actions/scripts/" .. script
dofile(scriptFile)
if not onUse then
io.write("[Error] Can not load action script, check '" .. scriptFile .. "' for a missing onUse callback\n")
return nil
end

action:onUse(onUse)

-- let it be garbage collected
onUse = nil
end

return action
end

local event = GlobalEvent("load actions.xml")

function event.onStartup()
local doc = XMLDocument("data/actions/actions.xml")
if not doc then
io.write("[Warning - GlobalEvent::onStartup] Could not load data/actions/actions.xml.\n")
return true
end

local actions = doc:child("actions")

io.write(">> Loading legacy XML actions from data/actions/actions.xml...\n")
local loaded, start = 0, os.mtime()
for node in actions:children() do
local action = configureActionEvent(node)
if action then
action:register()
loaded = loaded + 1
end
end
io.write(">> Loaded " .. loaded .. " actions in " .. os.mtime() - start .. "ms.\n")
end

event:register()
186 changes: 0 additions & 186 deletions src/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,143 +51,6 @@ Event_ptr Actions::getEvent(const std::string& nodeName)
return Event_ptr(new Action(&scriptInterface));
}

bool Actions::registerEvent(Event_ptr event, const pugi::xml_node& node)
{
Action_ptr action{static_cast<Action*>(event.release())}; // event is guaranteed to be an Action

pugi::xml_attribute attr;
if ((attr = node.attribute("itemid"))) {
std::vector<int32_t> idList = vectorAtoi(explodeString(attr.as_string(), ";"));
bool success = true;

for (const auto& id : idList) {
auto result = useItemMap.emplace(id, std::move(*action));
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << id
<< std::endl;
success = false;
}
}

return success;
} else if ((attr = node.attribute("fromid"))) {
pugi::xml_attribute toIdAttribute = node.attribute("toid");
if (!toIdAttribute) {
std::cout << "[Warning - Actions::registerEvent] Missing toid in fromid: " << attr.as_string() << std::endl;
return false;
}

uint16_t fromId = pugi::cast<uint16_t>(attr.value());
uint16_t iterId = fromId;
uint16_t toId = pugi::cast<uint16_t>(toIdAttribute.value());

auto result = useItemMap.emplace(iterId, *action);
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << iterId
<< " in fromid: " << fromId << ", toid: " << toId << std::endl;
}

bool success = result.second;
while (++iterId <= toId) {
result = useItemMap.emplace(iterId, *action);
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << iterId
<< " in fromid: " << fromId << ", toid: " << toId << std::endl;
continue;
}
success = true;
}
return success;
} else if ((attr = node.attribute("uniqueid"))) {
std::vector<int32_t> uidList = vectorAtoi(explodeString(attr.as_string(), ";"));
bool success = true;

for (const auto& uid : uidList) {
auto result = uniqueItemMap.emplace(uid, std::move(*action));
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with uniqueid: " << uid
<< std::endl;
success = false;
}
}

return success;
} else if ((attr = node.attribute("fromuid"))) {
pugi::xml_attribute toUidAttribute = node.attribute("touid");
if (!toUidAttribute) {
std::cout << "[Warning - Actions::registerEvent] Missing touid in fromuid: " << attr.as_string()
<< std::endl;
return false;
}

uint16_t fromUid = pugi::cast<uint16_t>(attr.value());
uint16_t iterUid = fromUid;
uint16_t toUid = pugi::cast<uint16_t>(toUidAttribute.value());

auto result = uniqueItemMap.emplace(iterUid, *action);
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with unique id: " << iterUid
<< " in fromuid: " << fromUid << ", touid: " << toUid << std::endl;
}

bool success = result.second;
while (++iterUid <= toUid) {
result = uniqueItemMap.emplace(iterUid, *action);
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with unique id: " << iterUid
<< " in fromuid: " << fromUid << ", touid: " << toUid << std::endl;
continue;
}
success = true;
}
return success;
} else if ((attr = node.attribute("actionid"))) {
std::vector<int32_t> aidList = vectorAtoi(explodeString(attr.as_string(), ";"));
bool success = true;

for (const auto& aid : aidList) {
auto result = actionItemMap.emplace(aid, std::move(*action));
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with actionid: " << aid
<< std::endl;
success = false;
}
}

return success;
} else if ((attr = node.attribute("fromaid"))) {
pugi::xml_attribute toAidAttribute = node.attribute("toaid");
if (!toAidAttribute) {
std::cout << "[Warning - Actions::registerEvent] Missing toaid in fromaid: " << attr.as_string()
<< std::endl;
return false;
}

uint16_t fromAid = pugi::cast<uint16_t>(attr.value());
uint16_t iterAid = fromAid;
uint16_t toAid = pugi::cast<uint16_t>(toAidAttribute.value());

auto result = actionItemMap.emplace(iterAid, *action);
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with action id: " << iterAid
<< " in fromaid: " << fromAid << ", toaid: " << toAid << std::endl;
}

bool success = result.second;
while (++iterAid <= toAid) {
result = actionItemMap.emplace(iterAid, *action);
if (!result.second) {
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with action id: " << iterAid
<< " in fromaid: " << fromAid << ", toaid: " << toAid << std::endl;
continue;
}
success = true;
}
return success;
}
return false;
}

bool Actions::registerLuaEvent(Action* event)
{
Action_ptr action{event};
Expand Down Expand Up @@ -488,55 +351,6 @@ Action::Action(LuaScriptInterface* interface) :
Event(interface), function(nullptr), allowFarUse(false), checkFloor(true), checkLineOfSight(true)
{}

bool Action::configureEvent(const pugi::xml_node& node)
{
pugi::xml_attribute allowFarUseAttr = node.attribute("allowfaruse");
if (allowFarUseAttr) {
allowFarUse = allowFarUseAttr.as_bool();
}

pugi::xml_attribute blockWallsAttr = node.attribute("blockwalls");
if (blockWallsAttr) {
checkLineOfSight = blockWallsAttr.as_bool();
}

pugi::xml_attribute checkFloorAttr = node.attribute("checkfloor");
if (checkFloorAttr) {
checkFloor = checkFloorAttr.as_bool();
}

return true;
}

namespace {

bool enterMarket(Player* player, Item*, const Position&, Thing*, const Position&, bool)
{
player->sendMarketEnter();
return true;
}

} // namespace

bool Action::loadFunction(const pugi::xml_attribute& attr, bool isScripted)
{
const char* functionName = attr.as_string();
if (caseInsensitiveEqual(functionName, "market")) {
function = enterMarket;
} else {
if (!isScripted) {
std::cout << "[Warning - Action::loadFunction] Function \"" << functionName << "\" does not exist."
<< std::endl;
return false;
}
}

if (!isScripted) {
scripted = false;
}
return true;
}

ReturnValue Action::canExecuteAction(const Player* player, const Position& toPos)
{
if (allowFarUse) {
Expand Down
5 changes: 2 additions & 3 deletions src/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class Action : public Event
public:
explicit Action(LuaScriptInterface* interface);

bool configureEvent(const pugi::xml_node& node) override;
bool loadFunction(const pugi::xml_attribute& attr, bool isScripted) override;
bool configureEvent(const pugi::xml_node&) override { return false; }

// scripting
virtual bool executeUse(Player* player, Item* item, const Position& fromPosition, Thing* target,
Expand Down Expand Up @@ -89,7 +88,7 @@ class Actions final : public BaseEvents
LuaScriptInterface& getScriptInterface() override;
std::string_view getScriptBaseName() const override { return "actions"; }
Event_ptr getEvent(const std::string& nodeName) override;
bool registerEvent(Event_ptr event, const pugi::xml_node& node) override;
bool registerEvent(Event_ptr, const pugi::xml_node&) override { return false; }

using ActionUseMap = std::map<uint16_t, Action>;
ActionUseMap useItemMap;
Expand Down
15 changes: 15 additions & 0 deletions src/luascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2955,6 +2955,8 @@ void LuaScriptInterface::registerFunctions()

registerMethod(L, "Player", "sendResourceBalance", LuaScriptInterface::luaPlayerSendResourceBalance);

registerMethod(L, "Player", "sendEnterMarket", LuaScriptInterface::luaPlayerSendEnterMarket);

// Monster
registerClass(L, "Monster", "Creature", LuaScriptInterface::luaMonsterCreate);
registerMetaMethod(L, "Monster", "__eq", LuaScriptInterface::luaUserdataCompare);
Expand Down Expand Up @@ -11356,6 +11358,19 @@ int LuaScriptInterface::luaPlayerSendResourceBalance(lua_State* L)
return 1;
}

int LuaScriptInterface::luaPlayerSendEnterMarket(lua_State* L)
{
// player:sendEnterMarket()
Player* player = tfs::lua::getUserdata<Player>(L, 1);
if (player) {
player->sendMarketEnter();
tfs::lua::pushBoolean(L, true);
} else {
lua_pushnil(L);
}
return 1;
}

// Monster
int LuaScriptInterface::luaMonsterCreate(lua_State* L)
{
Expand Down
1 change: 1 addition & 0 deletions src/luascript.h
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ class LuaScriptInterface
static int luaPlayerSetClientLowLevelBonusDisplay(lua_State* L);

static int luaPlayerSendResourceBalance(lua_State* L);
static int luaPlayerSendEnterMarket(lua_State* L);

// Monster
static int luaMonsterCreate(lua_State* L);
Expand Down
4 changes: 0 additions & 4 deletions src/scriptmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ bool ScriptingManager::loadScriptSystems()
}

g_actions = new Actions();
if (!g_actions->loadFromXml()) {
std::cout << "> ERROR: Unable to load actions!" << std::endl;
return false;
}

g_talkActions = new TalkActions();
if (!g_talkActions->loadFromXml()) {
Expand Down

0 comments on commit 0637efe

Please sign in to comment.