Skip to content

Commit

Permalink
fix: eventcallbacks which returns a ReturnValue (#2532)
Browse files Browse the repository at this point in the history
  • Loading branch information
lamonato29 authored Jun 23, 2024
1 parent 7b53154 commit 3f6ac9a
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 9 deletions.
33 changes: 28 additions & 5 deletions data/scripts/eventcallbacks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Event callbacks are available for several categories of game entities, such as `
### These are the functions available to use

- `(bool)` `creatureOnChangeOutfit`
- `(bool)` `creatureOnAreaCombat`
- `(bool)` `creatureOnTargetCombat`
- `(ReturnValue)` `creatureOnAreaCombat`
- `(ReturnValue)` `creatureOnTargetCombat`
- `(void)` `creatureOnHear`
- `(void)` `creatureOnDrainHealth`
- `(bool)` `partyOnJoin`
Expand Down Expand Up @@ -66,7 +66,7 @@ local callback = EventCallback()

function callback.creatureOnAreaCombat(creature, tile, isAggressive)
-- custom behavior when a creature enters combat area
return true
return RETURNVALUE_NOERROR
end

callback:register()
Expand Down Expand Up @@ -131,21 +131,44 @@ Here is an example of a boolean event callback:
```lua
local callback = EventCallback()

function callback.playerOnMoveItem(player, item, count, fromPos, toPos, fromCylinder, toCylinder)
if item:getId() == ITEM_PARCEL then
--Custom behavior when the player moves a parcel.
return false
end
return true
end

callback:register()
```

### In this example, when a player moves an item, the function checks if the item is a parcel and apply a custom behaviour, returning false making it impossible to move, stopping the associated function on the C++ side.

## ReturnValue Event Callbacks

Some event callbacks are expected to return a enum value, in this case, the enum ReturnValue. If the return is different of RETURNVALUE_NOERROR, it will stop the execution of the next callbacks.

Here is an example of a ReturnValue event callback:

```lua
local callback = EventCallback()

function callback.creatureOnAreaCombat(creature, tile, isAggressive)
-- if the creature is not aggressive, stop the execution of the C++ function
if not isAggressive then
return false
return RETURNVALUE_NOTPOSSIBLE
end

-- custom behavior when an aggressive creature enters a combat area
return true
return RETURNVALUE_NOERROR
end

callback:register()
```

### In this example, when a non-aggressive creature enters a combat area, the creatureOnAreaCombat function returns false, stopping the associated function on the C++ side.


## Multiple Callbacks for the Same Event

You can define multiple callbacks for the same event type. This allows you to encapsulate different behaviors in separate callbacks, making your code more modular and easier to manage.
Expand Down
2 changes: 1 addition & 1 deletion data/scripts/eventcallbacks/creature/on_area_combat.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
local callback = EventCallback()

function callback.creatureOnAreaCombat(creature, tile, isAggressive)
return true
return RETURNVALUE_NOERROR
end

callback:register()
15 changes: 12 additions & 3 deletions src/creatures/combat/combat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "items/weapons/weapons.hpp"
#include "map/spectators.hpp"
#include "lib/metrics/metrics.hpp"
#include "lua/callbacks/event_callback.hpp"
#include "lua/callbacks/events_callbacks.hpp"

int32_t Combat::getLevelFormula(std::shared_ptr<Player> player, const std::shared_ptr<Spell> wheelSpell, const CombatDamage &damage) const {
if (!player) {
Expand Down Expand Up @@ -273,8 +275,11 @@ ReturnValue Combat::canDoCombat(std::shared_ptr<Creature> caster, std::shared_pt
}
}
}

return g_events().eventCreatureOnAreaCombat(caster, tile, aggressive);
ReturnValue ret = g_events().eventCreatureOnAreaCombat(caster, tile, aggressive);
if (ret == RETURNVALUE_NOERROR) {
ret = g_callbacks().checkCallbackWithReturnValue(EventCallback_t::creatureOnTargetCombat, &EventCallback::creatureOnAreaCombat, caster, tile, aggressive);
}
return ret;
}

bool Combat::isInPvpZone(std::shared_ptr<Creature> attacker, std::shared_ptr<Creature> target) {
Expand Down Expand Up @@ -409,7 +414,11 @@ ReturnValue Combat::canDoCombat(std::shared_ptr<Creature> attacker, std::shared_
}
}
}
return g_events().eventCreatureOnTargetCombat(attacker, target);
ReturnValue ret = g_events().eventCreatureOnTargetCombat(attacker, target);
if (ret == RETURNVALUE_NOERROR) {
ret = g_callbacks().checkCallbackWithReturnValue(EventCallback_t::creatureOnTargetCombat, &EventCallback::creatureOnTargetCombat, attacker, target);
}
return ret;
}

void Combat::setPlayerCombatValues(formulaType_t newFormulaType, double newMina, double newMinb, double newMaxa, double newMaxb) {
Expand Down
26 changes: 26 additions & 0 deletions src/lua/callbacks/events_callbacks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,32 @@ class EventsCallbacks {
}
}
}
/**
* @brief Checks if all registered callbacks of the specified event type succeed.
* @param eventType The type of event to check.
* @param callbackFunc Function pointer to the callback method.
* @param args Variadic arguments to pass to the callback function.
* @return ReturnValue enum.
*/
template <typename CallbackFunc, typename... Args>
ReturnValue checkCallbackWithReturnValue(EventCallback_t eventType, CallbackFunc callbackFunc, Args &&... args) {
ReturnValue res = RETURNVALUE_NOERROR;
for (const auto &callback : getCallbacksByType(eventType)) {
auto argsCopy = std::make_tuple(args...);
if (callback && callback->isLoadedCallback()) {
ReturnValue callbackResult = std::apply(
[&callback, &callbackFunc](auto &&... args) {
return ((*callback).*callbackFunc)(std::forward<decltype(args)>(args)...);
},
argsCopy
);
if (callbackResult != RETURNVALUE_NOERROR) {
return callbackResult;
}
}
}
return res;
}

/**
* @brief Checks if all registered callbacks of the specified event type succeed.
Expand Down

0 comments on commit 3f6ac9a

Please sign in to comment.