Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix number of tool uses being off by 1..32767 (#11110)
  • Loading branch information
Wuzzy2 committed Oct 31, 2021
1 parent 38ba813 commit 6910c8d
Show file tree
Hide file tree
Showing 18 changed files with 228 additions and 70 deletions.
2 changes: 1 addition & 1 deletion builtin/game/item.lua
Expand Up @@ -613,7 +613,7 @@ function core.node_dig(pos, node, digger)
if wielded then
local wdef = wielded:get_definition()
local tp = wielded:get_tool_capabilities()
local dp = core.get_dig_params(def and def.groups, tp)
local dp = core.get_dig_params(def and def.groups, tp, wielded:get_wear())
if wdef and wdef.after_use then
wielded = wdef.after_use(wielded, digger, node, dp) or wielded
else
Expand Down
13 changes: 8 additions & 5 deletions doc/lua_api.txt
Expand Up @@ -1953,8 +1953,9 @@ to implement this.
### Uses (tools only)

Determines how many uses the tool has when it is used for digging a node,
of this group, of the maximum level. For lower leveled nodes, the use count
is multiplied by `3^leveldiff`.
of this group, of the maximum level. The maximum supported number of
uses is 65535. The special number 0 is used for infinite uses.
For lower leveled nodes, the use count is multiplied by `3^leveldiff`.
`leveldiff` is the difference of the tool's `maxlevel` `groupcaps` and the
node's `level` group. The node cannot be dug if `leveldiff` is less than zero.

Expand Down Expand Up @@ -3475,8 +3476,8 @@ Helper functions
* `minetest.pointed_thing_to_face_pos(placer, pointed_thing)`: returns a
position.
* returns the exact position on the surface of a pointed node
* `minetest.get_dig_params(groups, tool_capabilities)`: Simulates an item
that digs a node.
* `minetest.get_dig_params(groups, tool_capabilities [, wear])`:
Simulates an item that digs a node.
Returns a table with the following fields:
* `diggable`: `true` if node can be dug, `false` otherwise.
* `time`: Time it would take to dig the node.
Expand All @@ -3485,7 +3486,8 @@ Helper functions
Parameters:
* `groups`: Table of the node groups of the node that would be dug
* `tool_capabilities`: Tool capabilities table of the item
* `minetest.get_hit_params(groups, tool_capabilities [, time_from_last_punch])`:
* `wear`: Amount of wear the tool starts with (default: 0)
* `minetest.get_hit_params(groups, tool_capabilities [, time_from_last_punch [, wear]])`:
Simulates an item that punches an object.
Returns a table with the following fields:
* `hp`: How much damage the punch would cause.
Expand All @@ -3494,6 +3496,7 @@ Helper functions
* `groups`: Damage groups of the object
* `tool_capabilities`: Tool capabilities table of the item
* `time_from_last_punch`: time in seconds since last punch action
* `wear`: Amount of wear the item starts with (default: 0)



Expand Down
44 changes: 29 additions & 15 deletions games/devtest/mods/basetools/init.lua
Expand Up @@ -16,11 +16,11 @@ Tool types:
Tool materials:
* Dirt: dig nodes of rating 3, one use only
* Wood: dig nodes of rating 3
* Stone: dig nodes of rating 3 or 2
* Steel: dig nodes of rating 3, 2 or 1
* Mese: dig "everything" instantly
* n-Uses: can be used n times before breaking
]]

