Optimize GetContainerItemInfo hook and bump to 1.4.11

- Reduce temporary table allocations in GetContainerItemInfo
- Preserve the client return signature safely
- Fall back to the original hook if the signature is unexpected
- Keep mailbox, Open All and send-mail behavior unchanged
- Bump version to 1.4.11
This commit is contained in:
2026-09-14 09:08:50 +00:00
parent e3d2dc1034
commit 83367549c4
4 changed files with 92 additions and 6 deletions
+81 -1
View File
@@ -8,7 +8,7 @@ local m = TurtleMail
local getn = table.getn
local function pack( ... ) return arg end
m.compat_version = "1.4.10"
m.compat_version = "1.4.11"
local DEFAULT_SENT_FILTERS = {
Money = 1,
@@ -910,3 +910,83 @@ do
end
end
end
-- Performance compatibility fix inspired by Otari98/TurtleMail: the upstream
-- GetContainerItemInfo hook builds a temporary table with pack()/unpack() on
-- every bag query. Bag and mailbox refreshes can call this hook very frequently,
-- creating avoidable garbage and occasional GC hitches. Detect the native return
-- count once after the normal PLAYER_LOGIN hook setup, then use a fixed-local
-- wrapper with no per-call temporary table. Exact return arity is preserved for
-- up to 12 values so extended/custom clients remain compatible; if detection is
-- inconclusive, the existing upstream hook is left untouched.
do
local original_player_login = m.PLAYER_LOGIN
local legacy_hook = m.hooks and m.hooks.GetContainerItemInfo or nil
local detected_return_count
local function count_returns( ... )
return arg.n or getn( arg )
end
local function detect_container_info_return_count()
local fn = m.orig and m.orig.GetContainerItemInfo
if type( fn ) ~= "function" then return nil end
-- Prefer an occupied inventory slot so clients that return no values for an
-- empty slot cannot make us detect the wrong arity.
if m.api.GetContainerNumSlots then
for bag = 0, 4 do
local slots = tonumber( m.api.GetContainerNumSlots( bag ) ) or 0
for slot = 1, slots do
local texture = fn( bag, slot )
if texture then
return count_returns( fn( bag, slot ) )
end
end
end
end
-- A normal character should always have at least one item, but retain a
-- conservative fallback for unusual test clients or empty inventories.
local count = count_returns( fn( 0, 1 ) )
if count and count > 0 then return count end
return nil
end
local function optimized_get_container_item_info( bag, slot )
local r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12 =
m.orig.GetContainerItemInfo( bag, slot )
if not r3 and m.sendmail_attached( bag, slot ) then
r3 = 1
end
if detected_return_count == 1 then return r1 end
if detected_return_count == 2 then return r1, r2 end
if detected_return_count == 3 then return r1, r2, r3 end
if detected_return_count == 4 then return r1, r2, r3, r4 end
if detected_return_count == 5 then return r1, r2, r3, r4, r5 end
if detected_return_count == 6 then return r1, r2, r3, r4, r5, r6 end
if detected_return_count == 7 then return r1, r2, r3, r4, r5, r6, r7 end
if detected_return_count == 8 then return r1, r2, r3, r4, r5, r6, r7, r8 end
if detected_return_count == 9 then return r1, r2, r3, r4, r5, r6, r7, r8, r9 end
if detected_return_count == 10 then return r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 end
if detected_return_count == 11 then return r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11 end
if detected_return_count == 12 then return r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12 end
-- Should not normally be reached; keep the previous behavior if a custom
-- client exposes an unexpected signature.
if legacy_hook then return legacy_hook( bag, slot ) end
return r1, r2, r3, r4, r5
end
function m.PLAYER_LOGIN()
if original_player_login then original_player_login() end
detected_return_count = detect_container_info_return_count()
if detected_return_count and detected_return_count >= 1 and detected_return_count <= 12 then
m.api.GetContainerItemInfo = optimized_get_container_item_info
end
end
end