Skip to content

Commit 848eb78

Browse files
committed
cleanup
1 parent 36f5717 commit 848eb78

1 file changed

Lines changed: 106 additions & 90 deletions

File tree

Assets/Lua/Doom/doom.misc.lua

Lines changed: 106 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ MAXIMUM_INTERCEPTS = 128
3232
-- initially 12 but we have 64-bit architecture + pointer alignment.
3333
-- when intercept overflow is emulated, the size of 12 is still used internally
3434
-- to corrupt the same target values as in vanilla
35-
INTERCEPT_SIZE = 16
35+
INTERCEPT_SIZE = 16
36+
INTERCEPT_SIZE_VANILLA = 12
3637

3738
--#endregion
3839

@@ -129,6 +130,20 @@ end
129130
---@field name string Full name of the vanilla variable we're corrupting
130131
---@field value integer Value that the vanilla variable has at the moment
131132

133+
---@class (exact) intercept_overrun_info
134+
---@field offset string
135+
---@field value string
136+
---@field variable string
137+
138+
--- `intercept_t` plus some extra info for the user.
139+
---@class intercept_info
140+
---@field frac string `frac` is the most complicated part of `intercept_t` struct. When an intercept is checked, traceline length is normalized to [0, 1], and the point where it crosses something denotes the fraction of that length, meaning how soon the traceline hits it. Negative value means behind the origin, and more than 1 means outside the trace range. Then for all the intercepts in the list, those fractions are compared and the shortest one wins. So to manipulate what value is used for memory corruption, we just need to adjust the distance between trace origin and something it hits, keeping in mind intercept at which index/offset matches our target address. Internally represented as 32-bit integer, basically means percentage of traceline length if we multiply the value by 100.
141+
---@field isaline string Whether intercept is with a line or a thing. Internally represented as 32-bit integer.
142+
---@field offset string How far into corrupted memory we are. Informational addition.
143+
---@field pointer integer `d` field of `intercept_t`. Not super relevant outside vanilla executable. Current codebase makes it a 64-bit integer and when intercept overruns are emulated it's just truncated to 32 bits.
144+
---@field block integer Blockmap block where the intercept happened.
145+
---@field id integer `iLineID` or `index`, depending on `isaline`.
146+
132147
--- Used for specific things like point coordinates, but also for anything that can have x/y values
133148
---@class (exact) vertex
134149
---@field x number
@@ -217,8 +232,6 @@ LastBMEnd = nil
217232
CurrentPrompt = nil
218233
---@type confirmation
219234
Confirmation = nil
220-
---@type intercept_overrun[]
221-
InterceptOverrun = {}
222235
---@type intercepts_state
223236
InterceptsInfo = InterceptsState.NONE
224237
---@type line_log_type
@@ -256,9 +269,13 @@ Config = {}
256269
PRandomInfo = {}
257270
DivLines = {}
258271
MapBlocks = {}
259-
Intercepts = {}
260-
InterceptsOverruns = {}
261272
GUITexts = {}
273+
274+
--- Intercept objects per block
275+
---@type table<number, intercept_info[]>
276+
Intercepts = {}
277+
---@type table<number, intercept_overrun_info[]>
278+
InterceptsOverruns = {}
262279
-- map object positions bounds
263280
OB = {
264281
top = math.maxinteger,
@@ -328,9 +345,10 @@ end
328345

329346
--- After intercept overflow, shows which variables got corrupted and their resulting values. The list is consctructed on the fly so we could read from memory directly.
330347
---@param limit integer
331-
---@return intercept_overrun[] # Table index indicates offset, usable for comparing with offsets of individual intercepts after overflow
348+
---@return intercept_overrun_info[] # Table index indicates offset, usable for comparing with offsets of individual intercepts after overflow
332349
local function fetch_intercept_overruns(limit)
333-
local ret = {}
350+
---@type intercept_overrun_info[]
351+
local ret = {}
334352
---@type intercept_overrun[]
335353
local list = {
336354
[ 12] = { name = "line_opening.lowfloor", value = Globals.line_opening.lowfloor },
@@ -365,11 +383,10 @@ local function fetch_intercept_overruns(limit)
365383
}
366384

367385
-- walk through the list to check how far corruption went for this particular intercept
368-
-- TODO: probably check based on farthest affected offset,
369-
-- since intercepts are 12 bytes in size and overruns have different sizes
370386
for i = 0, 230 do
371387
local source = list[i]
372388
if source and i <= limit then
389+
---@type intercept_overrun_info
373390
local item = {
374391
offset = string.format("%d bytes", i),
375392
value = string.format("0x%X", source.value & 0xffffffff),
@@ -382,7 +399,84 @@ local function fetch_intercept_overruns(limit)
382399
return ret
383400
end
384401

385-
--- Very complicated thing that handles tracelines display and intercepts display and logging. Installs the hook while anything is enabled. When an intercept is added by the game, we read `trace` from memory which is the thing creating intercepts, and we add all those tracelines to a table that we then display once per frame. When the amount of intercepts per block exceeds user defined value, or if the overflow has happened, we print that. Upon overflow we also let the user dump all their contents and info to console.
402+
--- When the amount of intercepts per block exceeds user defined value, or if the overflow has happened, we print that. Upon overflow we also let the user dump all their contents and info to console.
403+
---@param block integer
404+
local function intercept_logger(block)
405+
if InterceptLog then
406+
local origin = Globals.intercepts
407+
local count = math.floor((InterceptPtr - origin) / INTERCEPT_SIZE)
408+
409+
if count > InterceptLimit then
410+
local text
411+
local i = 1 -- intercept #0 gets printed last so we start with 1 instead
412+
413+
if count > MAXIMUM_INTERCEPTS then
414+
text = string.format(
415+
"Frame %d, block %d, %d intercepts INTERCEPT OVERFLOW",
416+
Framecount, block, count
417+
)
418+
block = -block -- custom way to indicate overflow
419+
InterceptsInfo = InterceptsState.OVERFLOW
420+
421+
if not InterceptsOverruns[math.abs(block)] then
422+
InterceptsOverruns[math.abs(block)] = {}
423+
end
424+
InterceptsOverruns[math.abs(block)] = fetch_intercept_overruns(
425+
(count - MAXIMUM_INTERCEPTS)
426+
* INTERCEPT_SIZE_VANILLA
427+
+ INTERCEPT_SIZE_VANILLA
428+
)
429+
430+
client.pause()
431+
else
432+
text = string.format(
433+
"Frame %d, block %d, %d intercepts",
434+
Framecount, block, count
435+
)
436+
InterceptsInfo = InterceptsState.PRINT
437+
end
438+
439+
print(text)
440+
441+
if not Intercepts[math.abs(block)] then
442+
Intercepts[math.abs(block)] = {}
443+
end
444+
445+
for address = origin, InterceptPtr - INTERCEPT_SIZE, INTERCEPT_SIZE do
446+
local intercept = structs.intercept.from_pointer(address)
447+
---@type intercept_info
448+
local object = {
449+
frac = string.format("0x%08x", intercept.frac),
450+
isaline = string.format("0x%08x", intercept.isaline),
451+
offset = string.format("%d bytes",
452+
(i-1-MAXIMUM_INTERCEPTS)
453+
*INTERCEPT_SIZE_VANILLA),
454+
pointer = intercept.d,
455+
block = math.abs(block)
456+
}
457+
458+
if tonumber(intercept.isaline) == 1 then
459+
object.id = structs.line.from_pointer(object.pointer).iLineID
460+
else
461+
object.id = structs.mobj.from_pointer(object.pointer).index
462+
end
463+
464+
object.pointer = string.format("0x%08X", object.pointer)
465+
466+
-- we insert the same interecepts over and over for every new call,
467+
-- because we can't know when they'll end,
468+
-- and we may be asked to do this before it actually overflows.
469+
-- so we can't just sit and wait for an overflow and only
470+
-- then build the list. there won't be thousands of them anyway.
471+
Intercepts[math.abs(block)][i] = object
472+
473+
i = i + 1
474+
end
475+
end
476+
end
477+
end
478+
479+
--- Very complicated thing that handles tracelines display and intercepts display and logging. Installs the hook while anything is enabled. When an intercept is added by the game, we read `trace` from memory which is the thing creating intercepts, and we add all those tracelines to a table that we then display once per frame.
386480
local function hook_intercepts()
387481
local name = "Intercepts"
388482

@@ -405,86 +499,8 @@ local function hook_intercepts()
405499
if intercept_p ~= InterceptPtr then
406500
-- new intercept was just added
407501
InterceptPtr = intercept_p
408-
409-
if InterceptLog then
410-
local origin = Globals.intercepts
411-
local count = math.floor((InterceptPtr - origin) / INTERCEPT_SIZE)
412-
413-
if count > InterceptLimit then
414-
local text
415-
local i = 1 -- intercept #0 gets printed last so we start with 1 instead
416-
417-
if count > MAXIMUM_INTERCEPTS then
418-
text = string.format(
419-
"Frame %d, block %d, %d intercepts INTERCEPT OVERFLOW",
420-
Framecount, block, count
421-
)
422-
block = -block -- custom way to indicate overflow
423-
InterceptsInfo = InterceptsState.OVERFLOW
424-
425-
if not InterceptsOverruns[math.abs(block)] then
426-
InterceptsOverruns[math.abs(block)] = {}
427-
end
428-
InterceptsOverruns[math.abs(block)] = fetch_intercept_overruns(
429-
(count - MAXIMUM_INTERCEPTS) * 12
430-
)
431-
432-
client.pause()
433-
else
434-
text = string.format(
435-
"Frame %d, block %d, %d intercepts",
436-
Framecount, block, count
437-
)
438-
InterceptsInfo = InterceptsState.PRINT
439-
end
440-
441-
print(text)
442-
443-
if not Intercepts[math.abs(block)] then
444-
Intercepts[math.abs(block)] = {}
445-
end
446-
447-
for address = origin, InterceptPtr - INTERCEPT_SIZE, INTERCEPT_SIZE do
448-
local intercept = structs.intercept.from_pointer(address)
449-
local object = {
450-
-- frac is the most complicated part of intercept struct.
451-
-- when intercept is checked, traceline length is normalized
452-
-- to [0, 1], and the point where it crosses something
453-
-- denotes the fraction of that length, meaning how soon the
454-
-- traceline hits it. negative value means behind the origin,
455-
-- and more than 1 means outside the trace range.
456-
-- then for all the intercepts in the list, those fractions
457-
-- are compared and the shortest one wins.
458-
-- so to manipulate what value is used for memory corruption,
459-
-- we just need to adjust the distance between trace origin
460-
-- and something it hits, keeping in mind intercept at which
461-
-- index/offset matches our target address.
462-
frac = string.format("0x%08x", intercept.frac),
463-
isaline = string.format("0x%08x", intercept.isaline),
464-
offset = string.format("%d bytes",(i-1-MAXIMUM_INTERCEPTS)*12),
465-
pointer = intercept.d,
466-
block = math.abs(block)
467-
}
468-
469-
if tonumber(intercept.isaline) == 1 then
470-
object.id = structs.line.from_pointer(object.pointer).iLineID
471-
else
472-
object.id = structs.mobj.from_pointer(object.pointer).index
473-
end
474-
475-
object.pointer = string.format("0x%08X", object.pointer)
476-
477-
-- we insert the same interecepts over and over for every new call,
478-
-- because we can't know when they'll end,
479-
-- and we may be asked to do this before it actually overflows.
480-
-- so we can't just sit and wait for an overflow and only
481-
-- then build the list. there won't be thousands of them anyway.
482-
Intercepts[math.abs(block)][i] = object
483-
484-
i = i + 1
485-
end
486-
end
487-
end
502+
503+
intercept_logger(block)
488504

489505
if ShowMap and ShowGrid and InterceptShow then
490506
MapBlocks[block] = Framecount + FADEOUT_TIMER

0 commit comments

Comments
 (0)