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:
+81
-1
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user