-- The hand
Expand Down Expand Up @@ -92,20 +92,6 @@ minetest.register_tool("basetools:pick_mese", {
-- Pickaxes: Dig cracky
--

-- This should break after only 1 use
minetest.register_tool("basetools:pick_dirt", {
description = "Dirt Pickaxe".."\n"..
"Digs cracky=3".."\n"..
"1 use only",
inventory_image = "basetools_dirtpick.png",
tool_capabilities = {
max_drop_level=0,
groupcaps={
cracky={times={[3]=2.00}, uses=1, maxlevel=0}
},
},
})

minetest.register_tool("basetools:pick_wood", {
description = "Wooden Pickaxe".."\n"..
"Digs cracky=3",
Expand Down Expand Up @@ -348,3 +334,31 @@ minetest.register_tool("basetools:dagger_steel", {
damage_groups = {fleshy=2},
}
})

-- Test tool uses and punch_attack_uses
local uses = { 1, 2, 3, 5, 10, 50, 100, 1000, 10000, 65535 }
for i=1, #uses do
local u = uses[i]
local color = string.format("#FF00%02X", math.floor(((i-1)/#uses) * 255))
minetest.register_tool("basetools:pick_uses_"..string.format("%05d", u), {
description = u.."-Uses Pickaxe".."\n"..
"Digs cracky=3",
inventory_image = "basetools_steelpick.png^[colorize:"..color..":127",
tool_capabilities = {
max_drop_level=0,
groupcaps={
cracky={times={[3]=0.1, [2]=0.2, [1]=0.3}, uses=u, maxlevel=0}
},
},
})

minetest.register_tool("basetools:sword_uses_"..string.format("%05d", u), {
description = u.."-Uses Sword".."\n"..
"Damage: fleshy=1",
inventory_image = "basetools_woodsword.png^[colorize:"..color..":127",
tool_capabilities = {
damage_groups = {fleshy=1},
punch_attack_uses = u,
},
})
end
Binary file not shown.
53 changes: 53 additions & 0 deletions games/devtest/mods/util_commands/init.lua
Expand Up @@ -114,6 +114,59 @@ minetest.register_chatcommand("detach", {
end,
})

minetest.register_chatcommand("use_tool", {
params = "(dig <group> <leveldiff>) | (hit <damage_group> <time_from_last_punch>) [<uses>]",
description = "Apply tool wear a number of times, as if it were used for digging",
func = function(name, param)
local player = minetest.get_player_by_name(name)
if not player then
return false, "No player."
end
local mode, group, level, uses = string.match(param, "([a-z]+) ([a-z0-9]+) (-?%d+) (%d+)")
if not mode then
mode, group, level = string.match(param, "([a-z]+) ([a-z0-9]+) (-?%d+)")
uses = 1
end
if not mode or not group or not level then
return false
end
if mode ~= "dig" and mode ~= "hit" then
return false
end
local tool = player:get_wielded_item()
local caps = tool:get_tool_capabilities()
if not caps or tool:get_count() == 0 then
return false, "No tool in hand."
end
local actual_uses = 0
for u=1, uses do
local wear = tool:get_wear()
local dp
if mode == "dig" then
dp = minetest.get_dig_params({[group]=3, level=level}, caps, wear)
else
dp = minetest.get_hit_params({[group]=100}, caps, level, wear)
end
tool:add_wear(dp.wear)
actual_uses = actual_uses + 1
if tool:get_count() == 0 then
break
end
end
player:set_wielded_item(tool)
if tool:get_count() == 0 then
return true, string.format("Tool used %d time(s). "..
"The tool broke after %d use(s).", uses, actual_uses)
else
local wear = tool:get_wear()
return true, string.format("Tool used %d time(s). "..
"Final wear=%d", uses, wear)
end
end,
})



-- Use this to test waypoint capabilities
minetest.register_chatcommand("test_waypoints", {
params = "[change_immediate]",
Expand Down
3 changes: 2 additions & 1 deletion src/client/content_cao.cpp
Expand Up @@ -1870,7 +1870,8 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
m_armor_groups,
toolcap,
punchitem,
time_from_last_punch);
time_from_last_punch,
punchitem->wear);

if(result.did_punch && result.damage != 0)
{
Expand Down
3 changes: 2 additions & 1 deletion src/client/game.cpp
Expand Up @@ -3619,7 +3619,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
// cheat detection.
// Get digging parameters
DigParams params = getDigParams(nodedef_manager->get(n).groups,
&selected_item.getToolCapabilities(itemdef_manager));
&selected_item.getToolCapabilities(itemdef_manager),
selected_item.wear);

// If can't dig, try hand
if (!params.diggable) {
Expand Down
7 changes: 4 additions & 3 deletions src/network/serverpackethandler.cpp
Expand Up @@ -1119,8 +1119,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
float time_from_last_punch =
playersao->resetTimeFromLastPunch();

u16 wear = pointed_object->punch(dir, &toolcap, playersao,
time_from_last_punch);
u32 wear = pointed_object->punch(dir, &toolcap, playersao,
time_from_last_punch, tool_item.wear);

// Callback may have changed item, so get it again
playersao->getWieldedItem(&selected_item);
Expand Down Expand Up @@ -1173,7 +1173,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)

// Get diggability and expected digging time
DigParams params = getDigParams(m_nodedef->get(n).groups,
&selected_item.getToolCapabilities(m_itemdef));
&selected_item.getToolCapabilities(m_itemdef),
selected_item.wear);
// If can't dig, try hand
if (!params.diggable) {
params = getDigParams(m_nodedef->get(n).groups,
Expand Down
2 changes: 1 addition & 1 deletion src/script/lua_api/l_object.cpp
Expand Up @@ -174,7 +174,7 @@ int ObjectRef::l_punch(lua_State *L)
v3f dir = readParam<v3f>(L, 5, sao->getBasePosition() - puncher->getBasePosition());
dir.normalize();

u16 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch);
u32 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch);
lua_pushnumber(L, wear);

return 1;
Expand Down
19 changes: 12 additions & 7 deletions src/script/lua_api/l_util.cpp
Expand Up @@ -160,28 +160,33 @@ int ModApiUtil::l_write_json(lua_State *L)
return 1;
}

// get_dig_params(groups, tool_capabilities)
// get_dig_params(groups, tool_capabilities[, wear])
int ModApiUtil::l_get_dig_params(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ItemGroupList groups;
read_groups(L, 1, groups);
ToolCapabilities tp = read_tool_capabilities(L, 2);
push_dig_params(L, getDigParams(groups, &tp));
if (lua_isnoneornil(L, 3)) {
push_dig_params(L, getDigParams(groups, &tp));
} else {
u16 wear = readParam<int>(L, 3);
push_dig_params(L, getDigParams(groups, &tp, wear));
}
return 1;
}

// get_hit_params(groups, tool_capabilities[, time_from_last_punch])
// get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]])
int ModApiUtil::l_get_hit_params(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
std::unordered_map<std::string, int> groups;
read_groups(L, 1, groups);
ToolCapabilities tp = read_tool_capabilities(L, 2);
if(lua_isnoneornil(L, 3))
push_hit_params(L, getHitParams(groups, &tp));
else
push_hit_params(L, getHitParams(groups, &tp, readParam<float>(L, 3)));
float time_from_last_punch = readParam<float>(L, 3, 1000000);
int wear = readParam<int>(L, 4, 0);
push_hit_params(L, getHitParams(groups, &tp,
time_from_last_punch, wear));
return 1;
}

Expand Down
4 changes: 2 additions & 2 deletions src/script/lua_api/l_util.h
Expand Up @@ -50,10 +50,10 @@ class ModApiUtil : public ModApiBase
// write_json(data[, styled])
static int l_write_json(lua_State *L);

// get_dig_params(groups, tool_capabilities[, time_from_last_punch])
// get_dig_params(groups, tool_capabilities[, wear])
static int l_get_dig_params(lua_State *L);

// get_hit_params(groups, tool_capabilities[, time_from_last_punch])
// get_hit_params(groups, tool_capabilities[, time_from_last_punch[, wear]])
static int l_get_hit_params(lua_State *L);

// check_password_entry(name, entry, password)
Expand Down
8 changes: 5 additions & 3 deletions src/server/luaentity_sao.cpp
Expand Up @@ -305,10 +305,11 @@ void LuaEntitySAO::getStaticData(std::string *result) const
*result = os.str();
}

u16 LuaEntitySAO::punch(v3f dir,
u32 LuaEntitySAO::punch(v3f dir,
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
float time_from_last_punch)
float time_from_last_punch,
u16 initial_wear)
{
if (!m_registered) {
// Delete unknown LuaEntities when punched
Expand All @@ -326,7 +327,8 @@ u16 LuaEntitySAO::punch(v3f dir,
m_armor_groups,
toolcap,
&tool_item,
time_from_last_punch);
time_from_last_punch,
initial_wear);

bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher,
time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0);
Expand Down
5 changes: 3 additions & 2 deletions src/server/luaentity_sao.h
Expand Up @@ -44,9 +44,10 @@ class LuaEntitySAO : public UnitSAO
bool isStaticAllowed() const { return m_prop.static_save; }
bool shouldUnload() const { return true; }
void getStaticData(std::string *result) const;
u16 punch(v3f dir, const ToolCapabilities *toolcap = nullptr,
u32 punch(v3f dir, const ToolCapabilities *toolcap = nullptr,
ServerActiveObject *puncher = nullptr,
float time_from_last_punch = 1000000.0f);
float time_from_last_punch = 1000000.0f,
u16 initial_wear = 0);
void rightClick(ServerActiveObject *clicker);
void setPos(const v3f &pos);
void moveTo(v3f pos, bool continuous);
Expand Down
7 changes: 4 additions & 3 deletions src/server/player_sao.cpp
Expand Up @@ -409,10 +409,11 @@ void PlayerSAO::setLookPitchAndSend(const float pitch)
m_env->getGameDef()->SendMovePlayer(m_peer_id);
}

u16 PlayerSAO::punch(v3f dir,
u32 PlayerSAO::punch(v3f dir,
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
float time_from_last_punch)
float time_from_last_punch,
u16 initial_wear)
{
if (!toolcap)
return 0;
Expand All @@ -430,7 +431,7 @@ u16 PlayerSAO::punch(v3f dir,

s32 old_hp = getHP();
HitParams hitparams = getHitParams(m_armor_groups, toolcap,
time_from_last_punch);
time_from_last_punch, initial_wear);

PlayerSAO *playersao = m_player->getPlayerSAO();

Expand Down
4 changes: 2 additions & 2 deletions src/server/player_sao.h
Expand Up @@ -109,8 +109,8 @@ class PlayerSAO : public UnitSAO
Interaction interface
*/

u16 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher,
float time_from_last_punch);
u32 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher,
float time_from_last_punch, u16 initial_wear = 0);
void rightClick(ServerActiveObject *clicker);
void setHP(s32 hp, const PlayerHPChangeReason &reason) override
{
Expand Down
7 changes: 4 additions & 3 deletions src/server/serveractiveobject.h
Expand Up @@ -145,11 +145,12 @@ class ServerActiveObject : public ActiveObject
virtual bool shouldUnload() const
{ return true; }

// Returns tool wear
virtual u16 punch(v3f dir,
// Returns added tool wear
virtual u32 punch(v3f dir,
const ToolCapabilities *toolcap = nullptr,
ServerActiveObject *puncher = nullptr,
float time_from_last_punch = 1000000.0f)
float time_from_last_punch = 1000000.0f,
u16 initial_wear = 0)
{ return 0; }
virtual void rightClick(ServerActiveObject *clicker)
{}
Expand Down

0 comments on commit 6910c8d

Please sign in to comment.