From bab2a4e710b331bc00fd706a626422d4fded7af8 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 15 Mar 2021 10:28:06 +1100 Subject: [PATCH 01/32] Clone beta --- ModUtil.Compat.lua | 82 ++ ModUtil.Hades.lua | 401 +++++++ ModUtil.Main.lua | 97 ++ ModUtil.lua | 2689 ++++++++++++++++---------------------------- modfile.txt | 8 +- 5 files changed, 1556 insertions(+), 1721 deletions(-) create mode 100644 ModUtil.Compat.lua create mode 100644 ModUtil.Hades.lua create mode 100644 ModUtil.Main.lua diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua new file mode 100644 index 0000000..d9212ed --- /dev/null +++ b/ModUtil.Compat.lua @@ -0,0 +1,82 @@ + +ModUtil.Mod.Register( "Compat", ModUtil ) + +setmetatable( ModUtil, { + __index = ModUtil.Compat +} ) + +ModUtil.Compat.RegisterMod = ModUtil.Mod.Register + +ModUtil.Compat.ForceClosed = ModUtil.Internal.ForceClosed + +ModUtil.Compat.ValueString = ModUtil.ToString.Value + +ModUtil.Compat.KeyString = ModUtil.ToString.Key + +ModUtil.Compat.TableKeysString = ModUtil.ToString.TableKeys + +ModUtil.Compat.ToShallowString = ModUtil.ToString.Shallow + +ModUtil.Compat.ToDeepString = ModUtil.ToString.Deep + +ModUtil.Compat.ToDeepNoNamespacesString = ModUtil.ToString.DeepNoNamespaces + +ModUtil.Compat.ToDeepNamespacesString = ModUtil.ToString.DeepNamespaces + +ModUtil.Compat.JoinStrings = ModUtil.String.Join + +ModUtil.Compat.ChunkText = ModUtil.String.Chunk + +ModUtil.Compat.ReplaceTable = ModUtil.Table.Replace + +ModUtil.Compat.IsUnKeyed = ModUtil.Table.UnKeyed + +ModUtil.Compat.PrintToFile = ModUtil.Print.ToFile + +ModUtil.Compat.DebugPrint = ModUtil.Print.Debug + +ModUtil.Compat.PrintTraceback = ModUtil.Print.Traceback + +ModUtil.Compat.PrintNamespaces = ModUtil.Print.Namespaces + +ModUtil.Compat.PrintVariables = ModUtil.Print.Variables + +ModUtil.Compat.Slice = ModUtil.Array.Slice + +ModUtil.Compat.NewTable = ModUtil.Table.New + +ModUtil.Compat.SafeGet = ModUtil.IndexArray.Get + +ModUtil.Compat.SafeSet = ModUtil.IndexArray.Set + +ModUtil.Compat.MapNilTable = ModUtil.Table.NilMerge + +ModUtil.Compat.MapSetTable = ModUtil.Table.Merge + +ModUtil.Compat.JoinIndexArrays = ModUtil.IndexArray.Join + +ModUtil.Compat.PathToIndexArray = ModUtil.Path.IndexArray + +ModUtil.Compat.PathGet = ModUtil.Path.Get + +ModUtil.Compat.PathSet = ModUtil.Path.Set + +ModUtil.Compat.WrapFunction = ModUtil.IndexArray.Wrap + +ModUtil.Compat.RewrapFunction = ModUtil.IndexArray.Rewrap + +ModUtil.Compat.UnwrapFunction = ModUtil.IndexArray.Unwrap + +ModUtil.Compat.WrapBaseFunction = ModUtil.Path.Wrap + +ModUtil.Compat.RewrapBaseFunction = ModUtil.Path.Rewrap + +ModUtil.Compat.UnwrapBaseFunction = ModUtil.Path.Unwrap + +ModUtil.Compat.Override = ModUtil.IndexArray.Override + +ModUtil.Compat.BaseOverride = ModUtil.Path.Override + +ModUtil.Compat.GetOriginalValue = ModUtil.IndexArray.Original + +ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original \ No newline at end of file diff --git a/ModUtil.Hades.lua b/ModUtil.Hades.lua new file mode 100644 index 0000000..c7773c5 --- /dev/null +++ b/ModUtil.Hades.lua @@ -0,0 +1,401 @@ + +ModUtil.Mod.Register( "Hades", ModUtil ) + +ModUtil.Table.Merge( ModUtil.Hades, { + PrintStackHeight = 10, + PrintStackCapacity = 80 +} ) + +ModUtil.Anchors.PrintOverhead = {} + +-- Global Interception + +--[[ + Intercept global keys which are objects to return themselves + This way we can use other namespaces for UI etc +--]] +ModUtil.IndexArray.Wrap( getmetatable( _ENV ), { "__index" }, function( baseFunc, self, key ) + local value = baseFunc( self, key ) + if value ~= nil then return value end + local t = type( key ) + if t == "function" or t == "table" then + return key + end +end, ModUtil.Hades ) + +-- Menu Handling + +function ModUtil.Hades.CloseMenu( screen, button ) + CloseScreen(GetAllIds(screen.Components), 0.1) + ModUtil.Anchors.Menu[screen.Name] = nil + screen.KeepOpen = false + OnScreenClosed({ Flag = screen.Name }) + if TableLength(ModUtil.Anchors.Menu) == 0 then + SetConfigOption({ Name = "FreeFormSelectWrapY", Value = false }) + SetConfigOption({ Name = "UseOcclusion", Value = true }) + UnfreezePlayerUnit() + DisableShopGamepadCursor() + end + if ModUtil.Anchors.CloseFuncs[screen.Name] then + ModUtil.Anchors.CloseFuncs[screen.Name]( screen, button ) + ModUtil.Anchors.CloseFuncs[screen.Name]=nil + end +end + +function ModUtil.Hades.OpenMenu( group, closeFunc, openFunc ) + if ModUtil.Anchors.Menu[group] then + ModUtil.Hades.CloseMenu(ModUtil.Anchors.Menu[group]) + end + if closeFunc then ModUtil.Anchors.CloseFuncs[group]=closeFunc end + + local screen = { Name = group, Components = {} } + local components = screen.Components + ModUtil.Anchors.Menu[group] = screen + + OnScreenOpened({ Flag = screen.Name, PersistCombatUI = true }) + + components.Background = CreateScreenComponent({ Name = "BlankObstacle", Group = group }) + + if openFunc then openFunc(screen) end + + return screen +end + +function ModUtil.Hades.DimMenu( screen ) + if not screen then return end + if not screen.Components.BackgroundDim then + screen.Components.BackgroundDim = CreateScreenComponent({ Name = "rectangle01", Group = screen.Name }) + SetScale({ Id = screen.Components.BackgroundDim.Id, Fraction = 4 }) + end + SetColor({ Id = screen.Components.BackgroundDim.Id, Color = {0.090, 0.090, 0.090, 0.8} }) +end + +function ModUtil.Hades.UndimMenu( screen ) + if not screen then return end + if not screen.Components.BackgroundDim then return end + SetColor({ Id = screen.Components.BackgroundDim.Id, Color = {0.090, 0.090, 0.090, 0} }) +end + +function ModUtil.Hades.PostOpenMenu( screen ) + if TableLength(ModUtil.Anchors.Menu) == 1 then + SetConfigOption({ Name = "FreeFormSelectWrapY", Value = true }) + SetConfigOption({ Name = "UseOcclusion", Value = false }) + FreezePlayerUnit() + EnableShopGamepadCursor() + end + thread(HandleWASDInput, screen) + HandleScreenInput(screen) + return screen +end + +function ModUtil.Hades.GetMenuScreen( group ) + return ModUtil.Anchors.Menu[group] +end + +-- Debug Printing + +function ModUtil.Hades.PrintDisplay( text , delay, color ) + if type(text) ~= "string" then + text = tostring(text) + end + text = " "..text.." " + if color == nil then + color = Color.Yellow + end + if delay == nil then + delay = 5 + end + if ModUtil.Anchors.PrintDisplay then + Destroy({Ids = {ModUtil.Anchors.PrintDisplay.Id}}) + end + ModUtil.Anchors.PrintDisplay = CreateScreenComponent({Name = "BlankObstacle", Group = "PrintDisplay", X = ScreenCenterX, Y = 40 }) + CreateTextBox({ Id = ModUtil.Anchors.PrintDisplay.Id, Text = text, FontSize = 22, Color = color, Font = "UbuntuMonoBold"}) + + if delay > 0 then + thread(function() + wait(delay) + Destroy({Ids = {ModUtil.Anchors.PrintDisplay.Id}}) + ModUtil.Anchors.PrintDisplay = nil + end) + end +end + +function ModUtil.Hades.PrintOverhead(text, delay, color, dest) + if type(text) ~= "string" then + text = tostring(text) + end + text = " "..text.." " + if dest == nil then + dest = CurrentRun.Hero.ObjectId + end + if color == nil then + color = Color.Yellow + end + if delay == nil then + delay = 5 + end + Destroy({Ids = {ModUtil.Anchors.PrintOverhead[dest]}}) + local id = SpawnObstacle({ Name = "BlankObstacle", Group = "PrintOverhead", DestinationId = dest }) + ModUtil.Anchors.PrintOverhead[dest] = id + Attach({ Id = id, DestinationId = dest }) + CreateTextBox({ Id = id, Text = text, FontSize = 32, OffsetX = 0, OffsetY = -150, Color = color, Font = "AlegreyaSansSCBold", Justification = "Center" }) + if delay > 0 then + thread(function() + wait(delay) + if ModUtil.Anchors.PrintOverhead[dest] then + Destroy({Ids = {id}}) + ModUtil.Anchors.PrintOverhead[dest] = nil + end + end) + end +end + +local function ClosePrintStack() + if ModUtil.Anchors.PrintStack then + ModUtil.Anchors.PrintStack.CullEnabled = false + PlaySound({ Name = "/SFX/Menu Sounds/GeneralWhooshMENU" }) + ModUtil.Anchors.PrintStack.KeepOpen = false + + CloseScreen(GetAllIds(ModUtil.Anchors.PrintStack.Components),0) + ModUtil.Anchors.CloseFuncs["PrintStack"] = nil + ModUtil.Anchors.PrintStack = nil + end +end + +local function OrderPrintStack(screen,components) + + if screen.CullPrintStack then + local v = screen.TextStack[1] + if v.obj then + Destroy({Ids = {v.obj.Id}}) + components["TextStack_" .. v.tid] = nil + v.obj = nil + screen.TextStack[v.tid]=nil + end + thread( function() + local v = screen.TextStack[2] + if v then + wait(v.data.Delay) + if v.obj then + screen.CullPrintStack = true + end + end + end) + else + thread( function() + local v = screen.TextStack[1] + if v then + wait(v.data.Delay) + if v.obj then + screen.CullPrintStack = true + end + end + end) + end + screen.CullPrintStack = false + + for k,v in pairs(screen.TextStack) do + components["TextStack_" .. k] = nil + Destroy({Ids = {v.obj.Id}}) + end + + screen.TextStack = CollapseTable(screen.TextStack) + for i,v in pairs(screen.TextStack) do + v.tid = i + end + if #screen.TextStack == 0 then + return ClosePrintStack() + end + + local Ymul = screen.StackHeight+1 + local Ygap = 30 + local Yoff = 26*screen.StackHeight+22 + local n =#screen.TextStack + + if n then + for k=1,math.min(n,Ymul) do + v = screen.TextStack[k] + if v then + local data = v.data + screen.TextStack[k].obj = CreateScreenComponent({ Name = "rectangle01", Group = "PrintStack", X = -1000, Y = -1000}) + local textStack = screen.TextStack[k].obj + components["TextStack_" .. k] = textStack + SetScaleX({Id = textStack.Id, Fraction = 10/6}) + SetScaleY({Id = textStack.Id, Fraction = 0.1}) + SetColor({ Id = textStack.Id, Color = data.Bgcol }) + CreateTextBox({ Id = textStack.Id, Text = data.Text, FontSize = data.FontSize, OffsetX = 0, OffsetY = 0, Color = data.Color, Font = data.Font, Justification = "Center" }) + Attach({ Id = textStack.Id, DestinationId = components.Background.Id, OffsetX = 220, OffsetY = -Yoff }) + Yoff = Yoff - Ygap + end + end + end + +end + +function ModUtil.Hades.PrintStack( text, delay, color, bgcol, fontsize, font, sound ) + if color == nil then color = {1,1,1,1} end + if bgcol == nil then bgcol = {0.590, 0.555, 0.657,0.125} end + if fontsize == nil then fontsize = 13 end + if font == nil then font = "UbuntuMonoBold" end + if sound == nil then sound = "/Leftovers/SFX/AuraOff" end + if delay == nil then delay = 3 end + + if type(text) ~= "string" then + text = tostring(text) + end + text = " "..text.." " + + local first = false + if not ModUtil.Anchors.PrintStack then + first = true + ModUtil.Anchors.PrintStack = { Components = {} } + ModUtil.Anchors.CloseFuncs["PrintStack"] = ClosePrintStack + end + local screen = ModUtil.Anchors.PrintStack + local components = screen.Components + + if first then + + screen.KeepOpen = true + screen.TextStack = {} + screen.CullPrintStack = false + screen.MaxStacks = ModUtil.Hades.PrintStackCapacity + screen.StackHeight = ModUtil.Hades.PrintStackHeight + PlaySound({ Name = "/SFX/Menu Sounds/DialoguePanelOutMenu" }) + components.Background = CreateScreenComponent({ Name = "BlankObstacle", Group = "PrintStack", X = ScreenCenterX, Y = 2*ScreenCenterY}) + components.Backing = CreateScreenComponent({ Name = "TraitTray_Center", Group = "PrintStack"}) + Attach({ Id = components.Backing.Id, DestinationId = components.Background.Id, OffsetX = -180, OffsetY = 0 }) + SetColor({ Id = components.Backing.Id, Color = {0.590, 0.555, 0.657, 0.8} }) + SetScaleX({Id = components.Backing.Id, Fraction = 6.25}) + SetScaleY({Id = components.Backing.Id, Fraction = 6/55*(2+screen.StackHeight)}) + + thread( function() + while screen do + wait(0.5) + if screen.CullEnabled then + if screen.CullPrintStack then + OrderPrintStack(screen,components) + end + end + end + end) + + end + + if #screen.TextStack >= screen.MaxStacks then return end + + screen.CullEnabled = false + + local newText = {} + newText.obj = CreateScreenComponent({ Name = "rectangle01", Group = "PrintStack"}) + newText.data = {Delay = delay, Text = text, Color = color, Bgcol = bgcol, Font = font, FontSize = fontsize} + SetColor({ Id = newText.obj.Id, Color = {0,0,0,0}}) + table.insert(screen.TextStack, newText) + + PlaySound({ Name = sound }) + + OrderPrintStack(screen,components) + + screen.CullEnabled = true + +end + +function ModUtil.Hades.PrintStackChunks( text, linespan, ... ) + if not linespan then linespan = 90 end + for _,s in ipairs( ModUtil.String.Chunk( text, linespan, ModUtil.Hades.PrintStackCapacity ) ) do + ModUtil.Hades.PrintStack( s, ... ) + end +end + +-- Custom Menus + +function ModUtil.Hades.NewMenuYesNo( group, closeFunc, openFunc, yesFunc, noFunc, title, body, yesText, noText, icon, iconScale) + + if not group or group == "" then group = "MenuYesNo" end + if not yesFunc then yesFunc = function( ) end end + if not noFunc then noFunc = function( ) end end + if not icon then icon = "AmmoPack" end + if not iconScale then iconScale = 1 end + if not yesText then yesText = "Yes" end + if not noText then noText = "No" end + if not body then body = "Make a choice..." end + if not title then title = group end + + local screen = ModUtil.Hades.OpenMenu( group, closeFunc, openFunc ) + local components = screen.Components + + PlaySound({ Name = "/SFX/Menu Sounds/GodBoonInteract" }) + + components.LeftPart = CreateScreenComponent({ Name = "TraitTrayBackground", Group = group, X = 1030, Y = 424}) + components.MiddlePart = CreateScreenComponent({ Name = "TraitTray_Center", Group = group, X = 660, Y = 464 }) + components.RightPart = CreateScreenComponent({ Name = "TraitTray_Right", Group = group, X = 1270, Y = 438 }) + SetScaleY({Id = components.LeftPart.Id, Fraction = 0.8}) + SetScaleY({Id = components.MiddlePart.Id, Fraction = 0.8}) + SetScaleY({Id = components.RightPart.Id, Fraction = 0.8}) + SetScaleX({Id = components.MiddlePart.Id, Fraction = 5}) + + + CreateTextBox({ Id = components.Background.Id, Text = " "..title.." ", FontSize = 34, + OffsetX = 0, OffsetY = -225, Color = Color.White, Font = "SpectralSCLight", + ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 1}, Justification = "Center" }) + CreateTextBox({ Id = components.Background.Id, Text = " "..body.." ", FontSize = 19, + OffsetX = 0, OffsetY = -175, Width = 840, Color = Color.SubTitle, Font = "CrimsonTextItalic", + ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 1}, Justification = "Center" }) + + components.Icon = CreateScreenComponent({ Name = "BlankObstacle", Group = group }) + Attach({ Id = components.Icon.Id, DestinationId = components.Background.Id, OffsetX = 0, OffsetY = -50}) + SetAnimation({ Name = icon, DestinationId = components.Icon.Id, Scale = iconScale }) + + ModUtil.Nodes.New(ModUtil.Anchors.Menu[group], "Funcs") + ModUtil.Anchors.Menu[group].Funcs={ + Yes = function(screen, button) + if not yesFunc(screen,button) then + ModUtil.Hades.CloseMenuYesNo(screen,button) + end + end, + No = function(screen, button) + if not noFunc(screen,button) then + ModUtil.Hades.CloseMenuYesNo(screen,button) + end + end, + } + + components.CloseButton = CreateScreenComponent({ Name = "ButtonClose", Scale = 0.7, Group = group }) + Attach({ Id = components.CloseButton.Id, DestinationId = components.Background.Id, OffsetX = 0, OffsetY = ScreenCenterY - 315 }) + components.CloseButton.OnPressedFunctionName = ModUtil.Path.ReferFunction( "ModUtil.Hades.CloseMenuYesNo" ) + components.CloseButton.ControlHotkey = "Cancel" + + components.YesButton = CreateScreenComponent({ Name = "BoonSlot1", Group = group, Scale = 0.35, }) + components.YesButton.OnPressedFunctionName = ModUtil.Path.ReferFunction( "ModUtil.Anchors.Menu."..group..".Funcs.Yes" ) + SetScaleX({Id = components.YesButton.Id, Fraction = 0.75}) + SetScaleY({Id = components.YesButton.Id, Fraction = 1.15}) + Attach({ Id = components.YesButton.Id, DestinationId = components.Background.Id, OffsetX = -150, OffsetY = 75 }) + CreateTextBox({ Id = components.YesButton.Id, Text = " "..yesText.." ", + FontSize = 28, OffsetX = 0, OffsetY = 0, Width = 720, Color = Color.LimeGreen, Font = "AlegreyaSansSCLight", + ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 2}, Justification = "Center" + }) + + components.NoButton = CreateScreenComponent({ Name = "BoonSlot1", Group = group, Scale = 0.35, }) + components.NoButton.OnPressedFunctionName = ModUtil.Path.ReferFunction( "ModUtil.Anchors.Menu."..group..".Funcs.No" ) + SetScaleX({Id = components.NoButton.Id, Fraction = 0.75}) + SetScaleY({Id = components.NoButton.Id, Fraction = 1.15}) + Attach({ Id = components.NoButton.Id, DestinationId = components.Background.Id, OffsetX = 150, OffsetY = 75 }) + CreateTextBox({ Id = components.NoButton.Id, Text = noText, + FontSize = 26, OffsetX = 0, OffsetY = 0, Width = 720, Color = Color.Red, Font = "AlegreyaSansSCLight", + ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 2}, Justification = "Center" + }) + + return ModUtil.Hades.PostOpenMenu( screen ) +end + +function ModUtil.Hades.CloseMenuYesNo( screen, button ) + PlaySound({ Name = "/SFX/Menu Sounds/GeneralWhooshMENU" }) + ModUtil.Hades.CloseMenu( screen, button ) +end + +-- Misc + +function ModUtil.Hades.RandomElement( tableArg, rng ) + local Collapsed = CollapseTable( tableArg ) + return Collapsed[RandomInt( 1, #Collapsed, rng )] +end \ No newline at end of file diff --git a/ModUtil.Main.lua b/ModUtil.Main.lua new file mode 100644 index 0000000..2df70f2 --- /dev/null +++ b/ModUtil.Main.lua @@ -0,0 +1,97 @@ +--[[ + ModUtil Main + Components of ModUtil that depend on loading after Main.lua +]] + +--- bind to locals to minimise environment recursion and improve speed +local ModUtil, pairs, ipairs, table, SaveIgnores, _G + = ModUtil, pairs, ipairs, table, SaveIgnores, ModUtil.Internal._G + +-- Management + +SaveIgnores[ "ModUtil" ] = true + +--[[ + Create a namespace that can be used for the mod's functions + and data, and ensure that it doesn't end up in save files. + + modName - the name of the mod + parent - the parent mod, or nil if this mod stands alone +--]] +function ModUtil.Mod.Register( modName, parent, content ) + if not parent then + parent = _G + SaveIgnores[ modName ] = true + end + local mod = parent[ modName ] + if not mod then + mod = { } + parent[ modName ] = mod + local path = ModUtil.Mods.Inverse[ parent ] + if path ~= nil then + path = path .. '.' + else + path = '' + end + path = path .. modName + ModUtil.Mods.Data[ path ] = mod + ModUtil.Identifiers.Inverse[ path ] = mod + end + if content then + ModUtil.Table.SetMap( parent[ modName ], content ) + end + return parent[ modName ] +end + +--[[ + Tell each screen anchor that they have been forced closed by the game +--]] +local function forceClosed( triggerArgs ) + for _, v in pairs( ModUtil.Anchors.CloseFuncs ) do + v( nil, nil, triggerArgs ) + end + ModUtil.Anchors.CloseFuncs = { } + ModUtil.Anchors.Menu = { } +end +OnAnyLoad{ function( triggerArgs ) forceClosed( triggerArgs ) end } + +local funcsToLoad = { } + +local function loadFuncs( triggerArgs ) + for _, v in pairs( funcsToLoad ) do + v( triggerArgs ) + end + funcsToLoad = { } +end +OnAnyLoad{ function( triggerArgs ) loadFuncs( triggerArgs ) end } + +--[[ + Run the provided function once on the next in-game load. + + triggerFunction - the function to run +--]] +function ModUtil.LoadOnce( triggerFunction ) + table.insert( funcsToLoad, triggerFunction ) +end + +--[[ + Cancel running the provided function once on the next in-game load. + + triggerFunction - the function to cancel running +--]] +function ModUtil.CancelLoadOnce( triggerFunction ) + for i, v in ipairs( funcsToLoad ) do + if v == triggerFunction then + table.remove( funcsToLoad, i ) + end + end +end + +-- Internal Access + +do + local ups = ModUtil.UpValues( function( ) + return forceClosed, funcsToLoad, loadFuncs + end ) + rawset( ModUtil.Internal, "Main", setmetatable( { }, { __index = ups, __newindex = ups } ) ) +end \ No newline at end of file diff --git a/ModUtil.lua b/ModUtil.lua index 27afde2..6a492c7 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -5,32 +5,53 @@ Author: MagicGonads Library to allow mods to be more compatible with eachother and expand capabilities. Use the mod importer to import this mod to ensure it is loaded in the right position. -]] - +--]] ModUtil = { + + Mod = { }, + Print = { }, + ToString = { }, + String = { }, + Table = { }, + Path = { }, + Array = { }, + IndexArray = { }, + UpValues = { }, + Locals = { }, + Entangled = { }, Internal = { }, Metatables = { }, - New = { }, Anchors = { Menu = { }, CloseFuncs = { } - }, + } + } -SaveIgnores[ "ModUtil" ] = true -- Extended Global Utilities (assuming lua 5.2) -local debug = debug +local error, pcall, xpcall = error, pcall, xpcall + +local debug, type, table = debug, type, table +local function getname( ) + return debug.getinfo( 2, "n" ).name +end -- doesn't invoke __index rawnext = next local rawnext = rawnext +local function pusherror( f, ... ) + local ret = table.pack( pcall( f, ... ) ) + if ret[ 1 ] then return table.unpack( ret, 2, ret.n ) end + error( ret[ 2 ], 3 ) +end + -- invokes __next function next( t, k ) local m = debug.getmetatable( t ) local f = m and m.__next or rawnext - return f( t, k ) + return pusherror( f, t, k ) end local next = next @@ -49,7 +70,19 @@ local rawget = rawget -- doesn't invoke __index just like rawnext function rawinext( t, i ) - if i == nil then i = 0 end + + if type( t ) ~= "table" then + error( "bad argument #1 to '" .. getname( ) .. "'(table expected got " .. type( i ) ..")", 2 ) + end + + if i == nil then + i = 0 + elseif type( i ) ~= "number" then + error( "bad argument #2 to '" .. getname( ) .. "'(number expected got " .. type( i ) ..")", 2 ) + elseif i < 0 then + error( "bad argument #2 to '" .. getname( ) .. "'(index out of bounds, too low)", 2 ) + end + i = i + 1 local v = rawget( t, i ) if v ~= nil then @@ -63,7 +96,7 @@ local rawinext = rawinext function inext( t, i ) local m = debug.getmetatable( t ) local f = m and m.__inext or rawinext - return f( t, i ) + return pusherror( f, t, i ) end local inext = inext @@ -82,8 +115,6 @@ function qrawipairs( t ) end, t, nil end -local type = type - function getfenv( fn ) if type( fn ) ~= "function" then fn = debug.getinfo( ( fn or 1 ) + 1, "f" ).func @@ -103,8 +134,8 @@ end Global variable lookups (including function calls) in that function will use the new environment table rather than the normal one. This is useful for function-specific overrides. The new environment - table should generally have _G as its __index, so that any globals - other than those being overridden can still be read. + table should generally have _G as its __index and __newindex, so that any globals + other than those being deliberately overridden operate as usual. ]] function setfenv( fn, env ) if type( fn ) ~= "function" then @@ -118,13 +149,11 @@ function setfenv( fn, env ) debug.upvaluejoin( fn, i, ( function( ) return env end ), 1 ) - return env + return end until not name end -local table = table - table.rawinsert = table.insert -- table.insert that respects metamethods function table.insert( list, pos, value ) @@ -134,7 +163,7 @@ function table.insert( list, pos, value ) pos = last + 1 end if pos < 1 or pos > last + 1 then - error( "bad argument #2 to '" .. debug.getinfo( 1, "n" ).name .. "' (position out of bounds)", 2 ) + error( "bad argument #2 to '" .. getname( ) .. "' (position out of bounds)", 2 ) end if pos <= last then local i = last @@ -154,7 +183,7 @@ function table.remove( list, pos ) pos = last end if pos < 1 or pos > last then - error( "bad argument #2 to '" .. debug.getinfo( 1, "n" ).name .. "' (position out of bounds)", 2 ) + error( "bad argument #2 to '" .. getname( ) .. "' (position out of bounds)", 2 ) end local value = list[ pos ] if pos <= last then @@ -172,219 +201,140 @@ end - table.unpack - table.concat - table.sort -]] - --- Environment Context (EXPERIMENTAL) (WIP) (INCOMPLETE) +--]] --- bind to locals to minimise environment recursion +--- bind to locals to minimise environment recursion and improve speed local rawset, rawlen, ModUtil, getmetatable, setmetatable, pairs, ipairs, coroutine, - rawpairs, rawipairs, qrawpairs, qrawipairs, getfenv, setfenv, tostring, xpcall + rawpairs, rawipairs, qrawpairs, qrawipairs, tostring, getfenv, setfenv = rawset, rawlen, ModUtil, getmetatable, setmetatable, pairs, ipairs, coroutine, - rawpairs, rawipairs, qrawpairs, qrawipairs, getfenv, setfenv, tostring, xpcall + rawpairs, rawipairs, qrawpairs, qrawipairs, tostring, getfenv, setfenv -function ModUtil.RawInterface( obj ) +--[[ + local version of ToLookup as to not depend on Main.lua +]] +local function ToLookup( tableArg ) + local lookup = { } + for _, value in pairs( tableArg ) do + lookup[ value ] = true + end + return lookup +end - local meta = { - __index = function( _, key ) - return rawget( obj, key ) +-- Managed Object Data + +local objectData = setmetatable( { }, { __mode = "k" } ) + +local function newObjectData( data ) + local obj = { } + objectData[ obj ] = data + return obj +end + +local function getObjectData( obj, key ) + return objectData[ obj ][ key ] +end + +function ModUtil.ObjectDataProxy( data, meta ) + return setmetatable( newObjectData( data ), meta ) +end + +function ModUtil.RawInterface( obj ) + return setmetatable( { }, { + __index = function( _, ... ) + return rawget( obj, ... ) end, - __newindex = function( _, key, value ) - rawset( obj, key, value ) + __newindex = function( _, ... ) + return rawset( obj, ... ) end, - __len = function( ) - return rawlen( obj ) + __len = function( _, ...) + return rawlen( obj, ... ) end, - __next = function( _, key ) - return rawnext( obj, key ) + __next = function( _, ... ) + return rawnext( obj, ... ) end, - __inext = function( _ , idx ) - return rawinext( obj, idx ) + __inext = function( _, ... ) + return rawinext( obj, ... ) end, - __pairs = function( ) - return rawpairs( obj ) + __pairs = function( _, ... ) + return rawpairs( obj, ... ) end, - __ipairs = function( ) - return rawipairs( obj ) + __ipairs = function( _, ... ) + return rawipairs( obj, ... ) end - } - - local interface = { } - setmetatable( interface, meta ) - return interface - + } ) end -local __G = ModUtil.RawInterface( _G ) -__G.__G = __G +-- Environment Context ( EXPERIMENTAL ) ( BROKEN ) -local surrogateEnvironments = { } -setmetatable( surrogateEnvironments, { __mode = "k" } ) +local _G = _ENV +local __G -local function getenv( ) - local level = 3 - repeat - level = level + 1 - local info = debug.getinfo( level, "f" ) - if info then - local env = surrogateEnvironments[ info.func ] - if env then - return env - end - end - until not info - return __G -end +local threadEnvironments = setmetatable( { }, { __mode = "k" } ) ---[[ - Make lexical environments use locals instead of upvalues -]] -function ModUtil.ReplaceGlobalEnvironment( ) - - local split = function( path ) - if type( path ) == "string" - and path:find("[.]") - and not path:find("[.][.]+") - and not path:find("^[.]") - and not path:find("[.]$") then - return ModUtil.PathToIndexArray( path ) - end - return { path } - end - local get = ModUtil.SafeGet - debug.setmetatable( __G._G, { } ) +local function getEnv( thread ) + return threadEnvironments[ thread or coroutine.running( ) ] or _G +end - local meta = { +local function replaceGlobalEnvironment( ) + __G = debug.setmetatable( { }, { __index = function( _, key ) - local env = getenv( ) - local value = env[ key ] - if value ~= nil then return value end - return get( env, split( key ) ) + return getEnv( )[ key ] end, __newindex = function( _, key, value ) - getenv( )[ key ] = value + getEnv( )[ key ] = value end, __len = function( ) - return #getenv( ) + return #getEnv( ) end, __next = function( _, key ) - return next( getenv( ), key ) + return next( getEnv( ), key ) end, __inext = function( _, key ) - return inext( getenv( ), key ) + return inext( getEnv( ), key ) end, __pairs = function( ) - return pairs( getenv( ) ) + return pairs( getEnv( ) ) end, __ipairs = function( ) - return ipairs( getenv( ) ) - end - } - - debug.setmetatable( __G._G, meta ) -end - -local function skipenv( obj ) - if obj ~= __G._G then return obj end - return __G -end - --- Management - ---[[ - Create a namespace that can be used for the mod's functions - and data, and ensure that it doesn't end up in save files. - - modName - the name of the mod - parent - the parent mod, or nil if this mod stands alone -]] -function ModUtil.RegisterMod( modName, parent, content ) - if not parent then - parent = _G - SaveIgnores[ modName ] = true - end - local mod = parent[ modName ] - if not mod then - mod = { } - parent[ modName ] = mod - local path = ModUtil.Mods.Index[ parent ] - if path ~= nil then - path = path .. '.' - else - path = '' + return ipairs( getEnv( ) ) end - path = path .. modName - ModUtil.Mods.Table[ path ] = mod - ModUtil.Identifiers.Table[ mod ] = path - end - if content then - ModUtil.MapSetTable( parent[ modName ], content ) + } ) + _G._G = __G + local reg = debug.getregistry( ) + for i, v in ipairs( reg ) do + if v == _G then reg[ i ] = __G end end - return parent[ modName ] + ModUtil.Identifiers.Inverse._ENV = __G end ---[[ - Tell each screen anchor that they have been forced closed by the game -]] -function ModUtil.ForceClosed( triggerArgs ) - for _, v in pairs( ModUtil.Anchors.CloseFuncs ) do - v( nil, nil, triggerArgs ) - end - ModUtil.Anchors.CloseFuncs = { } - ModUtil.Anchors.Menu = { } -end -OnAnyLoad{ function( triggerArgs ) ModUtil.ForceClosed( triggerArgs ) end } +-- Data Misc -ModUtil.Internal.FuncsToLoad = { } +local passByValueTypes = ToLookup{ "number", "boolean", "nil" } +local excludedFieldNames = ToLookup{ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" } -function ModUtil.Internal.LoadFuncs( triggerArgs ) - for _, v in pairs( ModUtil.Internal.FuncsToLoad ) do - v( triggerArgs ) +setmetatable( ModUtil.ToString, { + __call = function ( _, o ) + local identifier = ModUtil.Identifiers.Data[ o ] + identifier = identifier and identifier .. ":" or "" + return identifier .. ModUtil.ToString.Static( o ) end - ModUtil.Internal.FuncsToLoad = { } -end -OnAnyLoad{ function( triggerArgs ) ModUtil.Internal.LoadFuncs( triggerArgs ) end } - ---[[ - Run the provided function once on the next in-game load. - - triggerFunction - the function to run -]] -function ModUtil.LoadOnce( triggerFunction ) - table.insert( ModUtil.Internal.FuncsToLoad, triggerFunction ) -end - ---[[ - Cancel running the provided function once on the next in-game load. +}) - triggerFunction - the function to cancel running -]] -function ModUtil.CancelLoadOnce( triggerFunction ) - for i, v in ipairs( ModUtil.Internal.FuncsToLoad ) do - if v == triggerFunction then - table.remove( ModUtil.Internal.FuncsToLoad, i ) - end - end +function ModUtil.ToString.Address( o ) + local t = type( o ) + if t == "string" or passByValueTypes[ t ] then return end + return tostring( o ):match( ": 0*([0-9A-F]*)" ) end --- Data Misc - -function ModUtil.ReferFunction( funcPath, baseTable ) - if type( baseTable ) == "number" then -- locals - baseTable = ModUtil.Locals( baseTable + 1 ) - end - baseTable = baseTable or _G - local indexArray = ModUtil.PathToIndexArray( funcPath ) - return function( ... ) - return ModUtil.SafeGet( baseTable, indexArray )( ... ) - end +function ModUtil.ToString.Static( o ) + local t = type( o ) + if t == "string" or passByValueTypes[ t ] then return tostring( o ) end + return tostring( o ):gsub( ": 0*", ":", 1 ) end -local passByValueTypes = ToLookup{ "number", "boolean", "nil" } -local excludedFieldNames = ToLookup{ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" } - -function ModUtil.ValueString( o ) +function ModUtil.ToString.Value( o ) local t = type( o ) if t == 'string' then return '"' .. o .. '"' @@ -392,45 +342,29 @@ function ModUtil.ValueString( o ) if passByValueTypes[ t ] then return tostring( o ) end - local identifier = ModUtil.Identifiers.Table[ o ] - if identifier then - identifier = "(" .. identifier .. ")" - else - identifier = "" - end - return identifier .. '<' .. tostring( o ) .. '>' + return '<' .. ModUtil.ToString( o ) .. '>' end -function ModUtil.KeyString( o ) +function ModUtil.ToString.Key( o ) local t = type( o ) - o = tostring( o ) - if t == 'string' and not excludedFieldNames[ o ] then - local pattern = "^[a-zA-Z_][a-zA-Z0-9_]*$" - if o:gmatch( pattern ) then + if t == 'string' then + if not excludedFieldNames[ o ] and o:gmatch( "^[a-zA-Z_][a-zA-Z0-9_]*$" ) then return o end return '"' .. o .. '"' end if t == 'number' then - o = "#" .. o - end - if not passByValueTypes[ t ] then - o = '<' .. o .. '>' - end - local identifier = ModUtil.Identifiers.Table[ o ] - if identifier then - identifier = "(" .. identifier .. ")" - else - identifier = "" + return "#" .. tostring( o ) end - return identifier .. o + if passByValueTypes[ t ] then return tostring( o ) end + return '<' .. ModUtil.ToString( o ) .. '>' end -function ModUtil.TableKeysString( o ) +function ModUtil.ToString.TableKeys( o ) if type( o ) == 'table' then local out = { } for k in pairs( o ) do - table.insert( out , ModUtil.KeyString( k ) ) + table.insert( out , ModUtil.ToString.Key( k ) ) table.insert( out , ', ' ) end table.remove( out ) @@ -438,117 +372,123 @@ function ModUtil.TableKeysString( o ) end end -function ModUtil.ToShallowString( o ) +function ModUtil.ToString.Shallow( o ) if type( o ) == "table" then - local out = { ModUtil.ValueString( o ), "{ " } + local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do - table.insert( out, ModUtil.KeyString( k ) ) + table.insert( out, ModUtil.ToString.Key( k ) ) table.insert( out, ' = ' ) - table.insert( out, ModUtil.ValueString( v ) ) + table.insert( out, ModUtil.ToString.Value( v ) ) table.insert( out , ", " ) end if #out > 2 then table.remove( out ) end - return table.concat( out ) .. " }" + return table.concat( out ) .. " )" else - return ModUtil.ValueString( o ) + return ModUtil.ToString.Value( o ) end end -function ModUtil.ToDeepString( o, seen ) +function ModUtil.ToString.Deep( o, seen ) seen = seen or { } if type( o ) == "table" and not seen[ o ] then seen[ o ] = true - local out = { ModUtil.ValueString( o ), "{ " } + local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do - table.insert( out, ModUtil.KeyString( k ) ) + table.insert( out, ModUtil.ToString.Key( k ) ) table.insert( out, ' = ' ) - table.insert( out, ModUtil.ToDeepString( v, seen ) ) + table.insert( out, ModUtil.ToString.Deep( v, seen ) ) table.insert( out , ", " ) end if #out > 2 then table.remove( out ) end - return table.concat( out ) .. " }" + return table.concat( out ) .. " )" else - return ModUtil.ValueString( o ) + return ModUtil.ToString.Value( o ) end end -function ModUtil.ToDeepNoNamespacesString( o, seen ) +function ModUtil.ToString.DeepNoNamespaces( o, seen ) local first = false if not seen then first = true seen = { } end - if type( o ) == "table" and not seen[ o ] and o ~= __G._G and ( first or not ModUtil.Mods.Index[ o ] ) then + if type( o ) == "table" and not seen[ o ] and o ~= _G and o ~= _ENV and ( first or not ModUtil.Mods.Inverse[ o ] ) then seen[ o ] = true - local out = { ModUtil.ValueString( o ), "{ " } + local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do - if v ~= __G._G and not ModUtil.Mods.Index[ v ] then - table.insert( out, ModUtil.KeyString( k ) ) + if v ~= _G and v ~= _ENV and not ModUtil.Mods.Inverse[ v ] then + table.insert( out, ModUtil.ToString.Key( k ) ) table.insert( out, ' = ' ) - table.insert( out, ModUtil.ToDeepNoNamespacesString( v, seen ) ) + table.insert( out, ModUtil.ToString.DeepNoNamespaces( v, seen ) ) table.insert( out , ", " ) end end if #out > 2 then table.remove( out ) end - return table.concat( out ) .. " }" + return table.concat( out ) .. " )" else - return ModUtil.ValueString( o ) + return ModUtil.ToString.Value( o ) end end -function ModUtil.ToDeepNamespacesString( o, seen ) +function ModUtil.ToString.DeepNamespaces( o, seen ) local first = false if not seen then first = true seen = { } end - if type( o ) == "table" and not seen[ o ] and ( first or o == __G._G or ModUtil.Mods.Index[ o ] ) then + if type( o ) == "table" and not seen[ o ] and ( first or o == _G or o == _ENV or ModUtil.Mods.Inverse[ o ] ) then seen[ o ] = true - local out = { ModUtil.ValueString( o ), "{ " } + local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do - if v == __G._G or ModUtil.Mods.Index[ v ] then - table.insert( out, ModUtil.KeyString( k ) ) + if v == _G or v == _ENV or ModUtil.Mods.Inverse[ v ] then + table.insert( out, ModUtil.ToString.Key( k ) ) table.insert( out, ' = ' ) - table.insert( out, ModUtil.ToDeepNamespacesString( v, seen ) ) + table.insert( out, ModUtil.ToString.DeepNamespaces( v, seen ) ) table.insert( out , ", " ) end end if #out > 2 then table.remove( out ) end - return table.concat( out ) .. " }" + return table.concat( out ) .. " )" else - return ModUtil.ValueString( o ) + return ModUtil.ToString.Value( o ) end end function ModUtil.MapVars( mapFunc, ... ) - local out = {} - for _, v in ipairs{ ... } do - table.insert( out, mapFunc( v ) ) + local out = { } + local args = table.pack( ... ) + for i = 1, args.n do + table.insert( out, mapFunc( args[ i ] ) ) end return table.unpack( out ) end -function ModUtil.MapTable( mapFunc, tableArg ) - local out = {} +function ModUtil.Table.MapCopy( tableArg, mapFunc ) + local out = { } for k, v in pairs( tableArg ) do out[ k ] = mapFunc( v ) end return out end -function ModUtil.JoinStrings( sep, ... ) +function ModUtil.Table.Map( tableArg, mapFunc ) + for k, v in pairs( tableArg ) do + tableArg[ k ] = mapFunc( v ) + end +end + +function ModUtil.String.Join( sep, ... ) local out = {} - local args = { ... } - local i - i, out[ 1 ] = inext( args ) - for _, v in inext, args, i do + local args = table.pack( ... ) + out[ 1 ] = args[ 1 ] + for i = 2, args.n do table.insert( out, sep ) - table.insert( out, v ) + table.insert( out, args[ i ] ) end return table.concat( out ) end -function ModUtil.ChunkText( text, chunkSize, maxChunks ) +function ModUtil.String.Chunk( text, chunkSize, maxChunks ) local chunks = { "" } local cs = 0 local ncs = 1 @@ -569,7 +509,7 @@ function ModUtil.ChunkText( text, chunkSize, maxChunks ) return chunks end -function ModUtil.ReplaceTable( target, data ) +function ModUtil.Table.Replace( target, data ) for k in pairs( target ) do target[ k ] = data[ k ] end @@ -578,7 +518,7 @@ function ModUtil.ReplaceTable( target, data ) end end -function ModUtil.IsUnKeyed( tableArg ) +function ModUtil.Table.UnKeyed( tableArg ) local lk = 0 for k in pairs( tableArg ) do if type( k ) ~= "number" then @@ -592,9 +532,22 @@ function ModUtil.IsUnKeyed( tableArg ) return true end --- Printing +-- Print + +setmetatable( ModUtil.Print, { + __call = function ( _, ... ) + print( ... ) + if DebugPrint then ModUtil.Print.Debug( ... ) end + if io then + if io.stdout ~= io.output( ) then + ModUtil.Print.ToFile( io.output( ), ... ) + end + io.flush( ) + end + end +}) -function ModUtil.PrintToFile( file, ... ) +function ModUtil.Print.ToFile( file, ... ) local close = false if type( file ) == "string" and io then file = io.open( file, "a" ) @@ -606,26 +559,15 @@ function ModUtil.PrintToFile( file, ... ) end end -function ModUtil.DebugPrint( ... ) - local text = ModUtil.JoinStrings( "\t", ModUtil.MapVars( tostring, ... ) ):gsub( "\t", " " ) +function ModUtil.Print.Debug( ... ) + local text = ModUtil.String.Join( "\t", ModUtil.MapVars( tostring, ... ) ):gsub( "\t", " " ) for line in text:gmatch( "([^\n]+)" ) do DebugPrint{ Text = line } end end -function ModUtil.Print( ... ) - print( ... ) - if DebugPrint then ModUtil.DebugPrint( ... ) end - if io then - if io.stdout ~= io.output( ) then - ModUtil.PrintToFile( io.output( ), ... ) - end - io.flush( ) - end -end - -function ModUtil.PrintTraceback( level ) - level = ( level or 1 ) +function ModUtil.Print.Traceback( level ) + level = level or 1 ModUtil.Print("Traceback:") local cont = true while cont do @@ -652,50 +594,48 @@ function ModUtil.PrintTraceback( level ) end end -function ModUtil.PrintDebugInfo( level ) - level = ( level or 1 ) +function ModUtil.Print.DebugInfo( level ) + level = level or 1 local text - text = ModUtil.ToDeepString( debug.getinfo( level + 1 ) ) + text = ModUtil.ToString.Deep( debug.getinfo( level + 1 ) ) ModUtil.Print( "Debug Info:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) end -function ModUtil.PrintNamespaces( level ) - level = ( level or 1 ) +function ModUtil.Print.Namespaces( level ) + level = level or 1 local text ModUtil.Print("Namespaces:") - text = ModUtil.ToDeepNamespacesString( ModUtil.Locals( level + 1 ) ) + text = ModUtil.ToString.DeepNamespaces( ModUtil.Locals( level + 1 ) ) ModUtil.Print( "\t" .. "Locals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - text = ModUtil.ToDeepNamespacesString( ModUtil.UpValues( level + 1 ) ) + text = ModUtil.ToString.DeepNamespaces( ModUtil.UpValues( level + 1 ) ) ModUtil.Print( "\t" .. "UpValues:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - local func = debug.getinfo( level + 1, "f" ).func - text = ModUtil.ToDeepNamespacesString( surrogateEnvironments[ func ] or getfenv( func ) ) - ModUtil.Print( "\t" .. "Globals:" .. "\t" .. text ) + text = ModUtil.ToString.DeepNamespaces( _ENV ) + ModUtil.Print( "\t" .. "Globals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) end -function ModUtil.PrintVariables( level ) - level = ( level or 1 ) +function ModUtil.Print.Variables( level ) + level = level or 1 local text ModUtil.Print("Variables:") - text = ModUtil.ToDeepNoNamespacesString( ModUtil.Locals( level + 1 ) ) + text = ModUtil.ToString.DeepNoNamespaces( ModUtil.Locals( level + 1 ) ) ModUtil.Print( "\t" .. "Locals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - text = ModUtil.ToDeepNoNamespacesString( ModUtil.UpValues( level + 1 ) ) + text = ModUtil.ToString.DeepNoNamespaces( ModUtil.UpValues( level + 1 ) ) ModUtil.Print( "\t" .. "UpValues:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - local func = debug.getinfo( level + 1, "f" ).func - text = ModUtil.ToDeepNoNamespacesString( surrogateEnvironments[ func ] or getfenv( func ) ) - ModUtil.Print( "\t" .. "Globals:" .. "\t" .. text ) + text = ModUtil.ToString.DeepNoNamespaces( _ENV ) + ModUtil.Print( "\t" .. "Globals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) end --[[ Call a function with the provided arguments instead of halting when an error occurs it prints the entire error traceback -]] +--]] function ModUtil.DebugCall( f, ... ) return xpcall( f, function( err ) ModUtil.Print( err ) - ModUtil.PrintDebugInfo( 2 ) - ModUtil.PrintNamespaces( 2 ) - ModUtil.PrintVariables( 2 ) - ModUtil.PrintTraceback( 2 ) + ModUtil.Print.DebugInfo( 2 ) + ModUtil.Print.Namespaces( 2 ) + ModUtil.Print.Variables( 2 ) + ModUtil.Print.Traceback( 2 ) end, ... ) end @@ -704,12 +644,12 @@ end --[[ Return a slice of an array table, python style would be written state[ start : stop : step ] in python - + start and stop are offsets rather than ordinals meaning 0 corresponds to the start of the array and -1 corresponds to the end -]] -function ModUtil.Slice( state, start, stop, step ) +--]] +function ModUtil.Array.Slice( state, start, stop, step ) local slice = { } local n = #state start = start or 0 @@ -726,102 +666,6 @@ function ModUtil.Slice( state, start, stop, step ) return slice end -local function ShallowCopyTable( orig ) - -- from UtilityScripts.lua - if orig == nil then - return - end - - local copy = { } - for k, v in pairs( orig ) do - copy[ k ] = v - end - return copy -end - -local function DeepCopyTable( orig ) - -- from UtilityScripts.lua - local orig_type = type( orig ) - local copy - if orig_type == 'table' then - copy = { } - -- slightly more efficient to call next directly instead of using pairs - for k, v in next, orig, nil do - copy[ k ] = DeepCopyTable( v ) - end - else - copy = orig - end - return copy -end - -ModUtil.Internal.MarkedForCollapse = { } - -function ModUtil.CollapseTable( tableArg ) - local collapsedTable = { } - local usedIndices = {} - local i = 1 - repeat - collapsedTable[ i ] = tableArg[ i ] - usedIndices[ i ] = true - i = i + 1 - until i > #tableArg - for k, v in pairs( tableArg ) do - if not usedIndices[ k ] then - collapsedTable[ i ] = v - i = i + 1 - end - end - return collapsedTable -end - -function ModUtil.CollapseTableInPlace( tableArg ) - local collapsedTable = ModUtil.CollapseTable( tableArg ) - for k in pairs( tableArg ) do - tableArg[ k ] = nil - end - for i, v in pairs( collapsedTable ) do - tableArg[ i ] = v - end -end - -function ModUtil.CollapseMarked( ) - for tbl, state in pairs( ModUtil.Internal.MarkedForCollapse ) do - if state then - ModUtil.CollapseTableInPlace( tbl ) - end - end - ModUtil.Internal.MarkedForCollapse = { } -end -OnAnyLoad{ ModUtil.CollapseMarked } - -function ModUtil.MarkForCollapse( tableArg ) - ModUtil.Internal.MarkedForCollapse[ tableArg ] = true -end - -function ModUtil.UnmarkForCollapse( tableArg ) - ModUtil.Internal.MarkedForCollapse[ tableArg ] = false -end - ---[[ - Safely create a new empty table at Table.key and return it. - - Table - the table to modify - key - the key at which to store the new empty table -]] -function ModUtil.NewTable( tableArg, key ) - local nodeType = ModUtil.Nodes.Index[ key ] - if nodeType then - return ModUtil.Nodes.Table[ nodeType ].New( tableArg ) - end - local tbl = tableArg[ key ] - if type( tbl ) ~= "table" then - tbl = { } - tableArg[ key ] = tbl - end - return tbl -end - --[[ Safely retrieve the a value from deep inside a table, given an array of indices into the table. @@ -833,16 +677,16 @@ end Table - the table to retrieve from indexArray - the list of indices -]] -function ModUtil.SafeGet( baseTable, indexArray ) +--]] +function ModUtil.IndexArray.Get( baseTable, indexArray ) local node = baseTable for _, key in ipairs( indexArray ) do if type( node ) ~= "table" then return nil end - local nodeType = ModUtil.Nodes.Index[ key ] + local nodeType = ModUtil.Nodes.Inverse[ key ] if nodeType then - node = ModUtil.Nodes.Table[ nodeType ].Get( node ) + node = ModUtil.Nodes.Data[ nodeType ].Get( node ) else node = node[ key ] end @@ -863,8 +707,8 @@ end baseTable - the table to set the value in indexArray - the list of indices value - the value to add -]] -function ModUtil.SafeSet( baseTable, indexArray, value ) +--]] +function ModUtil.IndexArray.Set( baseTable, indexArray, value ) if next( indexArray ) == nil then return false -- can't set the input argument end @@ -872,18 +716,18 @@ function ModUtil.SafeSet( baseTable, indexArray, value ) local node = baseTable for i = 1, n - 1 do local key = indexArray[ i ] - if not ModUtil.NewTable( node, key ) then return false end - local nodeType = ModUtil.Nodes.Index[ key ] + if not ModUtil.Table.New( node, key ) then return false end + local nodeType = ModUtil.Nodes.Inverse[ key ] if nodeType then - node = ModUtil.Nodes.Table[ nodeType ].Get( node ) + node = ModUtil.Nodes.Data[ nodeType ].Get( node ) else node = node[ key ] end end local key = indexArray[ n ] - local nodeType = ModUtil.Nodes.Index[ key ] + local nodeType = ModUtil.Nodes.Inverse[ key ] if nodeType then - return ModUtil.Nodes.Table[ nodeType ].Set( node, value ) + return ModUtil.Nodes.Data[ nodeType ].Set( node, value ) end node[ key ] = value return true @@ -920,12 +764,12 @@ end InnerBar = nil } } -]] -function ModUtil.MapNilTable( inTable, nilTable ) +--]] +function ModUtil.Table.NilMerge( inTable, nilTable ) for nilKey, nilVal in pairs( nilTable ) do local inVal = inTable[ nilKey ] if type( nilVal ) == "table" and type( inVal ) == "table" then - ModUtil.MapNilTable( inVal, nilVal ) + ModUtil.Table.NilMerge( inVal, nilVal ) else inTable[ nilKey ] = nil end @@ -958,26 +802,28 @@ end InnerBar = 8 } } -]] -function ModUtil.MapSetTable( inTable, setTable ) +--]] +function ModUtil.Table.Merge( inTable, setTable ) for setKey, setVal in pairs( setTable ) do local inVal = inTable[ setKey ] if type( setVal ) == "table" and type( inVal ) == "table" then - ModUtil.MapSetTable( inVal, setVal ) + ModUtil.Table.Merge( inVal, setVal ) else inTable[ setKey ] = setVal end end end --- Path Manipulation +function ModUtil.IndexArray.Map( baseTable, indexArray, map, ... ) + ModUtil.IndexArray.Set( baseTable, indexArray, map( ModUtil.IndexArray.Get( baseTable, indexArray ), ... ) ) +end --[[ Concatenates two index arrays, in order. a, b - the index arrays -]] -function ModUtil.JoinIndexArrays( a, b ) +--]] +function ModUtil.IndexArray.Join( a, b ) local c = { } local j = 0 for i, v in ipairs( a ) do @@ -990,15 +836,27 @@ function ModUtil.JoinIndexArrays( a, b ) return c end +-- Path Manipulation + +function ModUtil.Path.Map( path, map, ... ) + ModUtil.IndexArray.Map( _ENV, ModUtil.Path.IndexArray( path ), map, ... ) +end + +function ModUtil.Path.Join( a, b ) + if a == '' then return b end + if b == '' then return a end + return a .. '.' .. b +end + --[[ Create an index array from the provided Path. The returned array can be used as an argument to the safe table - manipulation functions, such as ModUtil.SafeSet and ModUtil.SafeGet. + manipulation functions, such as ModUtil.IndexArray.Set and ModUtil.IndexArray.Get. path - a dot-separated string that represents a path into a table -]] -function ModUtil.PathToIndexArray( path ) +--]] +function ModUtil.Path.IndexArray( path ) if type( path ) == "table" then return path end -- assume index array is given local s = "" local i = { } @@ -1019,55 +877,55 @@ end --[[ Safely get a value from a Path. - For example, ModUtil.PathGet( "a.b.c" ) returns a.b.c. + For example, ModUtil.Path.Get( "a.b.c" ) returns a.b.c. If either a or a.b is nil, nil is returned instead. path - the path to get the value base - (optional) The table to retreive the value from. If not provided, retreive a global. -]] -function ModUtil.PathGet( path, base ) - return ModUtil.SafeGet( base or _G, ModUtil.PathToIndexArray( path ) ) +--]] +function ModUtil.Path.Get( path, base ) + return ModUtil.IndexArray.Get( base or _ENV, ModUtil.Path.IndexArray( path ) ) end --[[ Safely get set a value to a Path. - For example, ModUtil.PathSet( "a.b.c", 1 ) sets a.b.c = 1. + For example, ModUtil.Path.Set( "a.b.c", 1 ) sets a.b.c = 1. If either a or a.b is nil, they are created. path - the path to get the value base - (optional) The table to retreive the value from. If not provided, retreive a global. -]] -function ModUtil.PathSet( path, value, base ) - return ModUtil.SafeSet( base or _G, ModUtil.PathToIndexArray( path ), value ) +--]] +function ModUtil.Path.Set( path, value, base ) + return ModUtil.IndexArray.Set( base or _ENV, ModUtil.Path.IndexArray( path ), value ) end --- Metaprogramming Shenanigans (EXPERIMENTAL) (WIP) +-- Metaprogramming Shenanigans local stackLevelProperty stackLevelProperty = { here = function( self ) - local thread = rawget( self, "thread" ) - local cursize = rawget( self, "level" ) + 1 + local thread = getObjectData( self, "thread" ) + local cursize = getObjectData( self, "level" ) + 1 while debug.getinfo( thread, cursize, "f" ) do cursize = cursize + 1 end - return cursize - rawget( self, "size" ) - 1 + return cursize - getObjectData( self, "size" ) - 1 end, top = function( self ) - local thread = rawget( self, "thread" ) - local level = rawget( self, "level" ) + local thread = getObjectData( self, "thread" ) + local level = getObjectData( self, "level" ) local cursize = level + 1 while debug.getinfo( thread, cursize, "f" ) do cursize = cursize + 1 end return cursize - level - 1 end, - there = function( self ) return rawget( self, "level" ) end, - bottom = function( self ) return rawget( self, "size" ) end, - co = function( self ) return rawget( self, "thread" ) end, + there = function( self ) return getObjectData( self, "level" ) end, + bottom = function( self ) return getObjectData( self, "size" ) end, + co = function( self ) return getObjectData( self, "thread" ) end, func = function( self ) return debug.getinfo( self.co, self.here, "f" ).func end @@ -1100,12 +958,6 @@ local stackLevelFunction = { end, upvaluejoin = function( self, ... ) return debug.upvaluejoin( self.func, ... ) - end, - getfenv = function( self, ... ) - return getfenv( self.func, ... ) - end, - setfenv = function( self, ... ) - return setfenv( self.func, ... ) end } @@ -1148,9 +1000,9 @@ ModUtil.Metatables.StackLevel = { return function( ) end, self end, __eq = function( self, other ) - return rawget( self, "thread" ) == rawget( other, "thread" ) - and rawget( self, "size" ) == rawget( other, "size") - and rawget( self, "level" ) == rawget( other, "level") + return getObjectData( self, "thread" ) == getObjectData( other, "thread" ) + and getObjectData( self, "size" ) == getObjectData( other, "size") + and getObjectData( self, "level" ) == getObjectData( other, "level") end } @@ -1164,19 +1016,17 @@ function ModUtil.StackLevel( level ) end size = size - level - 1 if size > 0 then - local stackLevel = { level = level, size = size, thread = thread } - setmetatable( stackLevel, ModUtil.Metatables.StackLevel ) - return stackLevel + return ModUtil.ObjectDataProxy( { level = level, size = size, thread = thread }, ModUtil.Metatables.StackLevel ) end end ModUtil.Metatables.StackLevels = { __index = function( self, level ) - return ModUtil.StackLevel( ( level or 0 ) + rawget( self, "level" ).here ) + return ModUtil.StackLevel( ( level or 0 ) + getObjectData( self, "level" ).here ) end, - __newindex = function() end, + __newindex = function( ) end, __len = function( self ) - return rawget( self, "level" ).bottom + return getObjectData( self, "level" ).bottom end, __next = function( self, level ) level = ( level or 0 ) + 1 @@ -1193,13 +1043,77 @@ ModUtil.Metatables.StackLevels.__ipairs = ModUtil.Metatables.StackLevels.__pairs ModUtil.Metatables.StackLevels.__inext = ModUtil.Metatables.StackLevels.__next function ModUtil.StackLevels( level ) - local levels = { level = ModUtil.StackLevel( level or 0 ) } - setmetatable( levels, ModUtil.Metatables.StackLevels ) - return levels + return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( level or 0 ) }, ModUtil.Metatables.StackLevels ) end + local excludedUpValueNames = ToLookup{ "_ENV" } +ModUtil.Metatables.UpValues = { + __index = function( self, name ) + if excludedUpValueNames[ name ] then return end + local func = getObjectData( self, "func" ) + local idx = 0 + repeat + idx = idx + 1 + local n, value = debug.getupvalue( func, idx ) + if n == name then + return value + end + until not n + end, + __newindex = function( self, name, value ) + if excludedUpValueNames[ name ] then return end + local func = getObjectData( self, "func" ) + local idx = name and 0 or -1 + repeat + idx = idx + 1 + local n = debug.getupvalue( func, idx ) + if n == name then + debug.setupvalue( func, idx, value ) + return + end + until not n + end, + __len = function( ) + return 0 + end, + __next = function( self, name ) + local func = getObjectData( self, "func" ) + local idx = name and 0 or -1 + repeat + idx = idx + 1 + local n = debug.getupvalue( func, idx ) + if n == name then + local value + repeat + idx = idx + 1 + n, value = debug.getupvalue( func, idx ) + if n and not excludedUpValueNames[ n ] then + return n, value + end + until not n + end + until not n + end, + __inext = function( ) end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return function( ) end, self + end +} + +setmetatable( ModUtil.UpValues, { + __call = function( _, func ) + if type( func ) ~= "function" then + func = debug.getinfo( ( func or 1 ) + 1, "f" ).func + end + return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues ) + end +}) + local idData = { } setmetatable( idData, { __mode = "k" } ) @@ -1211,7 +1125,7 @@ end local function setUpValueIdData( id, func, idx ) local tbl = idData[ id ] if not tbl then - tbl = {} + tbl = { } idData[ id ] = tbl end tbl.func, tbl.idx = func, idx @@ -1224,9 +1138,9 @@ function debug.upvaluejoin( f1, n1, f2, n2 ) setUpValueIdData( debug.upvalueid( f1, n1 ), f2, n2 ) end -ModUtil.Metatables.UpValueIds = { +ModUtil.Metatables.UpValues.Ids = { __index = function( self, idx ) - local func = rawget( self, "func" ) + local func = getObjectData( self, "func" ) local name = debug.getupvalue( func, idx ) if name and not excludedUpValueNames[ name ] then local id = debug.upvalueid( func, idx ) @@ -1235,7 +1149,7 @@ ModUtil.Metatables.UpValueIds = { end end, __newindex = function( self, idx, value ) - local func = rawget( self, "func" ) + local func = getObjectData( self, "func" ) local name = debug.getupvalue( func, idx ) if name and not excludedUpValueNames[ name ] then local func2, idx2 = getUpValueIdData( value ) @@ -1244,10 +1158,10 @@ ModUtil.Metatables.UpValueIds = { end end, __len = function( self ) - return debug.getinfo( rawget( self, "func" ), 'u' ).nups + return debug.getinfo( getObjectData( self, "func" ), 'u' ).nups end, __next = function ( self, idx ) - local func = rawget( self, "func" ) + local func = getObjectData( self, "func" ) idx = idx or 0 local name while true do @@ -1263,27 +1177,25 @@ ModUtil.Metatables.UpValueIds = { return qrawpairs( self ) end } -ModUtil.Metatables.UpValueIds.__inext = ModUtil.Metatables.UpValueIds.__next -ModUtil.Metatables.UpValueIds.__ipairs = ModUtil.Metatables.UpValueIds.__pairs +ModUtil.Metatables.UpValues.Ids.__inext = ModUtil.Metatables.UpValues.Ids.__next +ModUtil.Metatables.UpValues.Ids.__ipairs = ModUtil.Metatables.UpValues.Ids.__pairs -function ModUtil.UpValueIds( func ) +function ModUtil.UpValues.Ids( func ) if type(func) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end - local ups = { func = func } - setmetatable( ups, ModUtil.Metatables.UpValueIds ) - return ups + return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues.Ids ) end -ModUtil.Metatables.UpValueValues = { +ModUtil.Metatables.UpValues.Values = { __index = function( self, idx ) - local name, value = debug.getupvalue( rawget( self, "func" ), idx ) + local name, value = debug.getupvalue( getObjectData( self, "func" ), idx ) if name and not excludedUpValueNames[ name ] then return value end end, __newindex = function( self, idx, value ) - local func = rawget( self, "func" ) + local func = getObjectData( self, "func" ) local name = debug.getupvalue( func, idx ) if name and not excludedUpValueNames[ name ] then debug.setupvalue( func, idx, value ) @@ -1291,10 +1203,10 @@ ModUtil.Metatables.UpValueValues = { end end, __len = function( self ) - return debug.getinfo( rawget( self, "func" ), 'u' ).nups + return debug.getinfo( getObjectData( self, "func" ), 'u' ).nups end, __next = function ( self, idx ) - local func = rawget( self, "func" ) + local func = getObjectData( self, "func" ) idx = idx or 0 local name, value while true do @@ -1306,31 +1218,29 @@ ModUtil.Metatables.UpValueValues = { end end end, - __pairs = ModUtil.Metatables.UpValueIds.__pairs, - __ipairs = ModUtil.Metatables.UpValueIds.__ipairs + __pairs = ModUtil.Metatables.UpValues.Ids.__pairs, + __ipairs = ModUtil.Metatables.UpValues.Ids.__ipairs } -ModUtil.Metatables.UpValueValues.__inext = ModUtil.Metatables.UpValueValues.__next +ModUtil.Metatables.UpValues.Values.__inext = ModUtil.Metatables.UpValues.Values.__next -function ModUtil.UpValueValues( func ) +function ModUtil.UpValues.Values( func ) if type(func) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end - local ups = { func = func } - setmetatable( ups, ModUtil.Metatables.UpValueValues ) - return ups + return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues.Values ) end -ModUtil.Metatables.UpValueNames = { +ModUtil.Metatables.UpValues.Names = { __index = function( self, idx ) - local name = debug.getupvalue( rawget( self, "func" ), idx ) + local name = debug.getupvalue( getObjectData( self, "func" ), idx ) if name and not excludedUpValueNames[ name ] then return name end end, __newindex = function( ) end, - __len = ModUtil.Metatables.UpValueValues.__len, + __len = ModUtil.Metatables.UpValues.Values.__len, __next = function ( self, idx ) - local func = rawget( self, "func" ) + local func = getObjectData( self, "func" ) idx = idx or 0 local name while true do @@ -1342,98 +1252,22 @@ ModUtil.Metatables.UpValueNames = { end end end, - __pairs = ModUtil.Metatables.UpValueIds.__pairs, - __ipairs = ModUtil.Metatables.UpValueIds.__ipairs + __pairs = ModUtil.Metatables.UpValues.Ids.__pairs, + __ipairs = ModUtil.Metatables.UpValues.Ids.__ipairs } -ModUtil.Metatables.UpValueNames.__inext = ModUtil.Metatables.UpValueNames.__next +ModUtil.Metatables.UpValues.Names.__inext = ModUtil.Metatables.UpValues.Names.__next -function ModUtil.UpValueNames( func ) +function ModUtil.UpValues.Names( func ) if type(func) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end - local ups = { func = func } - setmetatable( ups, ModUtil.Metatables.UpValueNames ) - return ups + return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues.Names ) end -ModUtil.Metatables.UpValues = { +ModUtil.Metatables.UpValues.Stacked = { __index = function( self, name ) if excludedUpValueNames[ name ] then return end - local func = rawget( self, "func" ) - local idx = 0 - repeat - idx = idx + 1 - local n, value = debug.getupvalue( func, idx ) - if n == name then - return value - end - until not n - end, - __newindex = function( self, name, value ) - if excludedUpValueNames[ name ] then return end - local func = rawget( self, "func" ) - local idx = name and 0 or -1 - repeat - idx = idx + 1 - local n = debug.getupvalue( func, idx ) - if n == name then - debug.setupvalue( func, idx, value ) - return - end - until not n - end, - __len = function ( self ) - return 0 - end, - __next = function ( self, name ) - local func = rawget( self, "func" ) - local idx = name and 0 or -1 - repeat - idx = idx + 1 - local n = debug.getupvalue( func, idx ) - if n == name then - local value - repeat - idx = idx + 1 - n, value = debug.getupvalue( func, idx ) - if n and not excludedUpValueNames[ n ] then - return n, value - end - until not n - end - until not n - end, - __inext = function() end, - __pairs = function( self ) - return qrawpairs( self ) - end, - __ipairs = function( self ) - return function() end, self - end -} - ---[[ - Return a table representing the upvalues of a function. - - Upvalues are those variables captured by a function from it's - creation context. For example, locals defined in the same file - as the function are accessible to the function as upvalues. - - func - the function to get upvalues from -]] -function ModUtil.UpValues( func ) - if type(func) ~= "function" then - func = debug.getinfo( ( func or 1 ) + 1, "f" ).func - end - local upValues = { func = func } - setmetatable( upValues, ModUtil.Metatables.UpValues ) - return upValues -end - -ModUtil.Metatables.StackedUpValues = { - __index = function( self, name ) - if excludedUpValueNames[ name ] then return end - for _, level in pairs( rawget( self, "levels" ) ) do + for _, level in pairs( getObjectData( self, "levels" ) ) do local idx = 0 repeat idx = idx + 1 @@ -1446,7 +1280,7 @@ ModUtil.Metatables.StackedUpValues = { end, __newindex = function( self, name, value ) if excludedUpValueNames[ name ] then return end - for _, level in pairs( rawget( self, "levels" ) ) do + for _, level in pairs( getObjectData( self, "levels" ) ) do local idx = 0 repeat idx = idx + 1 @@ -1462,7 +1296,7 @@ ModUtil.Metatables.StackedUpValues = { return 0 end, __next = function( self, name ) - local levels = rawget( self, "levels" ) + local levels = getObjectData( self, "levels" ) for _, level in pairs( levels ) do local idx = name and 0 or -1 repeat @@ -1486,21 +1320,81 @@ ModUtil.Metatables.StackedUpValues = { return qrawpairs( self ), self end, __ipairs = function( self ) - return function() end, self + return function( ) end, self end } -function ModUtil.StackedUpValues( level ) - local upValues = { levels = ModUtil.StackLevels( ( level or 1 ) ) } - setmetatable( upValues, ModUtil.Metatables.StackedUpValues ) - return upValues +function ModUtil.UpValues.Stacked( level ) + return ModUtil.ObjectDataProxy( { levels = ModUtil.StackLevels( ( level or 1 ) ) }, ModUtil.Metatables.UpValues.Stacked ) end local excludedLocalNames = ToLookup{ "(*temporary)", "(for generator)", "(for state)", "(for control)" } -ModUtil.Metatables.LocalValues = { +ModUtil.Metatables.Locals = { + __index = function( self, name ) + if excludedLocalNames[ name ] then return end + local level = getObjectData( self, "level" ) + local idx = 0 + repeat + idx = idx + 1 + local n, v = level.getlocal( level, idx ) + if n == name then + return v + end + until not n + end, + __newindex = function( self, name, value ) + if excludedLocalNames[ name ] then return end + local level = getObjectData( self, "level" ) + local idx = 0 + repeat + idx = idx + 1 + local n = level.getlocal( idx ) + if n == name then + level.setlocal( idx, value ) + return + end + until not n + end, + __len = function( ) + return 0 + end, + __next = function( self, name ) + local level = getObjectData( self, "level" ) + local idx = name and 0 or -1 + repeat + idx = idx + 1 + local n = level.getlocal( idx ) + if name and n == name or not name then + local value + repeat + idx = idx + 1 + n, value = level.getlocal( idx ) + if n and not excludedLocalNames[ n ] then + return n, value + end + until not n + end + until not n + end, + __inext = function( ) return end, + __pairs = function( self ) + return qrawpairs( self ), self + end, + __ipairs = function( self ) + return function( ) end, self + end +} + +setmetatable( ModUtil.Locals, { + __call = function( _, level ) + return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) + end +} ) + +ModUtil.Metatables.Locals.Values = { __index = function( self, idx ) - local name, value = rawget( self, "level" ).getlocal( idx ) + local name, value = getObjectData( self, "level" ).getlocal( idx ) if name then if not excludedLocalNames[ name ] then return value @@ -1508,7 +1402,7 @@ ModUtil.Metatables.LocalValues = { end end, __newindex = function( self, idx, value ) - local level = rawget( self, "level" ) + local level = getObjectData( self, "level" ) local name = level.getlocal( idx ) if name then if not excludedLocalNames[ name ] then @@ -1517,7 +1411,7 @@ ModUtil.Metatables.LocalValues = { end end, __len = function( self ) - local level = rawget( self, "level" ) + local level = getObjectData( self, "level" ) local idx = 1 while level.getlocal( level, idx ) do idx = idx + 1 @@ -1527,7 +1421,7 @@ ModUtil.Metatables.LocalValues = { __next = function( self, idx ) idx = idx or 0 idx = idx + 1 - local name, val = rawget( self, "level" ).getlocal( idx ) + local name, val = getObjectData( self, "level" ).getlocal( idx ) if name then if not excludedLocalNames[ name ] then return idx, val @@ -1538,25 +1432,22 @@ ModUtil.Metatables.LocalValues = { return qrawpairs( self ), self end, } -ModUtil.Metatables.LocalValues.__ipairs = ModUtil.Metatables.LocalValues.__pairs -ModUtil.Metatables.LocalValues.__inext = ModUtil.Metatables.LocalValues.__next +ModUtil.Metatables.Locals.Values.__ipairs = ModUtil.Metatables.Locals.Values.__pairs +ModUtil.Metatables.Locals.Values.__inext = ModUtil.Metatables.Locals.Values.__next --[[ Example Use: - for i, name, value in pairs( ModUtil.LocalValues( level ) ) do - -- + for i, value in pairs( ModUtil.Locals.Values( level ) ) do + -- stuff end -]] -function ModUtil.LocalValues( level ) - if level == nil then level = 1 end - local locals = { level = ModUtil.StackLevel( level + 1 ) } - setmetatable( locals, ModUtil.Metatables.LocalValues ) - return locals +--]] +function ModUtil.Locals.Values( level ) + return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals.Values ) end -ModUtil.Metatables.LocalNames = { +ModUtil.Metatables.Locals.Names = { __index = function( self, idx ) - local name = rawget( self, "level" ).getlocal( idx ) + local name = getObjectData( self, "level" ).getlocal( idx ) if name then if not excludedLocalNames[ name ] then return name @@ -1564,11 +1455,11 @@ ModUtil.Metatables.LocalNames = { end end, __newindex = function( ) return end, - __len = ModUtil.Metatables.LocalValues.__len, + __len = ModUtil.Metatables.Locals.Values.__len, __next = function( self, idx ) if idx == nil then idx = 0 end idx = idx + 1 - local name = rawget( self, "level" ).getlocal( idx ) + local name = getObjectData( self, "level" ).getlocal( idx ) if name then if not excludedLocalNames[ name ] then return idx, name @@ -1579,89 +1470,23 @@ ModUtil.Metatables.LocalNames = { return qrawpairs( self ), self end, } -ModUtil.Metatables.LocalNames.__ipairs = ModUtil.Metatables.LocalNames.__pairs -ModUtil.Metatables.LocalNames.__inext = ModUtil.Metatables.LocalNames.__next +ModUtil.Metatables.Locals.Names.__ipairs = ModUtil.Metatables.Locals.Names.__pairs +ModUtil.Metatables.Locals.Names.__inext = ModUtil.Metatables.Locals.Names.__next --[[ Example Use: - for i, name, value in pairs( ModUtil.LocalNames( level ) ) do - -- - end -]] --- WORKS -function ModUtil.LocalNames( level ) - if level == nil then level = 1 end - local locals = { level = ModUtil.StackLevel( level + 1 ) } - setmetatable( locals, ModUtil.Metatables.LocalNames ) - return locals -end - -ModUtil.Metatables.Locals = { - __index = function( self, name ) - if excludedLocalNames[ name ] then return end - local level = rawget( self, "level" ) - local idx = 0 - repeat - idx = idx + 1 - local n, v = level.getlocal( level, idx ) - if n == name then - return v - end - until not n - end, - __newindex = function( self, name, value ) - if excludedLocalNames[ name ] then return end - local level = rawget( self, "level" ) - local idx = 0 - repeat - idx = idx + 1 - local n = level.getlocal( idx ) - if n == name then - level.setlocal( idx, value ) - return - end - until not n - end, - __len = function( ) - return 0 - end, - __next = function( self, name ) - local level = rawget( self, "level" ) - local idx = name and 0 or -1 - repeat - idx = idx + 1 - local n = level.getlocal( idx ) - if name and n == name or not name then - local value - repeat - idx = idx + 1 - n, value = level.getlocal( idx ) - if n and not excludedLocalNames[ n ] then - return n, value - end - until not n - end - until not n - end, - __inext = function( ) return end, - __pairs = function( self ) - return qrawpairs( self ), self - end, - __ipairs = function( self ) - return function( ) end, self + for i, name in pairs( ModUtil.Locals.Names( level ) ) do + -- stuff end -} - -function ModUtil.Locals( level ) - local locals = { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) } - setmetatable( locals, ModUtil.Metatables.Locals ) - return locals +--]] +function ModUtil.Locals.Names( level ) + return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals.Names ) end -ModUtil.Metatables.StackedLocals = { +ModUtil.Metatables.Locals.Stacked = { __index = function( self, name ) if excludedLocalNames[ name ] then return end - for _, level in pairs( rawget( self, "levels" ) ) do + for _, level in pairs( getObjectData( self, "levels" ) ) do local idx = 0 repeat idx = idx + 1 @@ -1674,7 +1499,7 @@ ModUtil.Metatables.StackedLocals = { end, __newindex = function( self, name, value ) if excludedLocalNames[ name ] then return end - for _, level in pairs( rawget( self, "levels" ) ) do + for _, level in pairs( getObjectData( self, "levels" ) ) do local idx = 0 repeat idx = idx + 1 @@ -1690,7 +1515,7 @@ ModUtil.Metatables.StackedLocals = { return 0 end, __next = function( self, name ) - local levels = rawget( self, "levels" ) + local levels = getObjectData( self, "levels" ) for _, level in pairs( levels ) do local idx = name and 0 or -1 repeat @@ -1714,7 +1539,7 @@ ModUtil.Metatables.StackedLocals = { return qrawpairs( self ), self end, __ipairs = function( self ) - return function() end, self + return function( ) end, self end } @@ -1724,1189 +1549,615 @@ ModUtil.Metatables.StackedLocals = { be used. For example, if your function is called from CreateTraitRequirements, - you could access its 'local screen' as ModUtil.StackedLocals().screen - and its 'local hasRequirement' as ModUtil.StackedLocals().hasRequirement. -]] -function ModUtil.StackedLocals( level ) - local locals = { levels = ModUtil.StackLevels( ( level or 1 ) ) } - setmetatable( locals, ModUtil.Metatables.StackedLocals ) - return locals + you could access its 'local screen' as ModUtil.Locals.Stacked( ).screen + and its 'local hasRequirement' as ModUtil.Locals.Stacked( ).hasRequirement. +--]] +function ModUtil.Locals.Stacked( level ) + return ModUtil.ObjectDataProxy( { levels = ModUtil.StackLevels( level or 1 ) }, ModUtil.Metatables.Locals.Stacked ) end --- Function Wrapping - -ModUtil.Internal.WrapCallbacks = { } - ---[[ - Wrap a function, so that you can insert code that runs before/after that function - whenever it's called, and modify the return value if needed. - - Generally, you should use ModUtil.WrapBaseFunction instead for a more modder-friendly - interface. +-- Entangled Data Structures - Multiple wrappers can be applied to the same function. +ModUtil.Metatables.Entangled = { } - As an example, for WrapFunction( _G, { "UIFunctions", "OnButton1Pushed" }, wrapper, MyMod ) +ModUtil.Metatables.Entangled.Map = { - Wrappers are stored in a structure like this: + Data = { + __index = function( self, key ) + return getObjectData( self, "Map" )[ key ] + end, + __newindex = function( self, key, value ) + local data = getObjectData( self, "Map" ) + local prevValue = data[ key ] + data[ key ] = value + local preImage = getObjectData( self, "PreImage" ) + local prevKeys + if prevValue ~= nil then + prevKeys = preImage[ prevValue ] + end + local keys = preImage[ value ] + if not keys then + keys = { } + preImage[ value ] = keys + end + if prevKeys then + prevKeys[ key ] = nil + end + keys[ key ] = true + end, + __len = function( self ) + return #getObjectData( self, "Map" ) + end, + __next = function( self, key ) + return next( getObjectData( self, "Map" ), key ) + end, + __inext = function( self, idx ) + return inext( getObjectData( self, "Map" ), idx ) + end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return qrawipairs( self ) + end + }, - ModUtil.Internal.WrapCallbacks[ _G ].UIFunctions.OnButton1Pushed = { - { id = 1, mod = MyMod, wrap=wrapper, func = } - } + PreImage = { + __index = function( self, value ) + return getObjectData( self, "PreImage" )[ value ] + end, + __newindex = function( self, value, keys ) + getObjectData( self, "PreImage" )[ value ] = keys + local data = getObjectData( self, "Map" ) + for key in pairs( data ) do + data[ key ] = nil + end + for key in ipairs( keys ) do + data[ key ] = value + end + end, + __len = function( self ) + return #getObjectData( self, "PreImage" ) + end, + __next = function( self, key ) + return next( getObjectData( self, "PreImage" ), key ) + end, + __inext = function( self, idx ) + return inext( getObjectData( self, "PreImage" ), idx ) + end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return qrawipairs( self ) + end + }, - If a second wrapper is applied via - WrapFunction( _G, { "UIFunctions", "OnButton1Pushed" }, wrapperFunction2, SomeOtherMod ) - then the resulting structure will be like: + Unique = { + + Data = { + __index = function( self, key ) + return getObjectData( self, "Data" )[ key ] + end, + __newindex = function( self, key, value ) + local data, inverse = getObjectData( self, "Data" ), getObjectData( self, "Inverse" ) + if value ~= nil then + local k = inverse[ value ] + if k ~= key then + if k ~= nil then + data[ k ] = nil + end + inverse[ value ] = key + end + end + if key ~= nil then + local v = data[ key ] + if v ~= value then + if v ~= nil then + inverse[ v ] = nil + end + data[ key ] = value + end + end + end, + __len = function( self ) + return #getObjectData( self, "Data" ) + end, + __next = function( self, key ) + return next( getObjectData( self, "Data" ), key ) + end, + __inext = function( self, idx ) + return inext( getObjectData( self, "Data" ), idx ) + end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return qrawipairs( self ) + end + }, + + Inverse = { + __index = function( self, value ) + return getObjectData( self, "Inverse" )[ value ] + end, + __newindex = function( self, value, key ) + local data, inverse = getObjectData( self, "Data" ), getObjectData( self, "Inverse" ) + if value ~= nil then + local k = inverse[ value ] + if k ~= key then + if k ~= nil then + data[ k ] = nil + end + inverse[ value ] = key + end + end + if key ~= nil then + local v = data[ key ] + if v ~= value then + if v ~= nil then + inverse[ v ] = nil + end + data[ key ] = value + end + end + end, + __len = function( self ) + return #getObjectData( self, "Inverse" ) + end, + __next = function( self, value ) + return next( getObjectData( self, "Inverse" ), value ) + end, + __inext = function( self, idx ) + return inext( getObjectData( self, "Inverse" ), idx ) + end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return qrawipairs( self ) + end + } - ModUtil.Internal.WrapCallbacks[ _G ].UIFunctions.OnButton1Pushed = { - { id = 1, mod = MyMod, wrap = wrapper, func = } - { id = 2, mod = SomeOtherMod, wrap = wrapper2, func = } } - This allows several mods to apply wrappers to the same base function, and then: - - unwrap again later - - reapply the same wrappers to a new base function when it's overridden - - This function also updates the entry in funcTable at indexArray to be the completely - wrapped function, ie. in our example with two wrappers it would do +} - UIFunctions.OnButton1Pushed = +ModUtil.Entangled.Map = { + Unique = { } +} - funcTable - the table the function is stored in (usually _G) - indexArray - the array of path elements to the function in the table - wrapFunc - the wrapping function - mod - (optional) the mod installing the wrapper, for informational purposes -]] -function ModUtil.WrapFunction( funcTable, indexArray, wrapFunc, mod ) - if type( wrapFunc ) ~= "function" then return end - if not funcTable then return end - local func = ModUtil.SafeGet( funcTable, indexArray ) - if type( func ) ~= "function" then return end - - ModUtil.NewTable( ModUtil.Internal.WrapCallbacks, funcTable ) - local tempTable = ModUtil.SafeGet( ModUtil.Internal.WrapCallbacks[ funcTable ], indexArray ) - if tempTable == nil then - tempTable = { } - ModUtil.SafeSet( ModUtil.Internal.WrapCallbacks[ funcTable ], indexArray, tempTable ) - end - table.insert( tempTable, { Id = #tempTable + 1, Mod = mod, Wrap = wrapFunc, Func = func } ) - - ModUtil.SafeSet( skipenv( funcTable ), indexArray, function( ... ) - return wrapFunc( func, ... ) - end ) -end +setmetatable( ModUtil.Entangled.Map, { + __call = function( ) + local data, preImage = { }, { } + data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } + data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) + preImage = ModUtil.ObjectDataProxy( preImage, ModUtil.Metatables.Entangled.Map.PreImage ) + return { Data = data, Index = preImage, PreImage = preImage } + end +} ) ---[[ - Internal utility that reapplies the list of wrappers when the base function changes. +setmetatable( ModUtil.Entangled.Map.Unique, { + __call = function( ) + local data, inverse = { }, { } + data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } + data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) + inverse = ModUtil.ObjectDataProxy( inverse, ModUtil.Metatables.Entangled.Map.Unique.Inverse ) + return { Data = data, Index = inverse, Inverse = inverse } + end +} ) - For example. if the list of wrappers looks like: - ModUtil.Internal.WrapCallbacks[ _G ].UIFunctions.OnButton1Pushed = { - { id = 1, mod = MyMod, wrap = wrapper, func = } - { id = 2, mod = SomeOtherMod, wrap = wrapper2, func = } - { id = 3, mod = ModNumber3, wrap = wrapper3, func = } - } +-- Context Managers ( EXPERIMENTAL ) ( BROKEN ) - and the base function is modified by setting [ 1 ].func to a new value, like so: - ModUtil.Internal.WrapCallbacks[ _G ].UIFunctions.OnButton1Pushed = { - { id = 1, mod = MyMod, wrap = wrapper, func = } - { id = 2, mod = SomeOtherMod, wrap = wrapper2, func = } - { id = 3, mod = ModNumber3, wrap = wrapper3, func = } - } +ModUtil.Context = { } - Then rewrap function will fix up eg. [ 2 ].func, [ 3 ].func so that the correct wrappers are applied - ModUtil.Internal.WrapCallbacks[ _G ].UIFunctions.OnButton1Pushed = { - { id = 1, mod = MyMod, wrap = wrapper, func = } - { id = 2, mod = SomeOtherMod, wrap = wrapper2, func = } - { id = 3, mod = ModNumber3, wrap = wrapper3, func = } - } - and also update the entry in funcTable to be the completely wrapped function, ie. +local threadContexts = { } +setmetatable( threadContexts, { __mode = "kv" } ) - UIFunctions.OnButton1Pushed = +ModUtil.Metatables.Context = { + __call = function( self, callContext, ... ) - funcTable - the table the function is stored in (usually _G) - indexArray - the array of path elements to the function in the table -]] -function ModUtil.RewrapFunction( funcTable, indexArray ) - local wrapCallbacks = ModUtil.SafeGet( ModUtil.Internal.WrapCallbacks[ funcTable ], indexArray ) - local preFunc = nil + local thread = coroutine.running( ) - for _, tempTable in ipairs( wrapCallbacks ) do - if preFunc then - tempTable.Func = preFunc - end - preFunc = function( ... ) - return tempTable.Wrap( tempTable.Func, ... ) - end - ModUtil.SafeSet( skipenv( funcTable ), indexArray, preFunc ) - end + local contextInfo = { + call = callContext, + wrap = function( ... ) callContext( ... ) end, + parent = threadContexts[ thread ], + thread = thread + } -end + threadContexts[ thread ] = contextInfo ---[[ - Removes the most recent wrapper from a function, and restore it to its - previous value. + contextInfo.context = self + contextInfo.args = table.pack( ... ) + contextInfo.data = { } + contextInfo.params = table.pack( getObjectData( self, "callContextProcessor" )( contextInfo ) ) - Generally, you should use ModUtil.UnwrapBaseFunction instead for a more - modder-friendly interface. + local penv = threadEnvironments[ thread ] + local env = setmetatable( { }, { __index = ( penv or _G ), __newindex = ( penv or _G ) } ) + threadEnvironments[ thread ] = env - funcTable - the table the function is stored in (usually _G) - indexArray - the array of path elements to the function in the table -]] -function ModUtil.UnwrapFunction( funcTable, indexArray ) - if not funcTable then return end - local func = ModUtil.SafeGet( skipenv( funcTable ), indexArray ) - if type( func ) ~= "function" then return end + contextInfo.response = table.pack( contextInfo.wrap( table.unpack( contextInfo.params ) ) ) - local tempTable = ModUtil.SafeGet( ModUtil.Internal.WrapCallbacks[ funcTable ], indexArray ) - if not tempTable then return end - local funcData = table.remove( tempTable ) -- removes the last value - if not funcData then return end + if getObjectData( self, "postCall" ) then + contextInfo.final = table.pack( getObjectData( self, "postCall" )( contextInfo ) ) + end - ModUtil.SafeSet( skipenv( funcTable ), indexArray, funcData.Func ) - return funcData -end + threadEnvironments[ thread ] = penv + threadContexts[ thread ] = contextInfo.parent + if contextInfo.final then + return table.unpack( contextInfo.final ) + end + end +} ---[[ - Wraps the function with the path given by baseFuncPath, so that you - can execute code before or after the original function is called, - or modify the return value. - - For example: - - ModUtil.WrapBaseFunction( "CreateNewHero", function( baseFunc, prevRun, args ) - local hero = baseFunc( prevRun, args ) - hero.Health = 1 - return hero - end, YourMod ) - - will cause the function CreateNewHero to be wrapped so that the hero's - health is set to 1 before the hero is returned. - - This provides better compatibility with other mods that overriding the - function, since multiple mods can wrap the same function. - - baseFuncPath - the (global) path to the function, as a string - for most SGG-provided functions, this is just the function's name - eg. "CreateRoomReward" or "SetTraitsOnLoot" - wrapFunc - the function to wrap around the base function - this function receives the base function as its first parameter. - all subsequent parameters should be the same as the base function - mod - (optional) the object for your mod, for debug purposes -]] -function ModUtil.WrapBaseFunction( baseFuncPath, wrapFunc, mod ) - local pathArray = ModUtil.PathToIndexArray( baseFuncPath ) - ModUtil.WrapFunction( _G, pathArray, wrapFunc, mod ) -end +setmetatable( ModUtil.Context, { + __call = function( _, callContextProcessor, postCall ) + return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) + end +} ) ---[[ - Internal function that reapplies all the wrappers to a function. -]] -function ModUtil.RewrapBaseFunction( baseFuncPath ) - local pathArray = ModUtil.PathToIndexArray( baseFuncPath ) - ModUtil.RewrapFunction( _G, pathArray ) -end +ModUtil.Context.Data = ModUtil.Context( function( info ) + local tbl = info.args[ 1 ] + info.env = setmetatable( { }, { + __index = function( _, key ) return tbl[ key ] or __G[ key ] end, + __newindex = tbl + } ) +end ) ---[[ - Remove the most recent wrapper from the function at baseFuncPath, - restoring it to its previous state +ModUtil.Context.Meta = ModUtil.Context( function( info ) + local tbl = ModUtil.Nodes.Data.Metatable.New( info.args[ 1 ] ) + info.env = setmetatable( { }, { + __index = function( _, key ) return tbl[ key ] or __G[ key ] end, + __newindex = tbl + } ) +end ) - Note that this does _not_ remove overrides, and it removes the most - recent wrapper regardless of which mod added it, so be careful! +local fenvData = setmetatable( { }, { __mode = "k" } ) - baseFuncPath - the (global) path to the function, as a string - for most SGG-provided functions, this is just the function's name - eg. "CreateRoomReward" or "SetTraitsOnLoot" -]] -function ModUtil.UnwrapBaseFunction( baseFuncPath ) - local pathArray = ModUtil.PathToIndexArray( baseFuncPath ) - ModUtil.UnwrapFunction( _G, pathArray ) -end +ModUtil.Context.Env = ModUtil.Context( function( info ) + local func = info.args[ 1 ] + local fenv = fenvData[ func ] + if not fenv then + fenv = getfenv( func ) or { } + fenvData[ func ] = fenv + end + setfenv( func, setmetatable( { }, { + __index = function( _, key ) + local val + local env = threadEnvironments[ coroutine.running( ) ] + if env then + val = env[ key ] + end + if val ~= nil then return val end + val = fenv[ key ] + if val ~= nil then return val end + return _G[ key ] + end, + __newindex = function( _, key, val ) + local env = threadEnvironments[ coroutine.running( ) ] + if env and env[ key ] ~= nil then + env[ key ] = val + elseif fenv[ key ] ~= nil then + fenv[ key ] = val + end + _G[ key ] = val + end + } ) ) + info.env = setmetatable( { }, { + __index = function( _, key ) return fenv[ key ] or __G[ key ] end, + __newindex = fenv + } ) +end ) --- Override Management +ModUtil.Context.Call = ModUtil.Context( + function( info ) + local meta + local penv = threadEnvironments[ info.thread ] + local func = info.args[ 1 ] + + meta = { + __index = function( _, key ) + local data = fenvData[ func ] + if data then + local val = data[ key ] + if val ~= nil then return val end + end + return ( penv or _G )[ key ] + end, + __newindex = function( _, key, val ) + local data = fenvData[ func ] + if data and data[ key ] ~= nil then + data[ key ] = val + else + ( penv or _G )[ key ] = val + end + end + } -ModUtil.Internal.Overrides = { } + local env = setmetatable( { }, meta ) + info.env = setmetatable( { }, { __index = env, __newindex = ModUtil.RawInterface( env ) } ) -local function getBaseValueForWraps( baseTable, indexArray ) - local baseValue = ModUtil.SafeGet( skipenv( baseTable ), indexArray ) - local wrapCallbacks = nil - wrapCallbacks = ModUtil.SafeGet( ModUtil.Internal.WrapCallbacks[ baseTable ], indexArray ) - if wrapCallbacks then - if wrapCallbacks[ 1 ] then - baseValue = wrapCallbacks[ 1 ].Func - end + info.data.penv = penv + info.data.env = env + info.data.func = func + end, + function ( info ) + threadEnvironments[ info.thread ] = info.env + local ret = table.pack( info.data.func( table.unpack( info.args, 2, info.args.n ) ) ) + threadEnvironments[ info.thread ] = info.penv + return table.unpack( ret ) end +) - return baseValue -end +-- Special traversal nodes -local function setBaseValueForWraps( baseTable, indexArray, value ) - local baseValue = ModUtil.SafeGet( skipenv( baseTable ), indexArray ) +ModUtil.Nodes = ModUtil.Entangled.Map.Unique( ) - if type( baseValue ) ~= "function" or type( value ) ~= "function" then return false end - - local wrapCallbacks = nil - wrapCallbacks = ModUtil.SafeGet( ModUtil.Internal.WrapCallbacks[ baseTable ], indexArray ) - if wrapCallbacks then if wrapCallbacks[ 1 ] then - baseValue = wrapCallbacks[ 1 ].Func - wrapCallbacks[ 1 ].Func = value - ModUtil.RewrapFunction( baseTable, indexArray ) - return true - end end - - return false -end - ---[[ - Override a value in baseTable. - - Generally, you should use ModUtil.BaseOverride instead for a more modder-friendly - interface. - - If the value is a function, overrides only the base function, - preserving all the wraps added with ModUtil.WrapFunction. - - The previous value is stored so that it can be restored later if desired. - For example, ModUtil.Override( _G, [ "UIFunctions", "OnButton1" ], overrideFunc, MyMod ) - will result in a data structure like: - - ModUtil.Internal.Overrides[ _G ].UIFunctions.OnButton1 = { - { id = 1, mod = MyMod, value = overrideFunc, base = } - } - - and subsequent overides wil be added as subsequent entries in the same table. - - baseTable - the table in which to override, usually _G (globals) - indexArray - the list of indices - value - the new value - mod - (optional) the mod that performed the override, for debugging purposes -]] -function ModUtil.Override( baseTable, indexArray, value, mod ) - if not baseTable then return end - - local baseValue = getBaseValueForWraps( baseTable, indexArray ) - - ModUtil.NewTable( ModUtil.Internal.Overrides, baseTable ) - local tempTable = ModUtil.SafeGet( ModUtil.Internal.Overrides[ baseTable ], indexArray ) - if tempTable == nil then - tempTable = { } - ModUtil.SafeSet( ModUtil.Internal.Overrides[ baseTable ], indexArray, tempTable ) - end - table.insert( tempTable, { Id = #tempTable + 1, Mod = mod, Value = value, Base = baseValue } ) - - if not setBaseValueForWraps( baseTable, indexArray, value ) then - ModUtil.SafeSet( skipenv( baseTable ), indexArray, value ) - end -end - ---[[ - Undo the most recent override performed with ModUtil.Override, restoring - the previous value. - - Generally, you should use ModUtil.BaseRestore instead for a more modder-friendly - interface. - - If the previous value is a function, the current stack of wraps for that - IndexArray will be reapplied to it. - - baseTable = the table in which to undo the override, usually _G (globals) - indexArray - the list of indices -]] -function ModUtil.Restore( baseTable, indexArray ) - if not baseTable then return end - local tempTable = ModUtil.SafeGet( ModUtil.Internal.Overrides[ baseTable ], indexArray ) - if not tempTable then return end - local baseData = table.remove( tempTable ) -- remove the last entry - if not baseData then return end - - if not setBaseValueForWraps( baseTable, indexArray, baseData.Base ) then - ModUtil.SafeSet( skipenv( baseTable ), indexArray, baseData.Base ) +function ModUtil.Nodes.New( parent, key ) + local nodeType = ModUtil.Nodes.Inverse[ key ] + if nodeType then + return ModUtil.Nodes.Data[ nodeType ].New( parent ) end - return baseData -end - ---[[ - Override the global value at the given basePath. - - If the Value is a function, preserves the wraps - applied with ModUtil.WrapBaseFunction et. al. - - basePath - the path to override, as a string - value - the new value to store at the path - mod - (optional) the mod performing the override, - for debug purposes -]] -function ModUtil.BaseOverride( basePath, value, mod ) - ModUtil.Override( _G, ModUtil.PathToIndexArray( basePath ), value, mod ) -end - ---[[ - Undo the most recent override performed with ModUtil.Override, - or ModUtil.BaseOverride, restoring the previous value. - - Use this carefully - if you are not the most recent mod to - override the given path, the results may be unexpected. - - basePath - the path to restore, as a string -]] -function ModUtil.BaseRestore( basePath ) - ModUtil.Restore( _G, ModUtil.PathToIndexArray( basePath ) ) -end - --- Wrap/Override interaction - -function ModUtil.GetOriginalValue( baseTable, indexArray ) - local baseValue = ModUtil.SafeGet( ModUtil.Internal.Overrides[ baseTable ], indexArray ) - if baseValue then - baseValue = baseValue[ #baseValue ].Base - else - baseValue = ModUtil.SafeGet( ModUtil.Internal.WrapCallbacks[ baseTable ], indexArray ) - if baseValue then - baseValue = baseValue[ 1 ].Func - else - baseValue = ModUtil.SafeGet( baseTable, indexArray ) - end + local tbl = parent[ key ] + if type( tbl ) ~= "table" then + tbl = { } + parent[ key ] = tbl end - return baseValue -end - -function ModUtil.GetOriginalBaseValue( basePath ) - return ModUtil.GetOriginalValue( _G, ModUtil.PathToIndexArray( basePath ) ) + return tbl end --- Automatically updating data structures - -ModUtil.Metatables.EntangledInvertibleTable = { - __index = function( self, key ) - return rawget( self, "Table" )[ key ] - end, - __newindex = function( self, key, value ) - local Table, Index = rawget( self, "Table" ), rawget( self, "Index" ) - if value ~= nil then - local k = Index[ value ] - if k ~= key then - if k ~= nil then - Table[ k ] = nil - end - Index[ value ] = key - end - end - if key ~= nil then - local v = Table[ key ] - if v ~= value then - if v ~= nil then - Index[ v ] = nil - end - Table[ key ] = value - end +ModUtil.Nodes.Data.Metatable = { + New = function( obj ) + local meta = getmetatable( obj ) + if meta == nil then + meta = { } + setmetatable( obj, meta ) end + return meta end, - __len = function( self ) - return #rawget( self, "Table" ) - end, - __next = function( self, key ) - return next( rawget( self, "Table" ), key ) - end, - __inext = function( self, idx ) - return inext( rawget( self, "Table" ), idx ) - end, - __pairs = function( self ) - return qrawpairs( self ) + Get = function( obj ) + return getmetatable( obj ) end, - __ipairs = function( self ) - return qrawipairs( self ) + Set = function( obj, value ) + setmetatable( obj, value ) + return true end } -ModUtil.Metatables.EntangledInvertibleIndex = { - __index = function( self, value ) - return rawget( self, "Index" )[ value ] - end, - __newindex = function( self, value, key ) - local table, index = rawget( self, "Table" ), rawget( self, "Index" ) - if value ~= nil then - local k = index[ value ] - if k ~= key then - if k ~= nil then - table[ k ] = nil +ModUtil.Nodes.Data.Call = { + New = function( obj ) + local call + while type( obj ) == "table" do + local meta = getmetatable( obj ) + if meta then + call = meta.__call + if call then + obj = call end - index[ value ] = key end end - if key ~= nil then - local v = table[ key ] - if v ~= value then - if v ~= nil then - index[ v ] = nil + return call or error( "node new rejected, new call nodes are not meaningfully mutable.", 2 ) + end, + Get = function( obj ) + while type( obj ) == "table" do + local meta = getmetatable( obj ) + if meta then + if meta.__call then + obj = meta.__call end - table[ key ] = value end end + return obj end, - __len = function( self ) - return #rawget( self, "Index" ) - end, - __next = function( self, value ) - return next( rawget( self, "Index" ), value ) - end, - __inext = function( self, idx ) - return inext( rawget( self, "Index" ), idx ) + Set = function( obj, value ) + local meta + while type( obj ) == "table" do + meta = getmetatable( obj ) + if meta then + if meta.__call then + obj = meta.__call + end + end + end + if not meta then return false end + meta.__call = value + return true + end +} + +ModUtil.Nodes.Data.UpValues = { + New = function( obj ) + return ModUtil.UpValues( obj ) end, - __pairs = function( self ) - return qrawpairs( self ) + Get = function( obj ) + return ModUtil.UpValues( obj ) end, - __ipairs = function( self ) - return qrawipairs( self ) + Set = function( ) + error( "node set rejected, upvalues node cannot be set.", 2 ) end } -function ModUtil.New.EntangledInvertiblePair( ) - local table, index = { }, { } - table, index = { Table = table, Index = index }, { Table = table, Index = index } - setmetatable( table, ModUtil.Metatables.EntangledInvertibleTable ) - setmetatable( index, ModUtil.Metatables.EntangledInvertibleIndex ) - return { Table = table, Index = index } -end +-- Identifier System -function ModUtil.New.EntangledInvertiblePairFromTable( tableArg ) - local pair = ModUtil.New.EntangledInvertiblePair( ) - for key, value in pairs( tableArg ) do - pair.Table[ key ] = value - end - return pair -end +ModUtil.Identifiers = ModUtil.Entangled.Map.Unique( ) +setmetatable( getObjectData( ModUtil.Identifiers.Data, "Inverse" ), { __mode = "k" } ) +setmetatable( getObjectData( ModUtil.Identifiers.Inverse, "Data" ), { __mode = "v" } ) -function ModUtil.New.EntangledInvertiblePairFromIndex( index ) - local pair = ModUtil.New.EntangledInvertiblePair( ) - for value, key in pairs( index ) do - pair.Index[ value ] = key - end - return pair -end +ModUtil.Identifiers.Inverse._G = _G +ModUtil.Identifiers.Inverse.ModUtil = ModUtil -ModUtil.Metatables.EntangledMap = { - __index = function( self, key ) - return rawget( self, "Map" )[ key ] - end, - __newindex = function( self, key, value ) - local map = rawget( self, "Map" ) - local prevValue = map[ key ] - map[ key ] = value - local preImage = rawget( self, "PreImage" ) - local prevKeys - if prevValue ~= nil then - prevKeys = preImage[ prevValue ] - end - local keys = preImage[ value ] - if not keys then - keys = { } - preImage[ value ] = keys - end - if prevKeys then - prevKeys[ key ] = nil - end - keys[ key ] = true - end, - __len = function( self ) - return #rawget( self, "Map" ) - end, - __next = function( self, key ) - return next( rawget( self, "Map" ), key ) - end, - __inext = function( self, idx ) - return inext( rawget( self, "Map" ), idx ) - end, - __pairs = function( self ) - return qrawpairs( self ) - end, - __ipairs = function( self ) - return qrawipairs( self ) - end -} +ModUtil.Mods = ModUtil.Entangled.Map.Unique( ) +setmetatable( getObjectData( ModUtil.Mods.Data, "Inverse" ), { __mode = "k" } ) +setmetatable( getObjectData( ModUtil.Mods.Inverse, "Data" ), { __mode = "v" } ) +ModUtil.Mods.Data.ModUtil = ModUtil -ModUtil.Metatables.EntangledPreImage = { - __index = function( self, value ) - return rawget( self, "PreImage" )[ value ] - end, - __newindex = function( self, value, keys ) - rawget( self, "PreImage" )[ value ] = keys - local map = rawget( self, "Map" ) - for key in pairs( map ) do - map[ key ] = nil - end - for key in ipairs( keys ) do - map[ key ] = value - end - end, - __len = function( self ) - return #rawget( self, "PreImage" ) - end, - __next = function( self, key ) - return next( rawget( self, "PreImage" ), key ) - end, - __inext = function( self, idx ) - return inext( rawget( self, "PreImage" ), idx ) - end, - __pairs = function( self ) - return qrawpairs( self ) - end, - __ipairs = function( self ) - return qrawipairs( self ) - end -} +-- Function Wrapping, Overriding, Referral -function ModUtil.New.EntangledPair( ) - local map, preImage = { }, { } - map, preImage = { Map = map, PreImage = preImage }, { Map = map, PreImage = preImage } - setmetatable( map, ModUtil.Metatables.EntangledMap ) - setmetatable( preImage, ModUtil.Metatables.EntangledPreImage ) - return { Map = map, PreImage = preImage } -end +local wrapCallbacks = { } +setmetatable( wrapCallbacks, { __mode = "k" } ) +local overrides = { } +setmetatable( overrides, { __mode = "k" } ) -function ModUtil.New.EntangledPairFromTable( tableArg ) - local pair = ModUtil.New.EntangledPair( ) - for key, value in pairs( tableArg ) do - pair.Map[ key ] = value - end - return pair +function ModUtil.Wrap( base, wrap, mod ) + local obj = { Base = base, Wrap = wrap, Mod = mod } + local func = function( ... ) return wrap( base, ... ) end + wrapCallbacks[ func ] = obj + return func end -function ModUtil.New.EntangledPairFromPreImage( preImage ) - local pair = ModUtil.New.EntangledPair( ) - for value, keys in pairs( preImage ) do - pair.PreImage[ value ] = keys - end - return pair +function ModUtil.Unwrap( obj ) + local callback = wrapCallbacks[ obj ] + return callback and callback.Base or obj end -ModUtil.Metatables.EntangledQueueData = { - __index = function( self, key ) - return rawget( self, "Data" )[ key ] - end, - __newindex = function( self, key, value ) - local data = rawget( self, "Data" ) - local prevValue = data[ key ] - data[ key ] = value - local order = rawget( self, "Order" ) - local prevOrder = nil - local prevOrderPair - if prevValue ~= nil then - prevOrderPair = order[ prevValue ] - if not prevOrderPair then - prevOrderPair = ModUtil.New.EntangledInvertiblePair( ) - order[ prevValue ] = prevOrderPair - end - prevOrder = prevOrderPair.Index[ key ] - end - local orderPair = order[ value ] - if not orderPair then - orderPair = ModUtil.New.EntangledInvertiblePair( ) - order[ value ] = orderPair - end - if prevOrder then - table.remove( prevOrderPair.Table, prevOrder ) - end - table.insert( orderPair.Table, key ) - end, - __len = function( self ) - return #rawget( self, "Data" ) - end, - __next = function( self, key ) - return next( rawget( self, "Data" ), key ) - end, - __inext = function( self, idx ) - return inext( rawget( self, "Data" ), idx ) - end, - __pairs = function( self ) - return qrawpairs( self ) - end, - __ipairs = function( self ) - return qrawipairs( self ) - end -} +function ModUtil.Rewrap( obj ) + local node = wrapCallbacks[ obj ] + if not node then return ModUtil.Overriden( obj ) end + return ModUtil.Wrap( ModUtil.Rewrap( node.Base ), node.Wrap, node.Mod ) +end -ModUtil.Metatables.EntangledQueueOrder = { - __index = function( self, value ) - return rawget( self, "Order" )[ value ] - end, - __newindex = function( self, value, pair ) - rawget( self, "Order" )[ value ] = pair - local data = rawget( self, "Data" ) - for _, key in pairs( data ) do - data[ key ] = nil - end - for _, key in ipairs( pair.Table ) do - data[ key ] = value - end - end, - __len = function( self ) - return #rawget( self, "Order" ) - end, - __next = function( self, key ) - return next( rawget( self, "Order" ), key ) - end, - __inext = function( self, idx ) - return inext( rawget( self, "Order" ), idx ) - end, - __pairs = function( self ) - return qrawpairs( self ) - end, - __ipairs = function( self ) - return qrawipairs( self ) - end -} +function ModUtil.Override( base, value, mod ) + local obj = { Base = ModUtil.Original( base ), Mod = mod } + overrides[ value ] = obj + return ModUtil.Rewrap( value ) +end -function ModUtil.New.EntangledQueuePair( ) - local data, order = { }, { } - data, order = { Data = data, Order = order }, { Data = data, Order = order } - setmetatable( data, ModUtil.Metatables.EntangledQueueData ) - setmetatable( order, ModUtil.Metatables.EntangledQueueOrder ) - return { Data = data, Order = order } +function ModUtil.Overriden( obj ) + local node = wrapCallbacks[ obj ] + if not node then return obj end + return ModUtil.Original( node.Base ) end -function ModUtil.New.EntangledQueuePairFromData( data ) - local pair = ModUtil.New.EntangledQueuePair( ) - for key, value in pairs( data ) do - pair.Data[ key ] = value - end - return pair +function ModUtil.Original( obj ) + local node = wrapCallbacks[ obj ] or overrides[ obj ] + if not node then return obj end + return ModUtil.Original( node.Base ) end -function ModUtil.New.EntangledQueuePairFromOrder( order ) - local pair = ModUtil.New.EntangledQueuePair( ) - for value, keys in pairs( order ) do - pair.Order[ value ] = keys +function ModUtil.ReferFunction( obtainer, ... ) + local args = table.pack( ... ) + return function( ... ) + return obtainer( table.unpack( args ) )( ... ) end - return pair end --- Context Managers (EXPERIMENTAL) (WIP) (BROKEN) (INCOMPLETE) - -ModUtil.Context = { } - -ModUtil.Metatables.Environment = { +ModUtil.Metatables.ReferTable = { __index = function( self, key ) - if key == "_G" then - return rawget( self, "global" ) - end - local value = rawget( self, "data" )[ key ] - if value ~= nil then - return value - end - return ( rawget( self, "fallback" ) or { } )[ key ] + return getObjectData( self, "obtain" )( )[ key ] end, __newindex = function( self, key, value ) - rawget( self, "data" )[ key ] = value - if key == "_G" then - rawset( self, "global", value ) - end + getObjectData( self, "obtain" )( )[ key ] = value + end, + __call = function( self, ... ) + return getObjectData( self, "obtain" )( )( ... ) end, __len = function( self ) - return #rawget( self, "data" ) + return #getObjectData( self, "obtain" )( ) end, __next = function( self, key ) - local out, first = { key }, true - while out[ 2 ] == nil and ( out[ 1 ] ~= nil or first ) do - first = false - out = { next( rawget( self, "data" ), out[ 1 ] ) } - if out[ 1 ] == "_G" then - out = { "_G", rawget( self, "global" ) } - end - end - return table.unpack( out ) + return next( getObjectData( self, "obtain" )( ), key ) end, __inext = function( self, idx ) - local out, first = { idx }, true - while out[ 2 ] == nil and ( out[ 1 ] ~= nil or first ) do - first = false - out = { inext( rawget( self, "data" ), out[ 1 ] ) } - if out[ 1 ] == "_G" then - out = { "_G", rawget( self, "global" ) } - end - end - return table.unpack( out ) + return inext( getObjectData( self, "obtain" )( ), idx ) end, __pairs = function( self ) - return qrawpairs( self ) + return pairs( getObjectData( self, "obtain" )( ) ) end, __ipairs = function( self ) - return qrawipairs( self ) + return ipairs( getObjectData( self, "obtain" )( ) ) end } -ModUtil.Metatables.Context = { - __call = function( self, targetPath_or_targetIndexArray, callContext, ... ) - local oldContextInfo = ModUtil.StackedLocals( 2 )._ContextInfo - local contextInfo = { - call = callContext, - parent = oldContextInfo - } - - contextInfo.targetIndexArray = ModUtil.PathToIndexArray( targetPath_or_targetIndexArray ) or { } - if oldContextInfo ~= nil then - contextInfo.indexArray = ShallowCopyTable( oldContextInfo.indexArray ) - contextInfo.baseTable = oldContextInfo.baseTable - else - contextInfo.indexArray = { } - contextInfo.baseTable = _G - end - - local callContextProcessor = rawget( self, "callContextProcessor" ) - contextInfo.callContextProcessor = callContextProcessor - - local contextData, contextArgs = callContextProcessor( contextInfo, ... ) - contextData = contextData or _G - contextArgs = contextArgs or { } - - local _ContextInfo = contextInfo - _ContextInfo.data = contextData - _ContextInfo.args = contextArgs - - local callWrap = function( ... ) callContext( ... ) end - surrogateEnvironments[ callWrap ] = contextData - callWrap( table.unpack( contextArgs ) ) +function ModUtil.ReferTable( obtainer, ... ) + local args = table.pack( ... ) + local obtain = function( ) + return obtainer( table.unpack( args ) ) end -} - -function ModUtil.New.Context( callContextProcessor ) - local context = { callContextProcessor = callContextProcessor } - setmetatable( context, ModUtil.Metatables.Context ) - return context + return ModUtil.ObjectDataProxy( { obtain = obtain }, ModUtil.Metatables.ReferTable ) end -ModUtil.Context.Call = ModUtil.New.Context( function( info ) - info.indexArray = ModUtil.JoinIndexArrays( info.indexArray, info.targetIndexArray ) - local obj = ModUtil.SafeGet( info.baseTable, info.indexArray ) - while type( obj ) == "table" do - local meta = getmetatable( obj ) - if meta then - if meta.__call then - table.insert( info.indexArray, ModUtil.Nodes.Table.Metatable ) - table.insert( info.indexArray, "__call" ) - obj = meta.__call - end - end - end - local env = { data = ModUtil.NewTable( obj, ModUtil.Nodes.Table.Environment ), fallback = _G } - env.global = env - setmetatable( env, ModUtil.Metatables.Environment ) - return env -end ) - -ModUtil.Context.Meta = ModUtil.New.Context( function( info ) - info.indexArray = ModUtil.JoinIndexArrays( info.indexArray, info.targetIndexArray ) - local parent = ModUtil.SafeGet( info.baseTable, info.indexArray ) - if parent == nil then - parent = { } - ModUtil.SafeSet( info.baseTable, info.indexArray, parent ) - end - local env = { data = ModUtil.NewTable( parent, ModUtil.Nodes.Table.Metatable ), fallback = _G } - env.global = env - setmetatable( env, ModUtil.Metatables.Environment ) - return env -end ) - -ModUtil.Context.Data = ModUtil.New.Context( function( info ) - info.indexArray = ModUtil.JoinIndexArrays( info.indexArray, info.targetIndexArray ) - local tempArray = ShallowCopyTable( info.indexArray ) - local key = table.remove( tempArray ) - local parent = ModUtil.SafeGet( info.baseTable, tempArray ) - if parent == nil then - parent = { } - ModUtil.SafeSet( info.baseTable, tempArray, parent ) - end - local env = { data = ModUtil.NewTable( parent, key ), fallback = _G } - env.global = env - setmetatable( env, ModUtil.Metatables.Environment ) - return env -end ) - --- Special traversal nodes (EXPERIMENTAL) (WIP) (INCOMPLETE) - -ModUtil.Nodes = ModUtil.New.EntangledInvertiblePair( ) - -ModUtil.Nodes.Table.Metatable = { - New = function( obj ) - local meta = getmetatable( obj ) - if meta == nil then - meta = { } - setmetatable( obj, meta ) - end - return meta - end, - Get = function( obj ) - return getmetatable( obj ) - end, - Set = function( obj, value ) - setmetatable( obj, value ) - return true - end -} - -ModUtil.Nodes.Table.Environment = { - New = function( obj ) - local env = surrogateEnvironments[ obj ] - if env == nil or getmetatable( env ) ~= ModUtil.Metatables.Environment then - env = { } - env.data = env.data or { } - env.fallback = _G - env.global = env - setmetatable( env, ModUtil.Metatables.Environment ) - surrogateEnvironments[ obj ] = env - end - return env - end, - Get = function( obj ) - return surrogateEnvironments[ obj ] - end, - Set = function( obj, value ) - surrogateEnvironments[ obj ] = value - return true - end -} - --- Identifier system (EXPERIMENTAL) - -ModUtil.Identifiers = ModUtil.New.EntangledInvertiblePair( ) -ModUtil.Identifiers.Index._G = _G -ModUtil.Identifiers.Index.ModUtil = ModUtil - -ModUtil.Mods = ModUtil.New.EntangledInvertiblePair( ) -ModUtil.Mods.Table.ModUtil = ModUtil +--- --- Mods tracking (EXPERIMENTAL) (WIP) (UNTESTED) (INCOMPLETE) - ---[[ - Users should only ever opt-in to running this function -]] -function ModUtil.EnableModHistory( ) - if not ModHistory then - ModHistory = { } - if PersistVariable then PersistVariable{ Name = "ModHistory" } end - SaveIgnores[ "ModHistory" ] = nil - end +function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrapFunc, mod ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrapFunc, mod ) end -function ModUtil.DisableModHistory( ) - if not ModHistory then - ModHistory = { } - if PersistVariable then PersistVariable{ Name = "ModHistory" } end - SaveIgnores[ "ModHistory" ] = nil - end +function ModUtil.IndexArray.Unwrap( baseTable, indexArray ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Unwrap ) end -function ModUtil.UpdateModHistoryEntry( options ) - if options.Override then - ModUtil.EnableModHistory( ) - end - if ModHistory then - local mod = options.Mod - local path = options.Path - if mod == nil then - mod = ModUtil.Mods.Table[ path ] - end - if path == nil then - path = ModUtil.Mods.Index[ mod ] - end - local entry = ModHistory[ path ] - if entry == nil then - entry = { } - ModHistory[ path ] = entry - end - if options.Version then - entry.Version = options.Version - end - if options.FirstTime or options.All then - if not entry.FirstTime then - entry.FirstTime = os.time( ) - end - end - if options.LastTime or options.All then - entry.LastTime = os.time( ) - end - - if options.Count or options.All then - local count = entry.Count - if not count then - count = 0 - end - entry.Count = count + 1 - end - end +function ModUtil.IndexArray.Rewrap( baseTable, indexArray ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Rewrap ) end -function ModUtil.PopulateModHistory( options ) - if not options then - options = { } - end - for path, mod in pairs( ModUtil.Mods.Table ) do - options.Path, options.Mod = path, mod - ModUtil.UpdateModHistoryEntry( options ) - end +function ModUtil.IndexArray.Override( baseTable, indexArray, value, mod ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Override, value, mod ) end --- Wrap/Overrides within functions (EXPERIMENTAL) (LIKELY DEPRECATED) - -ModUtil.Internal.PerFunctionEnv = { } - ---[[ - Create a new table whose getters and setters will default to the given - baseTable, except in cases where values are setOverride into the overrideTable. - This allows pinpoint overriding of values in the override table, while allowing - all other accesses to continue to operate as if they were operating on baseTable. - The overrides are stored in the _Overrides subtable. For example: - _Overrides = { - CurrentRun = { - CurrentRoom = { - _IsModUtilOverride = true, - _Value = { - Name = "RoomSimple01", - ... - } - } - } - } - would be the result of overriding "CurrentRun.CurrentRoom" with a table represnting a room. - Any accesses that happen above the override point (ie. reads/writes to CurrentRun) are - reed to the base table. Any accesses that happen at or below the override point (ie. - reads / writes to CurrentRun.CurrentRoom or CurrentRun.CurrentRoom.Name) are intercepted - and apply to the overridden value instead. - baseTable - the table to access for entries not specifically overridden -]] -local function makeOverrideTable( baseTable, overrides ) - local overrideTable = { - _IsModUtilOverrideTable = true, - _Overrides = overrides or { }, - _BaseTable = baseTable - } - setmetatable( overrideTable, ModUtil.Metatables.OverrideTable ) - return overrideTable +function ModUtil.IndexArray.Overriden( baseTable, indexArray ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Overriden ) end -ModUtil.Metatables.OverrideTable = { - __index = function( self, name ) - local baseResult = self._BaseTable[ name ] - local overridesResult = self._Overrides[ name ] - if overridesResult == nil then - return baseResult - elseif overridesResult._IsModUtilOverride then - return overridesResult._Value - elseif type( baseResult ) == "table" then - return makeOverrideTable( baseResult, overridesResult ) - else - return makeOverrideTable( { }, overridesResult ) - end - end, - __newindex = function( self, name, value ) - local currentOverride = self._Overrides[ name ] - if currentOverride == nil then - self._BaseTable[ name ] = value - elseif currentOverride._IsModUtilOverride then - currentOverride._Value = value - else - self._BaseTable[ name ] = value - end - end -} - ---[[ - Override the entry at indexArray in table with value. - table - the table whose entry should be overridden - must come from a previous call to makeOverrideTable( ) - indexArray - the list of indexes - value - the value to override -]] -local function setOverride( table, indexArray, value ) - if type( table ) ~= "table" or not table._IsModUtilOverrideTable then return end - ModUtil.SafeSet( table._Overrides, indexArray, { _IsModUtilOverride = true, _Value = value } ) +function ModUtil.IndexArray.Original( baseTable, indexArray ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Original ) end ---[[ - Remove the override entry at indexArray in table. - No effect if the indexArray does not identify an override point. - table - the table whose override should be removed - indexArray - the list of indexes -]] -local function removeOverride( table, indexArray ) - if type( table ) ~= "table" or not table._IsModUtilOverrideTable then return end - local currentOverride = ModUtil.SafeGet( table._Overrides, indexArray ) - if currentOverride ~= nil and currentOverride._IsModUtilOverride then - ModUtil.SafeSet( table._Overrides, indexArray, nil ) - end +function ModUtil.IndexArray.ReferFunction( baseTable, indexArray ) + return ModUtil.ReferFunction( ModUtil.IndexArray.Get, baseTable, indexArray ) end ---[[ - Check whether there is an override for indexArray in table. - Only returns true for exact matches. For example, if you override CurrentRun in table T, - hasOverride( T, { "CurrentRun", "CurrentRoom" } ) will return false. - table - the table to check for an override - indexArray - the list of indexes -]] -local function hasOverride( table, indexArray ) - if type( table ) ~= "table" or not table._IsModUtilOverrideTable then return false end - local value = ModUtil.SafeGet( table._Overrides, indexArray ) - return value ~= nil and value._IsModUtilOverride +function ModUtil.IndexArray.ReferTable( baseTable, indexArray ) + return ModUtil.ReferTable( ModUtil.IndexArray.Get, baseTable, indexArray ) end ---[[ - Gets the function's local (partially-overriden) environment, or - create a new one and attach it to the function if not yet present. - baseTable - the base table, on which to base the function's environment - indexArray - the list of indexes -]] -local function getFunctionEnv( baseTable, indexArray ) - local func = getBaseValueForWraps( baseTable, indexArray ) - if type( func ) ~= "function" then return nil end +--- - ModUtil.NewTable( ModUtil.Internal.PerFunctionEnv, baseTable ) - local env = ModUtil.SafeGet( ModUtil.Internal.PerFunctionEnv[ baseTable ], indexArray ) - if not env then - env = makeOverrideTable( baseTable ) - ModUtil.SafeSet( ModUtil.Internal.PerFunctionEnv[ baseTable ], indexArray, env ) - setfenv( func, env ) - end - return env +function ModUtil.Path.Wrap( path, wrapFunc, mod ) + ModUtil.Path.Map( path, ModUtil.Wrap, wrapFunc, mod ) end ---[[ - Overrides the value at envIndexArray within the function referred to by - indexArray in baseTable, by replacing it with value. - Accesses to the value at envIndexArray from within other functions are - unaffected. - Generally, you should use ModUtil.BaseOverrideWithinFunction for a more - modder-friendly interface. - For example, after you do - ModUtil.OverrideWithinFunction( _G, { "CreateRoom" }, { "CurrentRun.CurrentRoom" }, ) - 1. Any reads to CurrentRun.CurrentRoom from CreateRoom will return - 2. Any writes to CurrentRun.CurrentRoom from CreateRoom will replace , which will - with the new value, which will be returned for subsequent accesses to CurrentRun.CurrentRoom. - 3. Any writes to CurrentRun.CurrentRoom from CreateRoom will not be visible from other functions. - 4. If CreateRoom performs writes within (eg. CurrentRun.CurrentRoom.Name = "foo") - these will be visible to from any function that has access to it. If you want - full isolation, make sure you pass in an object that nobody else has a reference to, eg. by - creating one fresh or making a copy). - baseTable - the base table for function and environment lookups (usually _G) - indexArray - the list of indices identifying the function whose environment is to be overridden - envIndexArray - the list of indices identifying the value to be overridden in the function's environment - value - the value with which to override -]] -function ModUtil.OverrideWithinFunction( baseTable, indexArray, envIndexArray, value ) - if not baseTable then return end - local env = getFunctionEnv( baseTable, indexArray ) - - if not env then return end - if hasOverride( env, envIndexArray ) then - -- we might have wraps to reapply - local overrideEnvIndexArray = DeepCopyTable( envIndexArray ) - table.insert( overrideEnvIndexArray, "_Value" ) - if not setBaseValueForWraps( env._Overrides, overrideEnvIndexArray, value ) then - setOverride( env, envIndexArray, value ) - end - else - setOverride( env, envIndexArray, value ) - end +function ModUtil.Path.Unwrap( path ) + ModUtil.Path.Map( path, ModUtil.Unwrap ) end ---[[ - Remove the override at envIndexArray for the function at indexArray in baseTable, - so that reads and writes to envIndexArray have their usual effects on the base environment. - baseTable - the base table for function and environment lookups (usually _G) - indexArray - the list of indices identifying the function whose environment is to be overridden - envIndexArray - the list of indices identifying the value to be overridden in the function's environment -]] -function ModUtil.RestoreWithinFunction( baseTable, indexArray, envIndexArray ) - if not baseTable then return end - - local env = getFunctionEnv( baseTable, indexArray ) - if not env then return end +function ModUtil.Path.Rewrap( path ) + ModUtil.Path.Map( path, ModUtil.Rewrap ) +end - removeOverride( env, envIndexArray ) +function ModUtil.Path.Override( path, value, mod ) + ModUtil.Path.Map( path, ModUtil.Override, value, mod ) end +function ModUtil.Path.Overriden( path ) + ModUtil.Path.Map( path, ModUtil.Overriden ) +end ---[[ - Wrap a function, so that you can insert code that runs before/after that function whenever - it's called from within a particular other function, and modify the return value if needed. - Generally, you should use ModUtil.WrapBaseWithinFunction for a more modder-friendly interface. - baseTable - the base table for function and environment lookups (usually _G) - indexArray - the list of indices identifying the function within with the wrap will apply - envIndexArray - the list of indices identifying the function whose calls will be wrapped - wrapFunc - the wrapping function - mod - (optional) the mod performing the wrapping, for debug purposes -]] -function ModUtil.WrapWithinFunction( baseTable, indexArray, envIndexArray, wrapFunc, mod ) - if type( wrapFunc ) ~= "function" then return end - if not baseTable then return end - local env = getFunctionEnv( baseTable, indexArray ) - if not env then return end - - if not hasOverride( env, envIndexArray ) then - -- Resolve the entry in baseTable at call time (not now), - -- in case further wraps or overrides are applied to it. - setOverride( - env, - envIndexArray, - function( ... ) - local resolvedFunc = ModUtil.SafeGet( ModUtil.Experimental.SkipEnvironment( baseTable ), envIndexArray ) - return resolvedFunc( ... ) - end - ) - end +function ModUtil.Path.Original( path ) + ModUtil.Path.Map( path, ModUtil.Original ) +end - ModUtil.WrapFunction( env, envIndexArray, wrapFunc, mod ) +function ModUtil.Path.ReferFunction( path ) + return ModUtil.ReferFunction( ModUtil.Path.Get, path ) end ---[[ - Override the global value at the given path, when accessed from - within the global function at funcPath. - If the Value is a function, preserves the wraps - applied with ModUtil.WrapBaseWithinFunction et. al. - basePath - the path to override, as a string - envPath - the path to override, as a string - value - the new value to store at the path -]] -function ModUtil.BaseOverrideWithinFunction( funcPath, basePath, value ) - local indexArray = ModUtil.PathArray( funcPath ) - local envIndexArray = ModUtil.PathArray( basePath ) - ModUtil.OverrideWithinFunction( _G, indexArray, envIndexArray, value ) +function ModUtil.Path.ReferTable( path ) + return ModUtil.ReferTable( ModUtil.Path.Get, path ) end ---[[ - Wraps the function with the path given by baseFuncPath, when it is called from - the function given by funcPath. - This lets you insert code within a function, without affecting other functions - that might make similar calls. - For example, to insert code to display a "cancel" at the point in "CreateBoonLootButtons" - where it calls IsMetaUpgradeSelected( "RerollPanelMetaUpgrade" ), do: - ModUtil.WrapBaseWithinFunction( "CreateBoonLootButtons", "IsMetaUpgradeSelected", function( baseFunc, name ) - if name == "RerollPanelMetaUpgrade" and CalcNumLootChoices( ) == 0 then - < code to display the cancel button > - return false - else - return baseFunc( name ) - end - end, YourMod ) - This provides better compatibility between mods that just wrapping IsMetaUpgradeSelected, because - you new code only executes when within CreateBoonLootButtons, so there are less chances for collisions - and side effects. - It also provides better compatibility than using BaseOverride on "CreateBoonLootButtons", since only one - override for a function can be active at a time, but multiple wraps can be active. - funcPath - the (global) path to the function within which the wrap will apply, as a string - for most SGG-provided functions, this is just the function's name - eg. "CreateRoomReward" or "SetTraitsOnLoot" - baseFuncPath - the (global) path to the function to wrap, as a string - for most SGG-provided functions, this is just the function's name - eg. "CreateRoomReward" or "SetTraitsOnLoot" - wrapFunc - the function to wrap around the base function - this function receives the base function as its first parameter. - all subsequent parameters should be the same as the base function - mod - (optional) the object for your mod, for debug purposes -]] -function ModUtil.WrapBaseWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) - local indexArray = ModUtil.PathArray( funcPath ) - local envIndexArray = ModUtil.PathArray( baseFuncPath ) - ModUtil.WrapWithinFunction( _G, indexArray, envIndexArray, wrapFunc, mod ) +-- Internal access + +do + local ups = ModUtil.UpValues( function( ) + return _G, + objectData, newObjectData, getObjectData, + wrapCallbacks, overrides, + threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment + end ) + setmetatable( ModUtil.Internal, { __index = ups, __newindex = ups } ) end --- Final Processing -ModUtil.ReplaceGlobalEnvironment( ) \ No newline at end of file +-- Final Actions + +replaceGlobalEnvironment( ) \ No newline at end of file diff --git a/modfile.txt b/modfile.txt index 087f24d..4a55702 100644 --- a/modfile.txt +++ b/modfile.txt @@ -1,5 +1,9 @@ :: Mod Utility Load Priority 0 -Top Import "ModUtil.lua" -Import "ModUtilHades.lua" \ No newline at end of file + To "Scripts/Main.lua" + Top Import "ModUtil.lua" + Import "ModUtil.Main.lua" + Import "ModUtil.Compat.lua" + To "Scripts/RoomManager.lua" + Import "ModUtil.Hades.lua" \ No newline at end of file From 2c5e8b08816c08e38a3d07aafa8039390deac420 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 15 Mar 2021 13:16:09 +1100 Subject: [PATCH 02/32] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1a82c7c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Andre Issa + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 38d4223de57fe94d9d3c3dddbff105a51932bf07 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 15 Mar 2021 13:16:16 +1100 Subject: [PATCH 03/32] Delete ModUtilHades.lua --- ModUtilHades.lua | 404 ----------------------------------------------- 1 file changed, 404 deletions(-) delete mode 100644 ModUtilHades.lua diff --git a/ModUtilHades.lua b/ModUtilHades.lua deleted file mode 100644 index 26b30a9..0000000 --- a/ModUtilHades.lua +++ /dev/null @@ -1,404 +0,0 @@ - -ModUtil.RegisterMod( "Hades", ModUtil ) - -ModUtil.MapSetTable( ModUtil.Hades, { - PrintStackHeight = 10, - PrintStackCapacity = 80 -} ) - -ModUtil.Anchors.PrintOverhead = {} - --- Screen Handling - -OnAnyLoad{ function() - if ModUtil.Hades.UnfreezeLoop then return end - ModUtil.Hades.UnfreezeLoop = true - thread( function() - while ModUtil.Hades.UnfreezeLoop do - wait(15) - if ModUtil.SafeGet(CurrentRun,{'Hero','FreezeInputKeys'}) then - if (not AreScreensActive()) and (not IsInputAllowed({})) then - UnfreezePlayerUnit() - DisableShopGamepadCursor() - end - end - end - end) -end} - --- Menu Handling - -function ModUtil.Hades.CloseMenu( screen, button ) - CloseScreen(GetAllIds(screen.Components), 0.1) - ModUtil.Anchors.Menu[screen.Name] = nil - screen.KeepOpen = false - OnScreenClosed({ Flag = screen.Name }) - if TableLength(ModUtil.Anchors.Menu) == 0 then - SetConfigOption({ Name = "FreeFormSelectWrapY", Value = false }) - SetConfigOption({ Name = "UseOcclusion", Value = true }) - UnfreezePlayerUnit() - DisableShopGamepadCursor() - end - if ModUtil.Anchors.CloseFuncs[screen.Name] then - ModUtil.Anchors.CloseFuncs[screen.Name]( screen, button ) - ModUtil.Anchors.CloseFuncs[screen.Name]=nil - end -end - -function ModUtil.Hades.OpenMenu( group, closeFunc, openFunc ) - if ModUtil.Anchors.Menu[group] then - ModUtil.Hades.CloseMenu(ModUtil.Anchors.Menu[group]) - end - if closeFunc then ModUtil.Anchors.CloseFuncs[group]=closeFunc end - - local screen = { Name = group, Components = {} } - local components = screen.Components - ModUtil.Anchors.Menu[group] = screen - - OnScreenOpened({ Flag = screen.Name, PersistCombatUI = true }) - - components.Background = CreateScreenComponent({ Name = "BlankObstacle", Group = group }) - - if openFunc then openFunc(screen) end - - return screen -end - -function ModUtil.Hades.DimMenu( screen ) - if not screen then return end - if not screen.Components.BackgroundDim then - screen.Components.BackgroundDim = CreateScreenComponent({ Name = "rectangle01", Group = screen.Name }) - SetScale({ Id = screen.Components.BackgroundDim.Id, Fraction = 4 }) - end - SetColor({ Id = screen.Components.BackgroundDim.Id, Color = {0.090, 0.090, 0.090, 0.8} }) -end - -function ModUtil.Hades.UndimMenu( screen ) - if not screen then return end - if not screen.Components.BackgroundDim then return end - SetColor({ Id = screen.Components.BackgroundDim.Id, Color = {0.090, 0.090, 0.090, 0} }) -end - -function ModUtil.Hades.PostOpenMenu( screen ) - if TableLength(ModUtil.Anchors.Menu) == 1 then - SetConfigOption({ Name = "FreeFormSelectWrapY", Value = true }) - SetConfigOption({ Name = "UseOcclusion", Value = false }) - FreezePlayerUnit() - EnableShopGamepadCursor() - end - thread(HandleWASDInput, screen) - HandleScreenInput(screen) - return screen -end - -function ModUtil.Hades.GetMenuScreen( group ) - return ModUtil.Anchors.Menu[group] -end - --- Debug Printing - -function ModUtil.Hades.PrintDisplay( text , delay, color ) - if type(text) ~= "string" then - text = tostring(text) - end - text = " "..text.." " - if color == nil then - color = Color.Yellow - end - if delay == nil then - delay = 5 - end - if ModUtil.Anchors.PrintDisplay then - Destroy({Ids = {ModUtil.Anchors.PrintDisplay.Id}}) - end - ModUtil.Anchors.PrintDisplay = CreateScreenComponent({Name = "BlankObstacle", Group = "PrintDisplay", X = ScreenCenterX, Y = 40 }) - CreateTextBox({ Id = ModUtil.Anchors.PrintDisplay.Id, Text = text, FontSize = 22, Color = color, Font = "UbuntuMonoBold"}) - - if delay > 0 then - thread(function() - wait(delay) - Destroy({Ids = {ModUtil.Anchors.PrintDisplay.Id}}) - ModUtil.Anchors.PrintDisplay = nil - end) - end -end - -function ModUtil.Hades.PrintOverhead(text, delay, color, dest) - if type(text) ~= "string" then - text = tostring(text) - end - text = " "..text.." " - if dest == nil then - dest = CurrentRun.Hero.ObjectId - end - if color == nil then - color = Color.Yellow - end - if delay == nil then - delay = 5 - end - Destroy({Ids = {ModUtil.Anchors.PrintOverhead[dest]}}) - local id = SpawnObstacle({ Name = "BlankObstacle", Group = "PrintOverhead", DestinationId = dest }) - ModUtil.Anchors.PrintOverhead[dest] = id - Attach({ Id = id, DestinationId = dest }) - CreateTextBox({ Id = id, Text = text, FontSize = 32, OffsetX = 0, OffsetY = -150, Color = color, Font = "AlegreyaSansSCBold", Justification = "Center" }) - if delay > 0 then - thread(function() - wait(delay) - if ModUtil.Anchors.PrintOverhead[dest] then - Destroy({Ids = {id}}) - ModUtil.Anchors.PrintOverhead[dest] = nil - end - end) - end -end - -local function ClosePrintStack() - if ModUtil.Anchors.PrintStack then - ModUtil.Anchors.PrintStack.CullEnabled = false - PlaySound({ Name = "/SFX/Menu Sounds/GeneralWhooshMENU" }) - ModUtil.Anchors.PrintStack.KeepOpen = false - - CloseScreen(GetAllIds(ModUtil.Anchors.PrintStack.Components),0) - ModUtil.Anchors.CloseFuncs["PrintStack"] = nil - ModUtil.Anchors.PrintStack = nil - end -end - -local function OrderPrintStack(screen,components) - - if screen.CullPrintStack then - local v = screen.TextStack[1] - if v.obj then - Destroy({Ids = {v.obj.Id}}) - components["TextStack_" .. v.tid] = nil - v.obj = nil - screen.TextStack[v.tid]=nil - end - thread( function() - local v = screen.TextStack[2] - if v then - wait(v.data.Delay) - if v.obj then - screen.CullPrintStack = true - end - end - end) - else - thread( function() - local v = screen.TextStack[1] - if v then - wait(v.data.Delay) - if v.obj then - screen.CullPrintStack = true - end - end - end) - end - screen.CullPrintStack = false - - for k,v in pairs(screen.TextStack) do - components["TextStack_" .. k] = nil - Destroy({Ids = {v.obj.Id}}) - end - - screen.TextStack = CollapseTable(screen.TextStack) - for i,v in pairs(screen.TextStack) do - v.tid = i - end - if #screen.TextStack == 0 then - return ClosePrintStack() - end - - local Ymul = screen.StackHeight+1 - local Ygap = 30 - local Yoff = 26*screen.StackHeight+22 - local n =#screen.TextStack - - if n then - for k=1,math.min(n,Ymul) do - v = screen.TextStack[k] - if v then - local data = v.data - screen.TextStack[k].obj = CreateScreenComponent({ Name = "rectangle01", Group = "PrintStack", X = -1000, Y = -1000}) - local textStack = screen.TextStack[k].obj - components["TextStack_" .. k] = textStack - SetScaleX({Id = textStack.Id, Fraction = 10/6}) - SetScaleY({Id = textStack.Id, Fraction = 0.1}) - SetColor({ Id = textStack.Id, Color = data.Bgcol }) - CreateTextBox({ Id = textStack.Id, Text = data.Text, FontSize = data.FontSize, OffsetX = 0, OffsetY = 0, Color = data.Color, Font = data.Font, Justification = "Center" }) - Attach({ Id = textStack.Id, DestinationId = components.Background.Id, OffsetX = 220, OffsetY = -Yoff }) - Yoff = Yoff - Ygap - end - end - end - -end - -function ModUtil.Hades.PrintStack( text, delay, color, bgcol, fontsize, font, sound ) - if color == nil then color = {1,1,1,1} end - if bgcol == nil then bgcol = {0.590, 0.555, 0.657,0.125} end - if fontsize == nil then fontsize = 13 end - if font == nil then font = "UbuntuMonoBold" end - if sound == nil then sound = "/Leftovers/SFX/AuraOff" end - if delay == nil then delay = 3 end - - if type(text) ~= "string" then - text = tostring(text) - end - text = " "..text.." " - - local first = false - if not ModUtil.Anchors.PrintStack then - first = true - ModUtil.Anchors.PrintStack = { Components = {} } - ModUtil.Anchors.CloseFuncs["PrintStack"] = ClosePrintStack - end - local screen = ModUtil.Anchors.PrintStack - local components = screen.Components - - if first then - - screen.KeepOpen = true - screen.TextStack = {} - screen.CullPrintStack = false - screen.MaxStacks = ModUtil.Hades.PrintStackCapacity - screen.StackHeight = ModUtil.Hades.PrintStackHeight - PlaySound({ Name = "/SFX/Menu Sounds/DialoguePanelOutMenu" }) - components.Background = CreateScreenComponent({ Name = "BlankObstacle", Group = "PrintStack", X = ScreenCenterX, Y = 2*ScreenCenterY}) - components.Backing = CreateScreenComponent({ Name = "TraitTray_Center", Group = "PrintStack"}) - Attach({ Id = components.Backing.Id, DestinationId = components.Background.Id, OffsetX = -180, OffsetY = 0 }) - SetColor({ Id = components.Backing.Id, Color = {0.590, 0.555, 0.657, 0.8} }) - SetScaleX({Id = components.Backing.Id, Fraction = 6.25}) - SetScaleY({Id = components.Backing.Id, Fraction = 6/55*(2+screen.StackHeight)}) - - thread( function() - while screen do - wait(0.5) - if screen.CullEnabled then - if screen.CullPrintStack then - OrderPrintStack(screen,components) - end - end - end - end) - - end - - if #screen.TextStack >= screen.MaxStacks then return end - - screen.CullEnabled = false - - local newText = {} - newText.obj = CreateScreenComponent({ Name = "rectangle01", Group = "PrintStack"}) - newText.data = {Delay = delay, Text = text, Color = color, Bgcol = bgcol, Font = font, FontSize = fontsize} - SetColor({ Id = newText.obj.Id, Color = {0,0,0,0}}) - table.insert(screen.TextStack, newText) - - PlaySound({ Name = sound }) - - OrderPrintStack(screen,components) - - screen.CullEnabled = true - -end - -function ModUtil.Hades.PrintStackChunks( text, linespan, ... ) - if not linespan then linespan = 90 end - for _,s in ipairs( ModUtil.ChunkText( text, linespan,ModUtil.Hades.PrintStackCapacity ) ) do - ModUtil.Hades.PrintStack( s, ... ) - end -end - --- Custom Menus - -function ModUtil.Hades.NewMenuYesNo( group, closeFunc, openFunc, yesFunc, noFunc, title, body, yesText, noText, icon, iconScale) - - if not group or group == "" then group = "MenuYesNo" end - if not yesFunc then yesFunc = function( ) end end - if not noFunc then noFunc = function( ) end end - if not icon then icon = "AmmoPack" end - if not iconScale then iconScale = 1 end - if not yesText then yesText = "Yes" end - if not noText then noText = "No" end - if not body then body = "Make a choice..." end - if not title then title = group end - - local screen = ModUtil.Hades.OpenMenu( group, closeFunc, openFunc ) - local components = screen.Components - - PlaySound({ Name = "/SFX/Menu Sounds/GodBoonInteract" }) - - components.LeftPart = CreateScreenComponent({ Name = "TraitTrayBackground", Group = group, X = 1030, Y = 424}) - components.MiddlePart = CreateScreenComponent({ Name = "TraitTray_Center", Group = group, X = 660, Y = 464 }) - components.RightPart = CreateScreenComponent({ Name = "TraitTray_Right", Group = group, X = 1270, Y = 438 }) - SetScaleY({Id = components.LeftPart.Id, Fraction = 0.8}) - SetScaleY({Id = components.MiddlePart.Id, Fraction = 0.8}) - SetScaleY({Id = components.RightPart.Id, Fraction = 0.8}) - SetScaleX({Id = components.MiddlePart.Id, Fraction = 5}) - - - CreateTextBox({ Id = components.Background.Id, Text = " "..title.." ", FontSize = 34, - OffsetX = 0, OffsetY = -225, Color = Color.White, Font = "SpectralSCLight", - ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 1}, Justification = "Center" }) - CreateTextBox({ Id = components.Background.Id, Text = " "..body.." ", FontSize = 19, - OffsetX = 0, OffsetY = -175, Width = 840, Color = Color.SubTitle, Font = "CrimsonTextItalic", - ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 1}, Justification = "Center" }) - - components.Icon = CreateScreenComponent({ Name = "BlankObstacle", Group = group }) - Attach({ Id = components.Icon.Id, DestinationId = components.Background.Id, OffsetX = 0, OffsetY = -50}) - SetAnimation({ Name = icon, DestinationId = components.Icon.Id, Scale = iconScale }) - - ModUtil.NewTable(ModUtil.Anchors.Menu[group], "Funcs") - ModUtil.Anchors.Menu[group].Funcs={ - Yes = function(screen, button) - if not yesFunc(screen,button) then - ModUtil.Hades.CloseMenuYesNo(screen,button) - end - end, - No = function(screen, button) - if not noFunc(screen,button) then - ModUtil.Hades.CloseMenuYesNo(screen,button) - end - end, - } - - components.CloseButton = CreateScreenComponent({ Name = "ButtonClose", Scale = 0.7, Group = group }) - Attach({ Id = components.CloseButton.Id, DestinationId = components.Background.Id, OffsetX = 0, OffsetY = ScreenCenterY - 315 }) - components.CloseButton.OnPressedFunctionName = "ModUtil.Hades.CloseMenuYesNo" - components.CloseButton.ControlHotkey = "Cancel" - - components.YesButton = CreateScreenComponent({ Name = "BoonSlot1", Group = group, Scale = 0.35, }) - components.YesButton.OnPressedFunctionName = "ModUtil.Anchors.Menu."..group..".Funcs.Yes" - SetScaleX({Id = components.YesButton.Id, Fraction = 0.75}) - SetScaleY({Id = components.YesButton.Id, Fraction = 1.15}) - Attach({ Id = components.YesButton.Id, DestinationId = components.Background.Id, OffsetX = -150, OffsetY = 75 }) - CreateTextBox({ Id = components.YesButton.Id, Text = " "..yesText.." ", - FontSize = 28, OffsetX = 0, OffsetY = 0, Width = 720, Color = Color.LimeGreen, Font = "AlegreyaSansSCLight", - ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 2}, Justification = "Center" - }) - - components.NoButton = CreateScreenComponent({ Name = "BoonSlot1", Group = group, Scale = 0.35, }) - components.NoButton.OnPressedFunctionName = "ModUtil.Anchors.Menu."..group..".Funcs.No" - SetScaleX({Id = components.NoButton.Id, Fraction = 0.75}) - SetScaleY({Id = components.NoButton.Id, Fraction = 1.15}) - Attach({ Id = components.NoButton.Id, DestinationId = components.Background.Id, OffsetX = 150, OffsetY = 75 }) - CreateTextBox({ Id = components.NoButton.Id, Text = noText, - FontSize = 26, OffsetX = 0, OffsetY = 0, Width = 720, Color = Color.Red, Font = "AlegreyaSansSCLight", - ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 2}, Justification = "Center" - }) - - return ModUtil.Hades.PostOpenMenu( screen ) -end - -function ModUtil.Hades.CloseMenuYesNo( screen, button ) - PlaySound({ Name = "/SFX/Menu Sounds/GeneralWhooshMENU" }) - ModUtil.Hades.CloseMenu( screen, button ) -end - --- Misc - -function ModUtil.Hades.RandomElement( tableArg, rng ) - local Collapsed = CollapseTable( tableArg ) - return Collapsed[RandomInt( 1, #Collapsed, rng )] -end \ No newline at end of file From 2b11a4a8e98a7f0d63b41a244237cfb96b609b8c Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 17 Mar 2021 08:47:23 +1100 Subject: [PATCH 04/32] Add path intercept --- ModUtil.Hades.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ModUtil.Hades.lua b/ModUtil.Hades.lua index c7773c5..aa31178 100644 --- a/ModUtil.Hades.lua +++ b/ModUtil.Hades.lua @@ -10,6 +10,15 @@ ModUtil.Anchors.PrintOverhead = {} -- Global Interception +local function getGlobalPath( path ) + and path:find("[.]") + and not path:find("[.][.]+") + and not path:find("^[.]") + and not path:find("[.]$") then + return ModUtil.Path.Get( path ) + end +end + --[[ Intercept global keys which are objects to return themselves This way we can use other namespaces for UI etc @@ -18,7 +27,9 @@ ModUtil.IndexArray.Wrap( getmetatable( _ENV ), { "__index" }, function( baseFunc local value = baseFunc( self, key ) if value ~= nil then return value end local t = type( key ) - if t == "function" or t == "table" then + if t == "string" then + return getGlobalPath( key ) + elseif t == "function" or t == "table" then return key end end, ModUtil.Hades ) From 95cc58ab56d34a6021e565aa0823314c822e16fe Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Thu, 1 Jul 2021 11:45:31 +1000 Subject: [PATCH 05/32] should fix table.insert --- ModUtil.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModUtil.lua b/ModUtil.lua index 6a492c7..f7dc732 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -170,7 +170,7 @@ function table.insert( list, pos, value ) repeat list[ i + 1 ] = list[ i ] i = i - 1 - until i <= pos + until i < pos end list[ pos ] = value end From 8cbd8c2c828c44541c7482778a43cf6dfdb7e822 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 16 Aug 2021 22:00:11 +1000 Subject: [PATCH 06/32] Fix Contexts! --- ModUtil.Main.lua | 5 ++++ ModUtil.lua | 70 +++++++++++++++--------------------------------- 2 files changed, 26 insertions(+), 49 deletions(-) diff --git a/ModUtil.Main.lua b/ModUtil.Main.lua index 2df70f2..caaa1fa 100644 --- a/ModUtil.Main.lua +++ b/ModUtil.Main.lua @@ -3,6 +3,11 @@ Components of ModUtil that depend on loading after Main.lua ]] +ModUtil.Anchors = { + Menu = { }, + CloseFuncs = { } +} + --- bind to locals to minimise environment recursion and improve speed local ModUtil, pairs, ipairs, table, SaveIgnores, _G = ModUtil, pairs, ipairs, table, SaveIgnores, ModUtil.Internal._G diff --git a/ModUtil.lua b/ModUtil.lua index f7dc732..bcce0ec 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -20,11 +20,7 @@ ModUtil = { Locals = { }, Entangled = { }, Internal = { }, - Metatables = { }, - Anchors = { - Menu = { }, - CloseFuncs = { } - } + Metatables = { } } @@ -1768,15 +1764,15 @@ ModUtil.Metatables.Context = { threadContexts[ thread ] = contextInfo + local penv = threadEnvironments[ thread ] + contextInfo.penv = threadEnvironments[ thread ] or _G + contextInfo.context = self contextInfo.args = table.pack( ... ) contextInfo.data = { } contextInfo.params = table.pack( getObjectData( self, "callContextProcessor" )( contextInfo ) ) - - local penv = threadEnvironments[ thread ] - local env = setmetatable( { }, { __index = ( penv or _G ), __newindex = ( penv or _G ) } ) - threadEnvironments[ thread ] = env - + + threadEnvironments[ thread ] = contextInfo.env contextInfo.response = table.pack( contextInfo.wrap( table.unpack( contextInfo.params ) ) ) if getObjectData( self, "postCall" ) then @@ -1801,7 +1797,7 @@ setmetatable( ModUtil.Context, { ModUtil.Context.Data = ModUtil.Context( function( info ) local tbl = info.args[ 1 ] info.env = setmetatable( { }, { - __index = function( _, key ) return tbl[ key ] or __G[ key ] end, + __index = function( _, key ) return tbl[ key ] or info.penv[ key ] end, __newindex = tbl } ) end ) @@ -1809,7 +1805,7 @@ end ) ModUtil.Context.Meta = ModUtil.Context( function( info ) local tbl = ModUtil.Nodes.Data.Metatable.New( info.args[ 1 ] ) info.env = setmetatable( { }, { - __index = function( _, key ) return tbl[ key ] or __G[ key ] end, + __index = function( _, key ) return tbl[ key ] or info.penv[ key ] end, __newindex = tbl } ) end ) @@ -1820,7 +1816,10 @@ ModUtil.Context.Env = ModUtil.Context( function( info ) local func = info.args[ 1 ] local fenv = fenvData[ func ] if not fenv then - fenv = getfenv( func ) or { } + fenv = getfenv( func ) + if not fenv or fenv == __G then + fenv = { } + end fenvData[ func ] = fenv end setfenv( func, setmetatable( { }, { @@ -1839,55 +1838,28 @@ ModUtil.Context.Env = ModUtil.Context( function( info ) local env = threadEnvironments[ coroutine.running( ) ] if env and env[ key ] ~= nil then env[ key ] = val - elseif fenv[ key ] ~= nil then + return + end + if fenv[ key ] ~= nil then fenv[ key ] = val + return end _G[ key ] = val end } ) ) info.env = setmetatable( { }, { - __index = function( _, key ) return fenv[ key ] or __G[ key ] end, + __index = function( _, key ) return fenv[ key ] or info.penv[ key ] end, __newindex = fenv } ) -end ) + end +) ModUtil.Context.Call = ModUtil.Context( function( info ) - local meta - local penv = threadEnvironments[ info.thread ] - local func = info.args[ 1 ] - - meta = { - __index = function( _, key ) - local data = fenvData[ func ] - if data then - local val = data[ key ] - if val ~= nil then return val end - end - return ( penv or _G )[ key ] - end, - __newindex = function( _, key, val ) - local data = fenvData[ func ] - if data and data[ key ] ~= nil then - data[ key ] = val - else - ( penv or _G )[ key ] = val - end - end - } - - local env = setmetatable( { }, meta ) - info.env = setmetatable( { }, { __index = env, __newindex = ModUtil.RawInterface( env ) } ) - - info.data.penv = penv - info.data.env = env - info.data.func = func + info.env = setmetatable( { }, { __index = info.penv } ) end, function ( info ) - threadEnvironments[ info.thread ] = info.env - local ret = table.pack( info.data.func( table.unpack( info.args, 2, info.args.n ) ) ) - threadEnvironments[ info.thread ] = info.penv - return table.unpack( ret ) + return info.args[ 1 ]( table.unpack( info.args, 2, info.args.n ) ) end ) From f74e45c51c8ffe894374fc374d8631cbd387aa8f Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 16 Aug 2021 22:20:06 +1000 Subject: [PATCH 07/32] fix syntax --- ModUtil.Hades.lua | 10 ++++++---- ModUtil.lua | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ModUtil.Hades.lua b/ModUtil.Hades.lua index aa31178..a3bc513 100644 --- a/ModUtil.Hades.lua +++ b/ModUtil.Hades.lua @@ -11,12 +11,14 @@ ModUtil.Anchors.PrintOverhead = {} -- Global Interception local function getGlobalPath( path ) - and path:find("[.]") - and not path:find("[.][.]+") - and not path:find("^[.]") - and not path:find("[.]$") then + if path:find("[.]") + and not path:find("[.][.]+") + and not path:find("^[.]") + and not path:find("[.]$") then + return ModUtil.Path.Get( path ) end + return path end --[[ diff --git a/ModUtil.lua b/ModUtil.lua index bcce0ec..cfa0c49 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -2125,7 +2125,8 @@ do return _G, objectData, newObjectData, getObjectData, wrapCallbacks, overrides, - threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment + threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, + pusherror end ) setmetatable( ModUtil.Internal, { __index = ups, __newindex = ups } ) end From fa78b56bf74fc7b7e62c71d2f341d65fec4d0d6a Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 16 Aug 2021 22:38:00 +1000 Subject: [PATCH 08/32] compat for wrapwithin --- ModUtil.Compat.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index d9212ed..2472268 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -79,4 +79,16 @@ ModUtil.Compat.BaseOverride = ModUtil.Path.Override ModUtil.Compat.GetOriginalValue = ModUtil.IndexArray.Original -ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original \ No newline at end of file +ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original + +function ModUtil.Compat.WrapWithinFunction( baseTable, indexArray, envIndexArray, wrapFunc, mod ) + ModUtil.Context.Env( function( ) + ModUtil.IndexArray.Wrap( _G, envIndexArray, wrapFunc, mod ) + end, ModUtil.IndexArray.Get( baseTable, indexArray ) ) +end + +function ModUtil.Compat.BaseWrapWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) + ModUtil.Context.Env( function( ) + ModUtil.Path.Wrap( funcPath, wrapFunc, mod ) + end, ModUtil.IndexArray.Get( baseFuncPath ) ) +end \ No newline at end of file From 8cecd6b8f3f2d58b8aa15228fc9586608d9acee6 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 16 Aug 2021 23:15:37 +1000 Subject: [PATCH 09/32] Fix global intercept --- ModUtil.Hades.lua | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ModUtil.Hades.lua b/ModUtil.Hades.lua index a3bc513..b53ffc1 100644 --- a/ModUtil.Hades.lua +++ b/ModUtil.Hades.lua @@ -10,15 +10,11 @@ ModUtil.Anchors.PrintOverhead = {} -- Global Interception -local function getGlobalPath( path ) - if path:find("[.]") +local function isPath( path ) + return path:find("[.]") and not path:find("[.][.]+") and not path:find("^[.]") - and not path:find("[.]$") then - - return ModUtil.Path.Get( path ) - end - return path + and not path:find("[.]$") end --[[ @@ -29,9 +25,10 @@ ModUtil.IndexArray.Wrap( getmetatable( _ENV ), { "__index" }, function( baseFunc local value = baseFunc( self, key ) if value ~= nil then return value end local t = type( key ) - if t == "string" then - return getGlobalPath( key ) - elseif t == "function" or t == "table" then + if t == "string" and isPath( key ) then + return ModUtil.Path.Get( key ) + end + if t == "function" or t == "table" then return key end end, ModUtil.Hades ) From 71326d995d5c210f54769784fb081700063efb62 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Mon, 16 Aug 2021 23:35:57 +1000 Subject: [PATCH 10/32] Update ModUtil.Compat.lua --- ModUtil.Compat.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index 2472268..b30b923 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -87,8 +87,8 @@ function ModUtil.Compat.WrapWithinFunction( baseTable, indexArray, envIndexArray end, ModUtil.IndexArray.Get( baseTable, indexArray ) ) end -function ModUtil.Compat.BaseWrapWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) +function ModUtil.Compat.WrapBaseWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) ModUtil.Context.Env( function( ) ModUtil.Path.Wrap( funcPath, wrapFunc, mod ) end, ModUtil.IndexArray.Get( baseFuncPath ) ) -end \ No newline at end of file +end From 2efa6ce21492370d08104b1b408d46d1467554e5 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Tue, 17 Aug 2021 03:45:37 +1000 Subject: [PATCH 11/32] UNTESTED: add Context.Wrap and extended traversal --- ModUtil.Compat.lua | 8 +- ModUtil.Hades.lua | 2 +- ModUtil.lua | 190 +++++++++++++++++++++++++++------------------ 3 files changed, 119 insertions(+), 81 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index b30b923..5ce2b1f 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -82,13 +82,13 @@ ModUtil.Compat.GetOriginalValue = ModUtil.IndexArray.Original ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original function ModUtil.Compat.WrapWithinFunction( baseTable, indexArray, envIndexArray, wrapFunc, mod ) - ModUtil.Context.Env( function( ) + ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, function( ) ModUtil.IndexArray.Wrap( _G, envIndexArray, wrapFunc, mod ) - end, ModUtil.IndexArray.Get( baseTable, indexArray ) ) + end ) end function ModUtil.Compat.WrapBaseWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) - ModUtil.Context.Env( function( ) + ModUtil.Path.Context.Wrap( baseFuncPath, function( ) ModUtil.Path.Wrap( funcPath, wrapFunc, mod ) - end, ModUtil.IndexArray.Get( baseFuncPath ) ) + end ) end diff --git a/ModUtil.Hades.lua b/ModUtil.Hades.lua index b53ffc1..092f169 100644 --- a/ModUtil.Hades.lua +++ b/ModUtil.Hades.lua @@ -28,7 +28,7 @@ ModUtil.IndexArray.Wrap( getmetatable( _ENV ), { "__index" }, function( baseFunc if t == "string" and isPath( key ) then return ModUtil.Path.Get( key ) end - if t == "function" or t == "table" then + if ModUtil.Internal.callableCandidateTypes[ t ] then return key end end, ModUtil.Hades ) diff --git a/ModUtil.lua b/ModUtil.lua index cfa0c49..4530f0c 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -262,7 +262,7 @@ function ModUtil.RawInterface( obj ) } ) end --- Environment Context ( EXPERIMENTAL ) ( BROKEN ) +-- Environment Manipulation local _G = _ENV local __G @@ -305,11 +305,77 @@ local function replaceGlobalEnvironment( ) ModUtil.Identifiers.Inverse._ENV = __G end +local fenvData = setmetatable( { }, { __mode = "k" } ) + +function _G.getfenv( func ) + local fenv = fenvData[ func ] + if not fenv then + fenv = getfenv( func ) + if fenv == __G then + fenv = nil + end + end + return fenv +end + +function _G.newfenv( func ) + local fenv = _G.getfenv( func ) + if not fenv then + fenv = { } + fenvData[ func ] = fenv + end + return fenv +end + +function _G.setfenv( func, fenv ) + fenvData[ func ] = fenv + + setfenv( func, setmetatable( { }, { + __index = function( _, key ) + local val + local env = threadEnvironments[ coroutine.running( ) ] + if env then + val = env[ key ] + end + if val ~= nil then return val end + val = fenv[ key ] + if val ~= nil then return val end + return _G[ key ] + end, + __newindex = function( _, key, val ) + local env = threadEnvironments[ coroutine.running( ) ] + if env and env[ key ] ~= nil then + env[ key ] = val + return + end + if fenv[ key ] ~= nil then + fenv[ key ] = val + return + end + _G[ key ] = val + end + } ) ) +end + -- Data Misc local passByValueTypes = ToLookup{ "number", "boolean", "nil" } +local callableCandidateTypes = ToLookup{ "function", "table", "userdata" } local excludedFieldNames = ToLookup{ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" } +function ModUtil.Callable( obj ) + local meta, pobj + while obj do + local t = type( obj ) + if t == "function" then break end + if not callableCandidateTypes[ t ] then return nil, nil, pobj end + meta = getmetatable( obj ) + if not meta then break end + pobj, obj = obj, rawget( meta, "__call" ) + end + return obj, meta, pobj +end + setmetatable( ModUtil.ToString, { __call = function ( _, o ) local identifier = ModUtil.Identifiers.Data[ o ] @@ -684,7 +750,12 @@ function ModUtil.IndexArray.Get( baseTable, indexArray ) if nodeType then node = ModUtil.Nodes.Data[ nodeType ].Get( node ) else - node = node[ key ] + local call = ModUtil.Callable( key ) + if call then + node = call( node ) + else + node = node[ key ] + end end end return node @@ -712,12 +783,17 @@ function ModUtil.IndexArray.Set( baseTable, indexArray, value ) local node = baseTable for i = 1, n - 1 do local key = indexArray[ i ] - if not ModUtil.Table.New( node, key ) then return false end + if not ModUtil.Nodes.New( parent, key ) then return false end local nodeType = ModUtil.Nodes.Inverse[ key ] if nodeType then node = ModUtil.Nodes.Data[ nodeType ].Get( node ) else - node = node[ key ] + local call = ModUtil.Callable( key ) + if call then + node = call( node ) + else + node = node[ key ] + end end end local key = indexArray[ n ] @@ -725,6 +801,10 @@ function ModUtil.IndexArray.Set( baseTable, indexArray, value ) if nodeType then return ModUtil.Nodes.Data[ nodeType ].Set( node, value ) end + local call = ModUtil.Callable( key ) + if call then + return call( node, value ) + end node[ key ] = value return true end @@ -1743,7 +1823,7 @@ setmetatable( ModUtil.Entangled.Map.Unique, { end } ) --- Context Managers ( EXPERIMENTAL ) ( BROKEN ) +-- Context Managers ModUtil.Context = { } @@ -1751,7 +1831,7 @@ local threadContexts = { } setmetatable( threadContexts, { __mode = "kv" } ) ModUtil.Metatables.Context = { - __call = function( self, callContext, ... ) + __call = function( self, arg, callContext, ... ) local thread = coroutine.running( ) @@ -1769,6 +1849,7 @@ ModUtil.Metatables.Context = { contextInfo.context = self contextInfo.args = table.pack( ... ) + contextInfo.arg = arg contextInfo.data = { } contextInfo.params = table.pack( getObjectData( self, "callContextProcessor" )( contextInfo ) ) @@ -1795,7 +1876,7 @@ setmetatable( ModUtil.Context, { } ) ModUtil.Context.Data = ModUtil.Context( function( info ) - local tbl = info.args[ 1 ] + local tbl = info.arg info.env = setmetatable( { }, { __index = function( _, key ) return tbl[ key ] or info.penv[ key ] end, __newindex = tbl @@ -1803,50 +1884,17 @@ ModUtil.Context.Data = ModUtil.Context( function( info ) end ) ModUtil.Context.Meta = ModUtil.Context( function( info ) - local tbl = ModUtil.Nodes.Data.Metatable.New( info.args[ 1 ] ) + local tbl = ModUtil.Nodes.Data.Metatable.New( info.arg ) info.env = setmetatable( { }, { __index = function( _, key ) return tbl[ key ] or info.penv[ key ] end, __newindex = tbl } ) end ) -local fenvData = setmetatable( { }, { __mode = "k" } ) - ModUtil.Context.Env = ModUtil.Context( function( info ) - local func = info.args[ 1 ] - local fenv = fenvData[ func ] - if not fenv then - fenv = getfenv( func ) - if not fenv or fenv == __G then - fenv = { } - end - fenvData[ func ] = fenv - end - setfenv( func, setmetatable( { }, { - __index = function( _, key ) - local val - local env = threadEnvironments[ coroutine.running( ) ] - if env then - val = env[ key ] - end - if val ~= nil then return val end - val = fenv[ key ] - if val ~= nil then return val end - return _G[ key ] - end, - __newindex = function( _, key, val ) - local env = threadEnvironments[ coroutine.running( ) ] - if env and env[ key ] ~= nil then - env[ key ] = val - return - end - if fenv[ key ] ~= nil then - fenv[ key ] = val - return - end - _G[ key ] = val - end - } ) ) + local func = info.arg + local fenv = _G.newfenv( func ) + ModUtil.SetFunctionEnvironment( func, fenv ) info.env = setmetatable( { }, { __index = function( _, key ) return fenv[ key ] or info.penv[ key ] end, __newindex = fenv @@ -1859,10 +1907,14 @@ ModUtil.Context.Call = ModUtil.Context( info.env = setmetatable( { }, { __index = info.penv } ) end, function ( info ) - return info.args[ 1 ]( table.unpack( info.args, 2, info.args.n ) ) + return info.arg( table.unpack( info.args ) ) end ) +ModUtil.Context.Wrap = function( func, context ) + return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( context, base, ... ) end ) +end + -- Special traversal nodes ModUtil.Nodes = ModUtil.Entangled.Map.Unique( ) @@ -1872,6 +1924,8 @@ function ModUtil.Nodes.New( parent, key ) if nodeType then return ModUtil.Nodes.Data[ nodeType ].New( parent ) end + local call = ModUtil.Callable( key ) + if call then return call( parent ) local tbl = parent[ key ] if type( tbl ) ~= "table" then tbl = { } @@ -1900,41 +1954,16 @@ ModUtil.Nodes.Data.Metatable = { ModUtil.Nodes.Data.Call = { New = function( obj ) - local call - while type( obj ) == "table" do - local meta = getmetatable( obj ) - if meta then - call = meta.__call - if call then - obj = call - end - end - end + local call = ModUtil.Callable( obj ) return call or error( "node new rejected, new call nodes are not meaningfully mutable.", 2 ) end, Get = function( obj ) - while type( obj ) == "table" do - local meta = getmetatable( obj ) - if meta then - if meta.__call then - obj = meta.__call - end - end - end - return obj + local call = ModUtil.Callable( obj ) + return call end, Set = function( obj, value ) - local meta - while type( obj ) == "table" do - meta = getmetatable( obj ) - if meta then - if meta.__call then - obj = meta.__call - end - end - end - if not meta then return false end - meta.__call = value + local _, meta, parent = ModUtil.Callable( obj ) + rawset( getmetatable( setmetatable( parent, meta or { } ) ), "__call", value ) return true end } @@ -2056,6 +2085,10 @@ function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrapFunc, mod ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrapFunc, mod ) end +function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) +end + function ModUtil.IndexArray.Unwrap( baseTable, indexArray ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Unwrap ) end @@ -2090,6 +2123,10 @@ function ModUtil.Path.Wrap( path, wrapFunc, mod ) ModUtil.Path.Map( path, ModUtil.Wrap, wrapFunc, mod ) end +function ModUtil.IndexArray.Context.Wrap( path, context, mod ) + ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) +end + function ModUtil.Path.Unwrap( path ) ModUtil.Path.Map( path, ModUtil.Unwrap ) end @@ -2126,7 +2163,8 @@ do objectData, newObjectData, getObjectData, wrapCallbacks, overrides, threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, - pusherror + pusherror, getname, + passByValueTypes, callableCandidateTypes, excludedFieldNames end ) setmetatable( ModUtil.Internal, { __index = ups, __newindex = ups } ) end From cb9f81fc6cd13622420dd30108d16f2902e6c641 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Tue, 17 Aug 2021 05:24:18 +1000 Subject: [PATCH 12/32] UNTESTED: (actually loads) add Context.Wrap and extended traversal --- ModUtil.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index 4530f0c..0152708 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -783,7 +783,7 @@ function ModUtil.IndexArray.Set( baseTable, indexArray, value ) local node = baseTable for i = 1, n - 1 do local key = indexArray[ i ] - if not ModUtil.Nodes.New( parent, key ) then return false end + if not ModUtil.Nodes.New( node, key ) then return false end local nodeType = ModUtil.Nodes.Inverse[ key ] if nodeType then node = ModUtil.Nodes.Data[ nodeType ].Get( node ) @@ -1911,8 +1911,8 @@ ModUtil.Context.Call = ModUtil.Context( end ) -ModUtil.Context.Wrap = function( func, context ) - return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( context, base, ... ) end ) +function ModUtil.Context.Wrap( func, context, mod ) + return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( context, base, ... ) end, mod ) end -- Special traversal nodes @@ -1925,7 +1925,7 @@ function ModUtil.Nodes.New( parent, key ) return ModUtil.Nodes.Data[ nodeType ].New( parent ) end local call = ModUtil.Callable( key ) - if call then return call( parent ) + if call then return call( parent ) end local tbl = parent[ key ] if type( tbl ) ~= "table" then tbl = { } @@ -2081,6 +2081,8 @@ end --- +ModUtil.IndexArray.Context = { } + function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrapFunc, mod ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrapFunc, mod ) end @@ -2119,11 +2121,13 @@ end --- +ModUtil.Path.Context = { } + function ModUtil.Path.Wrap( path, wrapFunc, mod ) ModUtil.Path.Map( path, ModUtil.Wrap, wrapFunc, mod ) end -function ModUtil.IndexArray.Context.Wrap( path, context, mod ) +function ModUtil.Path.Context.Wrap( path, context, mod ) ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) end From f156f5645b34959e2c042a21f5545e367b79ea7d Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Tue, 17 Aug 2021 05:39:39 +1000 Subject: [PATCH 13/32] Partially tested --- ModUtil.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModUtil.lua b/ModUtil.lua index 0152708..c54c007 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -1894,7 +1894,7 @@ end ) ModUtil.Context.Env = ModUtil.Context( function( info ) local func = info.arg local fenv = _G.newfenv( func ) - ModUtil.SetFunctionEnvironment( func, fenv ) + _G.setfenv( func, fenv ) info.env = setmetatable( { }, { __index = function( _, key ) return fenv[ key ] or info.penv[ key ] end, __newindex = fenv From ba85253672a88ec6bb82bf657b0ec75452b10bd3 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Tue, 17 Aug 2021 05:42:52 +1000 Subject: [PATCH 14/32] fixed, tested, need to add some kind of priority --- ModUtil.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModUtil.lua b/ModUtil.lua index c54c007..01773ee 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -1912,7 +1912,7 @@ ModUtil.Context.Call = ModUtil.Context( ) function ModUtil.Context.Wrap( func, context, mod ) - return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( context, base, ... ) end, mod ) + return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( base, context, ... ) end, mod ) end -- Special traversal nodes From 29ba86e1a6d2fc97bbdd330ee1ebba425669bf0d Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 02:02:38 +1000 Subject: [PATCH 15/32] UNTESTED: extend wraps to decorators --- ModUtil.lua | 175 +++++++++++++++++++++++++++------------------------- 1 file changed, 90 insertions(+), 85 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index 01773ee..e0d4c5a 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -9,15 +9,11 @@ Author: MagicGonads ModUtil = { Mod = { }, - Print = { }, - ToString = { }, String = { }, Table = { }, Path = { }, Array = { }, IndexArray = { }, - UpValues = { }, - Locals = { }, Entangled = { }, Internal = { }, Metatables = { } @@ -218,6 +214,14 @@ local function ToLookup( tableArg ) return lookup end +local function tableFunction( t, f ) + return setmetatable( t, { + __call = function( _, ... ) + return f( ... ) + end + } ) +end + -- Managed Object Data local objectData = setmetatable( { }, { __mode = "k" } ) @@ -376,13 +380,11 @@ function ModUtil.Callable( obj ) return obj, meta, pobj end -setmetatable( ModUtil.ToString, { - __call = function ( _, o ) - local identifier = ModUtil.Identifiers.Data[ o ] - identifier = identifier and identifier .. ":" or "" - return identifier .. ModUtil.ToString.Static( o ) - end -}) +ModUtil.ToString = tableFunction( { }, function( o ) + local identifier = ModUtil.Identifiers.Data[ o ] + identifier = identifier and identifier .. ":" or "" + return identifier .. ModUtil.ToString.Static( o ) +end ) function ModUtil.ToString.Address( o ) local t = type( o ) @@ -596,18 +598,16 @@ end -- Print -setmetatable( ModUtil.Print, { - __call = function ( _, ... ) - print( ... ) - if DebugPrint then ModUtil.Print.Debug( ... ) end - if io then - if io.stdout ~= io.output( ) then - ModUtil.Print.ToFile( io.output( ), ... ) - end - io.flush( ) +ModUtil.Print = tableFunction( { }, function ( ... ) + print( ... ) + if DebugPrint then ModUtil.Print.Debug( ... ) end + if io then + if io.stdout ~= io.output( ) then + ModUtil.Print.ToFile( io.output( ), ... ) end + io.flush( ) end -}) +end ) function ModUtil.Print.ToFile( file, ... ) local close = false @@ -1181,14 +1181,12 @@ ModUtil.Metatables.UpValues = { end } -setmetatable( ModUtil.UpValues, { - __call = function( _, func ) - if type( func ) ~= "function" then - func = debug.getinfo( ( func or 1 ) + 1, "f" ).func - end - return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues ) +ModUtil.UpValues = tableFunction( { }, function( func ) + if type( func ) ~= "function" then + func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end -}) + return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues ) +end ) local idData = { } setmetatable( idData, { __mode = "k" } ) @@ -1462,11 +1460,9 @@ ModUtil.Metatables.Locals = { end } -setmetatable( ModUtil.Locals, { - __call = function( _, level ) - return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) - end -} ) +ModUtil.Locals = tableFunction( { }, function( level ) + return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) +end ) ModUtil.Metatables.Locals.Values = { __index = function( self, idx ) @@ -1803,25 +1799,21 @@ ModUtil.Entangled.Map = { Unique = { } } -setmetatable( ModUtil.Entangled.Map, { - __call = function( ) - local data, preImage = { }, { } - data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } - data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) - preImage = ModUtil.ObjectDataProxy( preImage, ModUtil.Metatables.Entangled.Map.PreImage ) - return { Data = data, Index = preImage, PreImage = preImage } - end -} ) +ModUtil.Entangled.Map = tableFunction( { }, function( ) + local data, preImage = { }, { } + data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } + data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) + preImage = ModUtil.ObjectDataProxy( preImage, ModUtil.Metatables.Entangled.Map.PreImage ) + return { Data = data, Index = preImage, PreImage = preImage } +end ) -setmetatable( ModUtil.Entangled.Map.Unique, { - __call = function( ) - local data, inverse = { }, { } - data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } - data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) - inverse = ModUtil.ObjectDataProxy( inverse, ModUtil.Metatables.Entangled.Map.Unique.Inverse ) - return { Data = data, Index = inverse, Inverse = inverse } - end -} ) +ModUtil.Entangled.Map.Unique = tableFunction( { }, function( ) + local data, inverse = { }, { } + data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } + data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) + inverse = ModUtil.ObjectDataProxy( inverse, ModUtil.Metatables.Entangled.Map.Unique.Inverse ) + return { Data = data, Index = inverse, Inverse = inverse } +end ) -- Context Managers @@ -1869,11 +1861,9 @@ ModUtil.Metatables.Context = { end } -setmetatable( ModUtil.Context, { - __call = function( _, callContextProcessor, postCall ) - return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) - end -} ) +ModUtil.Context = tableFunction( { }, function( callContextProcessor, postCall ) + return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) +end ) ModUtil.Context.Data = ModUtil.Context( function( info ) local tbl = info.arg @@ -1994,45 +1984,52 @@ setmetatable( getObjectData( ModUtil.Mods.Data, "Inverse" ), { __mode = "k" } ) setmetatable( getObjectData( ModUtil.Mods.Inverse, "Data" ), { __mode = "v" } ) ModUtil.Mods.Data.ModUtil = ModUtil --- Function Wrapping, Overriding, Referral +-- Function Wrapping, Decoration, Overriding, Referral -local wrapCallbacks = { } -setmetatable( wrapCallbacks, { __mode = "k" } ) +local decorators = { } +setmetatable( decorators, { __mode = "k" } ) local overrides = { } setmetatable( overrides, { __mode = "k" } ) +local function wrapDecorator( wrap ) + return function( base ) return function( ... ) wrap( base, ... ) end end +end + +ModUtil.Decorate = tableFunction ( { }, function( base, func, mod ) + local out = func( base ) + decorators[ out ] = { Base = base, Func = func, Mod = mod } + return out +end ) + function ModUtil.Wrap( base, wrap, mod ) - local obj = { Base = base, Wrap = wrap, Mod = mod } - local func = function( ... ) return wrap( base, ... ) end - wrapCallbacks[ func ] = obj - return func + return ModUtil.Decorate( base, wrapDecorator( wrap ), mod ) end -function ModUtil.Unwrap( obj ) - local callback = wrapCallbacks[ obj ] +function ModUtil.Decorate.Undo( obj ) + local callback = decorators[ obj ] return callback and callback.Base or obj end -function ModUtil.Rewrap( obj ) - local node = wrapCallbacks[ obj ] +function ModUtil.Decorate.Redo( obj ) + local node = decorators[ obj ] if not node then return ModUtil.Overriden( obj ) end - return ModUtil.Wrap( ModUtil.Rewrap( node.Base ), node.Wrap, node.Mod ) + return ModUtil.Decorate( ModUtil.Decorate.Redo( node.Base ), node.Func, node.Mod ) end function ModUtil.Override( base, value, mod ) local obj = { Base = ModUtil.Original( base ), Mod = mod } overrides[ value ] = obj - return ModUtil.Rewrap( value ) + return ModUtil.Decorate.Redo( value ) end function ModUtil.Overriden( obj ) - local node = wrapCallbacks[ obj ] + local node = decorators[ obj ] if not node then return obj end return ModUtil.Original( node.Base ) end function ModUtil.Original( obj ) - local node = wrapCallbacks[ obj ] or overrides[ obj ] + local node = decorators[ obj ] or overrides[ obj ] if not node then return obj end return ModUtil.Original( node.Base ) end @@ -2083,20 +2080,24 @@ end ModUtil.IndexArray.Context = { } -function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrapFunc, mod ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrapFunc, mod ) +function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrap, mod ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrap, mod ) end function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) end -function ModUtil.IndexArray.Unwrap( baseTable, indexArray ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Unwrap ) +ModUtil.Path.Decorate = tableFunction( { }, function( baseTable, indexArray, func, mod ) + ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) +end ) + +function ModUtil.IndexArray.Decorate.Undo( baseTable, indexArray ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Undo ) end -function ModUtil.IndexArray.Rewrap( baseTable, indexArray ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Rewrap ) +function ModUtil.IndexArray.Decorate.Redo( baseTable, indexArray ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Redo ) end function ModUtil.IndexArray.Override( baseTable, indexArray, value, mod ) @@ -2123,20 +2124,24 @@ end ModUtil.Path.Context = { } -function ModUtil.Path.Wrap( path, wrapFunc, mod ) - ModUtil.Path.Map( path, ModUtil.Wrap, wrapFunc, mod ) +function ModUtil.Path.Wrap( path, wrap, mod ) + ModUtil.Path.Map( path, ModUtil.Wrap, wrap, mod ) end function ModUtil.Path.Context.Wrap( path, context, mod ) ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) end -function ModUtil.Path.Unwrap( path ) - ModUtil.Path.Map( path, ModUtil.Unwrap ) +ModUtil.Path.Decorate = tableFunction( { }, function( path, func, mod ) + ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) +end ) + +function ModUtil.Path.Decorate.Undo( path ) + ModUtil.Path.Map( path, ModUtil.Decorate.Undo ) end -function ModUtil.Path.Rewrap( path ) - ModUtil.Path.Map( path, ModUtil.Rewrap ) +function ModUtil.Path.Decorate.Redo( path ) + ModUtil.Path.Map( path, ModUtil.Decorate.Redo ) end function ModUtil.Path.Override( path, value, mod ) @@ -2165,9 +2170,9 @@ do local ups = ModUtil.UpValues( function( ) return _G, objectData, newObjectData, getObjectData, - wrapCallbacks, overrides, + decorators, overrides, threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, - pusherror, getname, + pusherror, getname, tableFunction, passByValueTypes, callableCandidateTypes, excludedFieldNames end ) setmetatable( ModUtil.Internal, { __index = ups, __newindex = ups } ) From fdc8ee8d210d37fa61470481a26adc9f9674f899 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 02:07:23 +1000 Subject: [PATCH 16/32] UNTESTED: (prior commit) + compat upkeep --- ModUtil.Compat.lua | 8 ++++---- ModUtil.lua | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index 5ce2b1f..b5ae335 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -63,15 +63,15 @@ ModUtil.Compat.PathSet = ModUtil.Path.Set ModUtil.Compat.WrapFunction = ModUtil.IndexArray.Wrap -ModUtil.Compat.RewrapFunction = ModUtil.IndexArray.Rewrap +ModUtil.Compat.RewrapFunction = ModUtil.IndexArray.Decorate.Redo -ModUtil.Compat.UnwrapFunction = ModUtil.IndexArray.Unwrap +ModUtil.Compat.UnwrapFunction = ModUtil.IndexArray.Decorate.Undo ModUtil.Compat.WrapBaseFunction = ModUtil.Path.Wrap -ModUtil.Compat.RewrapBaseFunction = ModUtil.Path.Rewrap +ModUtil.Compat.RewrapBaseFunction = ModUtil.Path.Decorate.Redo -ModUtil.Compat.UnwrapBaseFunction = ModUtil.Path.Unwrap +ModUtil.Compat.UnwrapBaseFunction = ModUtil.Path.Decorate.Undo ModUtil.Compat.Override = ModUtil.IndexArray.Override diff --git a/ModUtil.lua b/ModUtil.lua index e0d4c5a..8014a47 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -2172,7 +2172,8 @@ do objectData, newObjectData, getObjectData, decorators, overrides, threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, - pusherror, getname, tableFunction, + pusherror, getname, + tableFunction, ToLookup, wrapDecorator, passByValueTypes, callableCandidateTypes, excludedFieldNames end ) setmetatable( ModUtil.Internal, { __index = ups, __newindex = ups } ) From f8c617133631ad666757d0f0b5558ff229ec66fc Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 02:44:06 +1000 Subject: [PATCH 17/32] decorators edit loads --- ModUtil.lua | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index 8014a47..01d3ed5 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -1795,11 +1795,7 @@ ModUtil.Metatables.Entangled.Map = { } -ModUtil.Entangled.Map = { - Unique = { } -} - -ModUtil.Entangled.Map = tableFunction( { }, function( ) +ModUtil.Entangled.Map = tableFunction( { Unique = { } }, function( ) local data, preImage = { }, { } data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) @@ -1817,8 +1813,6 @@ end ) -- Context Managers -ModUtil.Context = { } - local threadContexts = { } setmetatable( threadContexts, { __mode = "kv" } ) @@ -1992,10 +1986,10 @@ local overrides = { } setmetatable( overrides, { __mode = "k" } ) local function wrapDecorator( wrap ) - return function( base ) return function( ... ) wrap( base, ... ) end end + return function( base ) return function( ... ) return wrap( base, ... ) end end end -ModUtil.Decorate = tableFunction ( { }, function( base, func, mod ) +ModUtil.Decorate = tableFunction( { }, function( base, func, mod ) local out = func( base ) decorators[ out ] = { Base = base, Func = func, Mod = mod } return out @@ -2088,7 +2082,7 @@ function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) end -ModUtil.Path.Decorate = tableFunction( { }, function( baseTable, indexArray, func, mod ) +ModUtil.IndexArray.Decorate = tableFunction( { }, function( baseTable, indexArray, func, mod ) ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -2112,6 +2106,8 @@ function ModUtil.IndexArray.Original( baseTable, indexArray ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Original ) end + + function ModUtil.IndexArray.ReferFunction( baseTable, indexArray ) return ModUtil.ReferFunction( ModUtil.IndexArray.Get, baseTable, indexArray ) end @@ -2174,6 +2170,7 @@ do threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, pusherror, getname, tableFunction, ToLookup, wrapDecorator, + stackLevelFunction, stackLevelInterface, stackLevelProperty, passByValueTypes, callableCandidateTypes, excludedFieldNames end ) setmetatable( ModUtil.Internal, { __index = ups, __newindex = ups } ) From ede5b2b79a34860c95c10e01438939a3f3f43edd Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 02:50:08 +1000 Subject: [PATCH 18/32] small internal rename --- ModUtil.lua | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index 01d3ed5..33c68b4 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -214,8 +214,8 @@ local function ToLookup( tableArg ) return lookup end -local function tableFunction( t, f ) - return setmetatable( t, { +local function calltable( f, t ) + return setmetatable( t or { }, { __call = function( _, ... ) return f( ... ) end @@ -380,7 +380,7 @@ function ModUtil.Callable( obj ) return obj, meta, pobj end -ModUtil.ToString = tableFunction( { }, function( o ) +ModUtil.ToString = calltable( function( o ) local identifier = ModUtil.Identifiers.Data[ o ] identifier = identifier and identifier .. ":" or "" return identifier .. ModUtil.ToString.Static( o ) @@ -598,7 +598,7 @@ end -- Print -ModUtil.Print = tableFunction( { }, function ( ... ) +ModUtil.Print = calltable( function ( ... ) print( ... ) if DebugPrint then ModUtil.Print.Debug( ... ) end if io then @@ -1181,7 +1181,7 @@ ModUtil.Metatables.UpValues = { end } -ModUtil.UpValues = tableFunction( { }, function( func ) +ModUtil.UpValues = calltable( function( func ) if type( func ) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end @@ -1460,7 +1460,7 @@ ModUtil.Metatables.Locals = { end } -ModUtil.Locals = tableFunction( { }, function( level ) +ModUtil.Locals = calltable( function( level ) return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) end ) @@ -1795,15 +1795,15 @@ ModUtil.Metatables.Entangled.Map = { } -ModUtil.Entangled.Map = tableFunction( { Unique = { } }, function( ) +ModUtil.Entangled.Map = calltable( function( ) local data, preImage = { }, { } data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) preImage = ModUtil.ObjectDataProxy( preImage, ModUtil.Metatables.Entangled.Map.PreImage ) return { Data = data, Index = preImage, PreImage = preImage } -end ) +end, { Unique = { } } ) -ModUtil.Entangled.Map.Unique = tableFunction( { }, function( ) +ModUtil.Entangled.Map.Unique = calltable( function( ) local data, inverse = { }, { } data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) @@ -1855,7 +1855,7 @@ ModUtil.Metatables.Context = { end } -ModUtil.Context = tableFunction( { }, function( callContextProcessor, postCall ) +ModUtil.Context = calltable( function( callContextProcessor, postCall ) return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) end ) @@ -1989,7 +1989,7 @@ local function wrapDecorator( wrap ) return function( base ) return function( ... ) return wrap( base, ... ) end end end -ModUtil.Decorate = tableFunction( { }, function( base, func, mod ) +ModUtil.Decorate = calltable( function( base, func, mod ) local out = func( base ) decorators[ out ] = { Base = base, Func = func, Mod = mod } return out @@ -2082,7 +2082,7 @@ function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) end -ModUtil.IndexArray.Decorate = tableFunction( { }, function( baseTable, indexArray, func, mod ) +ModUtil.IndexArray.Decorate = calltable( function( baseTable, indexArray, func, mod ) ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -2128,7 +2128,7 @@ function ModUtil.Path.Context.Wrap( path, context, mod ) ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) end -ModUtil.Path.Decorate = tableFunction( { }, function( path, func, mod ) +ModUtil.Path.Decorate = calltable( function( path, func, mod ) ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) @@ -2169,7 +2169,7 @@ do decorators, overrides, threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, pusherror, getname, - tableFunction, ToLookup, wrapDecorator, + calltable, ToLookup, wrapDecorator, stackLevelFunction, stackLevelInterface, stackLevelProperty, passByValueTypes, callableCandidateTypes, excludedFieldNames end ) From e96172bee87523992bed5eb3e78312135a90b9f7 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 04:10:02 +1000 Subject: [PATCH 19/32] add Context.StaticWrap --- ModUtil.Compat.lua | 4 ++-- ModUtil.lua | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index b5ae335..26691df 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -82,13 +82,13 @@ ModUtil.Compat.GetOriginalValue = ModUtil.IndexArray.Original ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original function ModUtil.Compat.WrapWithinFunction( baseTable, indexArray, envIndexArray, wrapFunc, mod ) - ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, function( ) + ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, function( ) ModUtil.IndexArray.Wrap( _G, envIndexArray, wrapFunc, mod ) end ) end function ModUtil.Compat.WrapBaseWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) - ModUtil.Path.Context.Wrap( baseFuncPath, function( ) + ModUtil.Path.Context.StaticWrap( baseFuncPath, function( ) ModUtil.Path.Wrap( funcPath, wrapFunc, mod ) end ) end diff --git a/ModUtil.lua b/ModUtil.lua index 33c68b4..5fefbc7 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -1841,12 +1841,12 @@ ModUtil.Metatables.Context = { threadEnvironments[ thread ] = contextInfo.env contextInfo.response = table.pack( contextInfo.wrap( table.unpack( contextInfo.params ) ) ) + threadEnvironments[ thread ] = penv if getObjectData( self, "postCall" ) then contextInfo.final = table.pack( getObjectData( self, "postCall" )( contextInfo ) ) end - threadEnvironments[ thread ] = penv threadContexts[ thread ] = contextInfo.parent if contextInfo.final then @@ -1891,7 +1891,28 @@ ModUtil.Context.Call = ModUtil.Context( info.env = setmetatable( { }, { __index = info.penv } ) end, function ( info ) - return info.arg( table.unpack( info.args ) ) + local thread = coroutine.running( ) + local penv = threadEnvironments[ thread ] + threadEnvironments[ thread ] = info.env + local ret = table.pack( info.arg( table.unpack( info.args ) ) ) + threadEnvironments[ thread ] = penv + return table.unpack( ret ) + end +) + +ModUtil.Context.StaticWrap = ModUtil.Context( + function( info ) + info.env = setmetatable( { }, { __index = info.penv } ) + end, + function ( info ) + return ModUtil.Wrap( info.arg, function( base, ... ) + local thread = coroutine.running( ) + local penv = threadEnvironments[ thread ] + threadEnvironments[ thread ] = info.env + local ret = table.pack( base( ... ) ) + threadEnvironments[ thread ] = penv + return table.unpack( ret ) + end, info.args[1] ) end ) @@ -2082,6 +2103,10 @@ function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) end +function ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, context, mod ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.StaticWrap, context, mod ) +end + ModUtil.IndexArray.Decorate = calltable( function( baseTable, indexArray, func, mod ) ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -2106,8 +2131,6 @@ function ModUtil.IndexArray.Original( baseTable, indexArray ) ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Original ) end - - function ModUtil.IndexArray.ReferFunction( baseTable, indexArray ) return ModUtil.ReferFunction( ModUtil.IndexArray.Get, baseTable, indexArray ) end @@ -2128,6 +2151,10 @@ function ModUtil.Path.Context.Wrap( path, context, mod ) ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) end +function ModUtil.Path.Context.StaticWrap( path, context, mod ) + ModUtil.Path.Map( path, ModUtil.Context.StaticWrap, context, mod ) +end + ModUtil.Path.Decorate = calltable( function( path, func, mod ) ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) From dbcd4bfbf46c715c59e45e1835b2c1a18c5bd7e9 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 04:36:31 +1000 Subject: [PATCH 20/32] make compat use env for wrapwithin --- ModUtil.Compat.lua | 4 ++-- ModUtil.lua | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index 26691df..6e967f9 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -82,13 +82,13 @@ ModUtil.Compat.GetOriginalValue = ModUtil.IndexArray.Original ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original function ModUtil.Compat.WrapWithinFunction( baseTable, indexArray, envIndexArray, wrapFunc, mod ) - ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, function( ) + ModUtil.IndexArray.Context.Env( baseTable, indexArray, function( ) ModUtil.IndexArray.Wrap( _G, envIndexArray, wrapFunc, mod ) end ) end function ModUtil.Compat.WrapBaseWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) - ModUtil.Path.Context.StaticWrap( baseFuncPath, function( ) + ModUtil.Path.Context.Env( baseFuncPath, function( ) ModUtil.Path.Wrap( funcPath, wrapFunc, mod ) end ) end diff --git a/ModUtil.lua b/ModUtil.lua index 5fefbc7..4ee0030 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -2107,6 +2107,11 @@ function ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, context, ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.StaticWrap, context, mod ) end +function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) + ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context ) +end + + ModUtil.IndexArray.Decorate = calltable( function( baseTable, indexArray, func, mod ) ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -2155,6 +2160,10 @@ function ModUtil.Path.Context.StaticWrap( path, context, mod ) ModUtil.Path.Map( path, ModUtil.Context.StaticWrap, context, mod ) end +function ModUtil.Path.Context.Env( path, context ) + ModUtil.Path.Map( path, ModUtil.Context.Env, context ) +end + ModUtil.Path.Decorate = calltable( function( path, func, mod ) ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) From 6c36d62c34e737ea393cb814803121aa4357b6a0 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 15:09:55 +1000 Subject: [PATCH 21/32] rename calltable and make it public --- ModUtil.lua | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index 4ee0030..d1e9464 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -214,12 +214,15 @@ local function ToLookup( tableArg ) return lookup end -local function calltable( f, t ) - return setmetatable( t or { }, { - __call = function( _, ... ) - return f( ... ) - end - } ) +-- Callable table setup + +function ModUtil.Table.SetCall( t, f ) + t = t or { } + local m = getmetatable( t ) or { } + function m.__call( _, ... ) + return f( ... ) + end + return setmetatable( t, m ) end -- Managed Object Data @@ -311,6 +314,8 @@ end local fenvData = setmetatable( { }, { __mode = "k" } ) +rawgetfenv = getfenv + function _G.getfenv( func ) local fenv = fenvData[ func ] if not fenv then @@ -331,6 +336,8 @@ function _G.newfenv( func ) return fenv end +rawsetfenv = setfenv + function _G.setfenv( func, fenv ) fenvData[ func ] = fenv @@ -380,7 +387,7 @@ function ModUtil.Callable( obj ) return obj, meta, pobj end -ModUtil.ToString = calltable( function( o ) +ModUtil.ToString = ModUtil.Table.SetCall( { }, function( o ) local identifier = ModUtil.Identifiers.Data[ o ] identifier = identifier and identifier .. ":" or "" return identifier .. ModUtil.ToString.Static( o ) @@ -598,7 +605,7 @@ end -- Print -ModUtil.Print = calltable( function ( ... ) +ModUtil.Print = ModUtil.Table.SetCall( { }, function ( ... ) print( ... ) if DebugPrint then ModUtil.Print.Debug( ... ) end if io then @@ -1181,7 +1188,7 @@ ModUtil.Metatables.UpValues = { end } -ModUtil.UpValues = calltable( function( func ) +ModUtil.UpValues = ModUtil.Table.SetCall( { }, function( func ) if type( func ) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end @@ -1460,7 +1467,7 @@ ModUtil.Metatables.Locals = { end } -ModUtil.Locals = calltable( function( level ) +ModUtil.Locals = ModUtil.Table.SetCall( { }, function( level ) return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) end ) @@ -1795,15 +1802,15 @@ ModUtil.Metatables.Entangled.Map = { } -ModUtil.Entangled.Map = calltable( function( ) +ModUtil.Entangled.Map = ModUtil.Table.SetCall( { Unique = { } }, function( ) local data, preImage = { }, { } data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) preImage = ModUtil.ObjectDataProxy( preImage, ModUtil.Metatables.Entangled.Map.PreImage ) return { Data = data, Index = preImage, PreImage = preImage } -end, { Unique = { } } ) +end ) -ModUtil.Entangled.Map.Unique = calltable( function( ) +ModUtil.Entangled.Map.Unique = ModUtil.Table.SetCall( { }, function( ) local data, inverse = { }, { } data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) @@ -1855,7 +1862,7 @@ ModUtil.Metatables.Context = { end } -ModUtil.Context = calltable( function( callContextProcessor, postCall ) +ModUtil.Context = ModUtil.Table.SetCall( { }, function( callContextProcessor, postCall ) return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) end ) @@ -2010,7 +2017,7 @@ local function wrapDecorator( wrap ) return function( base ) return function( ... ) return wrap( base, ... ) end end end -ModUtil.Decorate = calltable( function( base, func, mod ) +ModUtil.Decorate = ModUtil.Table.SetCall( { }, function( base, func, mod ) local out = func( base ) decorators[ out ] = { Base = base, Func = func, Mod = mod } return out @@ -2112,7 +2119,7 @@ function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) end -ModUtil.IndexArray.Decorate = calltable( function( baseTable, indexArray, func, mod ) +ModUtil.IndexArray.Decorate = ModUtil.Table.SetCall( { }, function( baseTable, indexArray, func, mod ) ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -2164,7 +2171,7 @@ function ModUtil.Path.Context.Env( path, context ) ModUtil.Path.Map( path, ModUtil.Context.Env, context ) end -ModUtil.Path.Decorate = calltable( function( path, func, mod ) +ModUtil.Path.Decorate = ModUtil.Table.SetCall( { }, function( path, func, mod ) ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) @@ -2204,8 +2211,7 @@ do objectData, newObjectData, getObjectData, decorators, overrides, threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, - pusherror, getname, - calltable, ToLookup, wrapDecorator, + pusherror, getname, ToLookup, wrapDecorator, stackLevelFunction, stackLevelInterface, stackLevelProperty, passByValueTypes, callableCandidateTypes, excludedFieldNames end ) From d702aeb2bd8ff013e4081d8debe522a8e4daaebb Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 18 Aug 2021 15:12:22 +1000 Subject: [PATCH 22/32] no reason setcall had to be specific to tables --- ModUtil.lua | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index d1e9464..fa07efa 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -214,15 +214,15 @@ local function ToLookup( tableArg ) return lookup end --- Callable table setup - -function ModUtil.Table.SetCall( t, f ) - t = t or { } - local m = getmetatable( t ) or { } +--[[ + Set an object's call to a function +]] +function ModUtil.SetCall( o, f ) + local m = getmetatable( o ) or { } function m.__call( _, ... ) return f( ... ) end - return setmetatable( t, m ) + return setmetatable( o, m ) end -- Managed Object Data @@ -387,7 +387,7 @@ function ModUtil.Callable( obj ) return obj, meta, pobj end -ModUtil.ToString = ModUtil.Table.SetCall( { }, function( o ) +ModUtil.ToString = ModUtil.SetCall( { }, function( o ) local identifier = ModUtil.Identifiers.Data[ o ] identifier = identifier and identifier .. ":" or "" return identifier .. ModUtil.ToString.Static( o ) @@ -605,7 +605,7 @@ end -- Print -ModUtil.Print = ModUtil.Table.SetCall( { }, function ( ... ) +ModUtil.Print = ModUtil.SetCall( { }, function ( ... ) print( ... ) if DebugPrint then ModUtil.Print.Debug( ... ) end if io then @@ -1188,7 +1188,7 @@ ModUtil.Metatables.UpValues = { end } -ModUtil.UpValues = ModUtil.Table.SetCall( { }, function( func ) +ModUtil.UpValues = ModUtil.SetCall( { }, function( func ) if type( func ) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end @@ -1467,7 +1467,7 @@ ModUtil.Metatables.Locals = { end } -ModUtil.Locals = ModUtil.Table.SetCall( { }, function( level ) +ModUtil.Locals = ModUtil.SetCall( { }, function( level ) return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) end ) @@ -1802,7 +1802,7 @@ ModUtil.Metatables.Entangled.Map = { } -ModUtil.Entangled.Map = ModUtil.Table.SetCall( { Unique = { } }, function( ) +ModUtil.Entangled.Map = ModUtil.SetCall( { Unique = { } }, function( ) local data, preImage = { }, { } data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) @@ -1810,7 +1810,7 @@ ModUtil.Entangled.Map = ModUtil.Table.SetCall( { Unique = { } }, function( ) return { Data = data, Index = preImage, PreImage = preImage } end ) -ModUtil.Entangled.Map.Unique = ModUtil.Table.SetCall( { }, function( ) +ModUtil.Entangled.Map.Unique = ModUtil.SetCall( { }, function( ) local data, inverse = { }, { } data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) @@ -1862,7 +1862,7 @@ ModUtil.Metatables.Context = { end } -ModUtil.Context = ModUtil.Table.SetCall( { }, function( callContextProcessor, postCall ) +ModUtil.Context = ModUtil.SetCall( { }, function( callContextProcessor, postCall ) return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) end ) @@ -2017,7 +2017,7 @@ local function wrapDecorator( wrap ) return function( base ) return function( ... ) return wrap( base, ... ) end end end -ModUtil.Decorate = ModUtil.Table.SetCall( { }, function( base, func, mod ) +ModUtil.Decorate = ModUtil.SetCall( { }, function( base, func, mod ) local out = func( base ) decorators[ out ] = { Base = base, Func = func, Mod = mod } return out @@ -2119,7 +2119,7 @@ function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) end -ModUtil.IndexArray.Decorate = ModUtil.Table.SetCall( { }, function( baseTable, indexArray, func, mod ) +ModUtil.IndexArray.Decorate = ModUtil.SetCall( { }, function( baseTable, indexArray, func, mod ) ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -2171,7 +2171,7 @@ function ModUtil.Path.Context.Env( path, context ) ModUtil.Path.Map( path, ModUtil.Context.Env, context ) end -ModUtil.Path.Decorate = ModUtil.Table.SetCall( { }, function( path, func, mod ) +ModUtil.Path.Decorate = ModUtil.SetCall( { }, function( path, func, mod ) ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) From a98cac9822fb4a5ecef82fd012e082aa8b750a38 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Thu, 19 Aug 2021 03:14:20 +1000 Subject: [PATCH 23/32] refined use of nodes, added union, prep for separating file --- ModUtil.lua | 729 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 424 insertions(+), 305 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index fa07efa..b574289 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -2,20 +2,19 @@ Mod: Mod Utility Author: MagicGonads - Library to allow mods to be more compatible with eachother and expand capabilities. - Use the mod importer to import this mod to ensure it is loaded in the right position. + Library to allow mods to be more compatible and expand capabilities. --]] ModUtil = { Mod = { }, + Args = { }, String = { }, Table = { }, Path = { }, Array = { }, IndexArray = { }, Entangled = { }, - Internal = { }, Metatables = { } } @@ -214,15 +213,54 @@ local function ToLookup( tableArg ) return lookup end ---[[ - Set an object's call to a function -]] -function ModUtil.SetCall( o, f ) - local m = getmetatable( o ) or { } - function m.__call( _, ... ) - return f( ... ) +-- Type/Syntax Constants + +local passByValueTypes = ToLookup{ "number", "boolean", "nil" } +local callableCandidateTypes = ToLookup{ "function", "table", "userdata" } -- string excluded because their references are managed +local excludedFieldNames = ToLookup{ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" } + + +-- Environment Manipulation + +local _G = _ENV +local __G + +local threadEnvironments = setmetatable( { }, { __mode = "k" } ) + +local function getEnv( thread ) + return threadEnvironments[ thread or coroutine.running( ) ] or _G +end + +local function replaceGlobalEnvironment( ) + __G = debug.setmetatable( { }, { + __index = function( _, key ) + return getEnv( )[ key ] + end, + __newindex = function( _, key, value ) + getEnv( )[ key ] = value + end, + __len = function( ) + return #getEnv( ) + end, + __next = function( _, key ) + return next( getEnv( ), key ) + end, + __inext = function( _, key ) + return inext( getEnv( ), key ) + end, + __pairs = function( ) + return pairs( getEnv( ) ) + end, + __ipairs = function( ) + return ipairs( getEnv( ) ) + end + } ) + _G._G = __G + local reg = debug.getregistry( ) + for i, v in ipairs( reg ) do + if v == _G then reg[ i ] = __G end end - return setmetatable( o, m ) + ModUtil.Identifiers.Inverse._ENV = __G end -- Managed Object Data @@ -269,125 +307,136 @@ function ModUtil.RawInterface( obj ) } ) end --- Environment Manipulation +-- Operations on Callables -local _G = _ENV -local __G +ModUtil.Callable = { } -local threadEnvironments = setmetatable( { }, { __mode = "k" } ) +function ModUtil.Callable.Get( obj ) + local meta, pobj + while obj do + local t = type( obj ) + if t == "function" then break end + if not callableCandidateTypes[ t ] then return pobj end + meta = getmetatable( obj ) + if not meta then break end + pobj, obj = obj, rawget( meta, "__call" ) + end + return pobj, obj +end -local function getEnv( thread ) - return threadEnvironments[ thread or coroutine.running( ) ] or _G +function ModUtil.Callable.Set( o, f ) + local m = getmetatable( o ) or { } + function m.__call( _, ... ) + return f( ... ) + end + return setmetatable( o, m ) end -local function replaceGlobalEnvironment( ) - __G = debug.setmetatable( { }, { - __index = function( _, key ) - return getEnv( )[ key ] - end, - __newindex = function( _, key, value ) - getEnv( )[ key ] = value - end, - __len = function( ) - return #getEnv( ) - end, - __next = function( _, key ) - return next( getEnv( ), key ) - end, - __inext = function( _, key ) - return inext( getEnv( ), key ) - end, - __pairs = function( ) - return pairs( getEnv( ) ) - end, - __ipairs = function( ) - return ipairs( getEnv( ) ) - end - } ) - _G._G = __G - local reg = debug.getregistry( ) - for i, v in ipairs( reg ) do - if v == _G then reg[ i ] = __G end +ModUtil.Callable.Set( ModUtil.Callable, function ( obj ) + local meta + while obj do + local t = type( obj ) + if t == "function" then return true end + if not callableCandidateTypes[ t ] then return false end + meta = getmetatable( obj ) + if not meta then break end + obj = rawget( meta, "__call" ) end - ModUtil.Identifiers.Inverse._ENV = __G +end ) + +-- Data Misc + +function ModUtil.Args.Map( mapFunc, ... ) + local out = { } + local args = table.pack( ... ) + for i = 1, args.n do + table.insert( out, mapFunc( args[ i ] ) ) + end + return table.unpack( out ) end -local fenvData = setmetatable( { }, { __mode = "k" } ) +function ModUtil.Args.Take( n, ... ) + local args = table.pack( ... ) + return table.unpack( args, 1, n ) +end -rawgetfenv = getfenv +function ModUtil.Args.Drop( n, ... ) + local args = table.pack( ... ) + return table.unpack( args, n + 1, args.n ) +end -function _G.getfenv( func ) - local fenv = fenvData[ func ] - if not fenv then - fenv = getfenv( func ) - if fenv == __G then - fenv = nil - end +function ModUtil.Table.Map( tableArg, mapFunc ) + local out = { } + for k, v in pairs( tableArg ) do + out[ k ] = mapFunc( v ) end - return fenv + return out end -function _G.newfenv( func ) - local fenv = _G.getfenv( func ) - if not fenv then - fenv = { } - fenvData[ func ] = fenv +function ModUtil.Table.Mutate( tableArg, mapFunc ) + for k, v in pairs( tableArg ) do + tableArg[ k ] = mapFunc( v ) end - return fenv end -rawsetfenv = setfenv +function ModUtil.Table.Replace( target, data ) + for k in pairs( target ) do + target[ k ] = data[ k ] + end + for k, v in pairs( data ) do + target[ k ] = v + end +end -function _G.setfenv( func, fenv ) - fenvData[ func ] = fenv - - setfenv( func, setmetatable( { }, { - __index = function( _, key ) - local val - local env = threadEnvironments[ coroutine.running( ) ] - if env then - val = env[ key ] - end - if val ~= nil then return val end - val = fenv[ key ] - if val ~= nil then return val end - return _G[ key ] - end, - __newindex = function( _, key, val ) - local env = threadEnvironments[ coroutine.running( ) ] - if env and env[ key ] ~= nil then - env[ key ] = val - return - end - if fenv[ key ] ~= nil then - fenv[ key ] = val - return - end - _G[ key ] = val +function ModUtil.Table.UnKeyed( tableArg ) + local lk = 0 + for k in pairs( tableArg ) do + if type( k ) ~= "number" then + return false + end + if lk + 1 ~= k then + return false end - } ) ) + lk = k + end + return true end --- Data Misc - -local passByValueTypes = ToLookup{ "number", "boolean", "nil" } -local callableCandidateTypes = ToLookup{ "function", "table", "userdata" } -local excludedFieldNames = ToLookup{ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" } +function ModUtil.String.Join( sep, ... ) + local out = {} + local args = table.pack( ... ) + out[ 1 ] = args[ 1 ] + for i = 2, args.n do + table.insert( out, sep ) + table.insert( out, args[ i ] ) + end + return table.concat( out ) +end -function ModUtil.Callable( obj ) - local meta, pobj - while obj do - local t = type( obj ) - if t == "function" then break end - if not callableCandidateTypes[ t ] then return nil, nil, pobj end - meta = getmetatable( obj ) - if not meta then break end - pobj, obj = obj, rawget( meta, "__call" ) +function ModUtil.String.Chunk( text, chunkSize, maxChunks ) + local chunks = { "" } + local cs = 0 + local ncs = 1 + for chr in text:gmatch( "." ) do + cs = cs + 1 + if cs > chunkSize or chr == "\n" then + ncs = ncs + 1 + if maxChunks and ncs > maxChunks then + return chunks + end + chunks[ ncs ] = "" + cs = 0 + end + if chr ~= "\n" then + chunks[ ncs ] = chunks[ ncs ] .. chr + end end - return obj, meta, pobj + return chunks end -ModUtil.ToString = ModUtil.SetCall( { }, function( o ) +-- String Representations + +ModUtil.ToString = ModUtil.Callable.Set( { }, function( o ) local identifier = ModUtil.Identifiers.Data[ o ] identifier = identifier and identifier .. ":" or "" return identifier .. ModUtil.ToString.Static( o ) @@ -525,87 +574,9 @@ function ModUtil.ToString.DeepNamespaces( o, seen ) end end -function ModUtil.MapVars( mapFunc, ... ) - local out = { } - local args = table.pack( ... ) - for i = 1, args.n do - table.insert( out, mapFunc( args[ i ] ) ) - end - return table.unpack( out ) -end - -function ModUtil.Table.MapCopy( tableArg, mapFunc ) - local out = { } - for k, v in pairs( tableArg ) do - out[ k ] = mapFunc( v ) - end - return out -end - -function ModUtil.Table.Map( tableArg, mapFunc ) - for k, v in pairs( tableArg ) do - tableArg[ k ] = mapFunc( v ) - end -end - -function ModUtil.String.Join( sep, ... ) - local out = {} - local args = table.pack( ... ) - out[ 1 ] = args[ 1 ] - for i = 2, args.n do - table.insert( out, sep ) - table.insert( out, args[ i ] ) - end - return table.concat( out ) -end - -function ModUtil.String.Chunk( text, chunkSize, maxChunks ) - local chunks = { "" } - local cs = 0 - local ncs = 1 - for chr in text:gmatch( "." ) do - cs = cs + 1 - if cs > chunkSize or chr == "\n" then - ncs = ncs + 1 - if maxChunks and ncs > maxChunks then - return chunks - end - chunks[ ncs ] = "" - cs = 0 - end - if chr ~= "\n" then - chunks[ ncs ] = chunks[ ncs ] .. chr - end - end - return chunks -end - -function ModUtil.Table.Replace( target, data ) - for k in pairs( target ) do - target[ k ] = data[ k ] - end - for k, v in pairs( data ) do - target[ k ] = v - end -end - -function ModUtil.Table.UnKeyed( tableArg ) - local lk = 0 - for k in pairs( tableArg ) do - if type( k ) ~= "number" then - return false - end - if lk + 1 ~= k then - return false - end - lk = k - end - return true -end - -- Print -ModUtil.Print = ModUtil.SetCall( { }, function ( ... ) +ModUtil.Print = ModUtil.Callable.Set( { }, function ( ... ) print( ... ) if DebugPrint then ModUtil.Print.Debug( ... ) end if io then @@ -622,14 +593,14 @@ function ModUtil.Print.ToFile( file, ... ) file = io.open( file, "a" ) close = true end - file:write( ModUtil.MapVars( tostring, ... ) ) + file:write( ModUtil.Args.Map( tostring, ... ) ) if close then file:close( ) end end function ModUtil.Print.Debug( ... ) - local text = ModUtil.String.Join( "\t", ModUtil.MapVars( tostring, ... ) ):gsub( "\t", " " ) + local text = ModUtil.String.Join( "\t", ModUtil.Args.Map( tostring, ... ) ):gsub( "\t", " " ) for line in text:gmatch( "([^\n]+)" ) do DebugPrint{ Text = line } end @@ -735,85 +706,28 @@ function ModUtil.Array.Slice( state, start, stop, step ) return slice end ---[[ - Safely retrieve the a value from deep inside a table, given - an array of indices into the table. - - For example, if indexArray is { "a", 1, "c" }, then - Table[ "a" ][ 1 ][ "c" ] is returned. If any of Table[ "a" ], - Table[ "a" ][ 1 ], or Table[ "a" ][ 1 ][ "c" ] are nil, then nil - is returned instead. - - Table - the table to retrieve from - indexArray - the list of indices ---]] -function ModUtil.IndexArray.Get( baseTable, indexArray ) - local node = baseTable - for _, key in ipairs( indexArray ) do - if type( node ) ~= "table" then - return nil - end - local nodeType = ModUtil.Nodes.Inverse[ key ] - if nodeType then - node = ModUtil.Nodes.Data[ nodeType ].Get( node ) - else - local call = ModUtil.Callable( key ) - if call then - node = call( node ) - else - node = node[ key ] - end - end - end - return node +function ModUtil.Array.Copy( a ) + return { table.unpack( a ) } end --[[ - Safely set a value deep inside a table, given an array of - indices into the table, and creating any necessary tables - along the way. + Concatenates arrays, in order. - For example, if indexArray is { "a", 1, "c" }, then - Table[ "a" ][ 1 ][ "c" ] = Value once this function returns. - If any of Table[ "a" ] or Table[ "a" ][ 1 ] does not exist, they - are created. - - baseTable - the table to set the value in - indexArray - the list of indices - value - the value to add + a, ... - the arrays --]] -function ModUtil.IndexArray.Set( baseTable, indexArray, value ) - if next( indexArray ) == nil then - return false -- can't set the input argument - end - local n = #indexArray -- change to shallow copy + table.remove later - local node = baseTable - for i = 1, n - 1 do - local key = indexArray[ i ] - if not ModUtil.Nodes.New( node, key ) then return false end - local nodeType = ModUtil.Nodes.Inverse[ key ] - if nodeType then - node = ModUtil.Nodes.Data[ nodeType ].Get( node ) - else - local call = ModUtil.Callable( key ) - if call then - node = call( node ) - else - node = node[ key ] - end - end - end - local key = indexArray[ n ] - local nodeType = ModUtil.Nodes.Inverse[ key ] - if nodeType then - return ModUtil.Nodes.Data[ nodeType ].Set( node, value ) +function ModUtil.Array.Join( a, ... ) + local b = ... + if not b then return ModUtil.Array.Copy( a ) end + local c = { } + local j = 0 + for i, v in ipairs( a ) do + c[ i ] = v + j = i end - local call = ModUtil.Callable( key ) - if call then - return call( node, value ) + for i, v in ipairs( b ) do + c[ i + j ] = v end - node[ key ] = value - return true + return ModUtil.Array.Join( c, ModUtil.Args.Drop( 1, ... ) ) end --[[ @@ -897,38 +811,91 @@ function ModUtil.Table.Merge( inTable, setTable ) end end -function ModUtil.IndexArray.Map( baseTable, indexArray, map, ... ) - ModUtil.IndexArray.Set( baseTable, indexArray, map( ModUtil.IndexArray.Get( baseTable, indexArray ), ... ) ) +-- Index Array Manipulation + +--[[ + Safely retrieve the a value from deep inside a table, given + an array of indices into the table. + + For example, if indexArray is { "a", 1, "c" }, then + Table[ "a" ][ 1 ][ "c" ] is returned. If any of Table[ "a" ], + Table[ "a" ][ 1 ], or Table[ "a" ][ 1 ][ "c" ] are nil, then nil + is returned instead. + + Table - the table to retrieve from + indexArray - the list of indices +--]] +function ModUtil.IndexArray.Get( baseTable, indexArray ) + local node = baseTable + for _, key in ipairs( indexArray ) do + if type( node ) ~= "table" then + return nil + end + local nodeType = ModUtil.Node.Inverse[ key ] + if nodeType then + node = ModUtil.Node.Data[ nodeType ].Get( node ) + else + node = node[ key ] + end + end + return node end --[[ - Concatenates two index arrays, in order. + Safely set a value deep inside a table, given an array of + indices into the table, and creating any necessary tables + along the way. - a, b - the index arrays + For example, if indexArray is { "a", 1, "c" }, then + Table[ "a" ][ 1 ][ "c" ] = Value once this function returns. + If any of Table[ "a" ] or Table[ "a" ][ 1 ] does not exist, they + are created. + + baseTable - the table to set the value in + indexArray - the list of indices + value - the value to add --]] -function ModUtil.IndexArray.Join( a, b ) - local c = { } - local j = 0 - for i, v in ipairs( a ) do - c[ i ] = v - j = i +function ModUtil.IndexArray.Set( baseTable, indexArray, value ) + if next( indexArray ) == nil then + return false -- can't set the input argument end - for i, v in ipairs( b ) do - c[ i + j ] = v + local n = #indexArray -- change to shallow copy + table.remove later + local node = baseTable + for i = 1, n - 1 do + local key = indexArray[ i ] + if not ModUtil.Node.New( node, key ) then return false end + local nodeType = ModUtil.Node.Inverse[ key ] + if nodeType then + node = ModUtil.Node.Data[ nodeType ].Get( node ) + else + node = node[ key ] + end end - return c + local key = indexArray[ n ] + local nodeType = ModUtil.Node.Inverse[ key ] + if nodeType then + return ModUtil.Node.Data[ nodeType ].Set( node, value ) + end + node[ key ] = value + return true +end + +function ModUtil.IndexArray.Map( baseTable, indexArray, map, ... ) + ModUtil.IndexArray.Set( baseTable, indexArray, map( ModUtil.IndexArray.Get( baseTable, indexArray ), ... ) ) end -- Path Manipulation -function ModUtil.Path.Map( path, map, ... ) - ModUtil.IndexArray.Map( _ENV, ModUtil.Path.IndexArray( path ), map, ... ) +function ModUtil.Path.Join( p, ... ) + local q = ... + if not q then return p end + if p == '' then return ModUtil.Path.Join( q, ModUtil.Args.Drop( 1, ... ) ) end + if q == '' then return ModUtil.Path.Join( p, ModUtil.Args.Drop( 1, ... ) ) end + return ModUtil.Path.Join( p .. '.' .. q, ModUtil.Args.Drop( 1, ... ) ) end -function ModUtil.Path.Join( a, b ) - if a == '' then return b end - if b == '' then return a end - return a .. '.' .. b +function ModUtil.Path.Map( path, map, ... ) + ModUtil.IndexArray.Map( _ENV, ModUtil.Path.IndexArray( path ), map, ... ) end --[[ @@ -1188,7 +1155,7 @@ ModUtil.Metatables.UpValues = { end } -ModUtil.UpValues = ModUtil.SetCall( { }, function( func ) +ModUtil.UpValues = ModUtil.Callable.Set( { }, function( func ) if type( func ) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end @@ -1467,7 +1434,7 @@ ModUtil.Metatables.Locals = { end } -ModUtil.Locals = ModUtil.SetCall( { }, function( level ) +ModUtil.Locals = ModUtil.Callable.Set( { }, function( level ) return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) end ) @@ -1639,6 +1606,104 @@ end ModUtil.Metatables.Entangled = { } +ModUtil.Metatables.Entangled.Union = { + + __index = function( self, key ) + local value + for t in pairs( getObjectData( self, "Members" ) ) do + value = t[ key ] + if value ~= nil then + return value + end + end + return getObjectData( self, "Reserve" )[ key ] + end, + __newindex = function( self, key, value ) + if value ~= nil then + getObjectData( self, "Keys" )[ key ] = true + else + getObjectData( self, "Keys" )[ key ] = nil + end + local hit = false + for t in pairs( getObjectData( self, "Members" ) ) do + if t[ key ] ~= nil then + t[ key ] = value + hit = true + end + end + if hit then + getObjectData( self, "Reserve" )[ key ] = nil + else + getObjectData( self, "Reserve" )[ key ] = value + end + end, + __len = function( self ) + local m = #getObjectData( self, "Reserve" ) + local n + for t in pairs( getObjectData( self, "Members" ) ) do + n = #t + if n > m then + m = n + end + end + return m + end, + __next = function( self, key ) + key = next( getObjectData( self, "Keys" ), key ) + return key, self[ key ] + end, + __inext = function( self, idx ) + idx = ( idx or 0 ) + 1 + local val = self[ idx ] + if val == nil then return end + return idx, val + end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return qrawipairs( self ) + end + +} + +ModUtil.Entangled.Union = ModUtil.Callable.Set( { }, function( ... ) + local keys, members = { }, ToLookup{ ... } + local union = { Reserve = { }, Keys = keys, Members = members } + for t in pairs( members ) do + for k in pairs( t ) do + keys[ k ] = true + end + end + return ModUtil.ObjectDataProxy( union, ModUtil.Metatables.Entangled.Union ) +end ) + +function ModUtil.Entangled.Union.Add( union, ... ) + local members = getObjectData( union, "Members" ) + local keys = getObjectData( union, "Keys" ) + local reserve = getObjectData( union, "Reserve" ) + for t in pairs( ToLookup{ ... } ) do + members[ t ] = true + for k in pairs( t ) do + keys[ k ] = true + reserve[ k ] = nil + end + end +end + +function ModUtil.Entangled.Union.Sub( union, ... ) + local members = getObjectData( union, "Members" ) + local keys = getObjectData( union, "Keys" ) + for t in pairs( ToLookup{ ... } ) do + members[ t ] = nil + end + for k in pairs( keys ) do + if union[ k ] == nil then + keys[ k ] = nil + end + end +end + ModUtil.Metatables.Entangled.Map = { Data = { @@ -1802,7 +1867,7 @@ ModUtil.Metatables.Entangled.Map = { } -ModUtil.Entangled.Map = ModUtil.SetCall( { Unique = { } }, function( ) +ModUtil.Entangled.Map = ModUtil.Callable.Set( { Unique = { } }, function( ) local data, preImage = { }, { } data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) @@ -1810,7 +1875,7 @@ ModUtil.Entangled.Map = ModUtil.SetCall( { Unique = { } }, function( ) return { Data = data, Index = preImage, PreImage = preImage } end ) -ModUtil.Entangled.Map.Unique = ModUtil.SetCall( { }, function( ) +ModUtil.Entangled.Map.Unique = ModUtil.Callable.Set( { }, function( ) local data, inverse = { }, { } data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) @@ -1862,7 +1927,7 @@ ModUtil.Metatables.Context = { end } -ModUtil.Context = ModUtil.SetCall( { }, function( callContextProcessor, postCall ) +ModUtil.Context = ModUtil.Callable.Set( { }, function( callContextProcessor, postCall ) return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) end ) @@ -1875,7 +1940,7 @@ ModUtil.Context.Data = ModUtil.Context( function( info ) end ) ModUtil.Context.Meta = ModUtil.Context( function( info ) - local tbl = ModUtil.Nodes.Data.Metatable.New( info.arg ) + local tbl = ModUtil.Node.Data.Metatable.New( info.arg ) info.env = setmetatable( { }, { __index = function( _, key ) return tbl[ key ] or info.penv[ key ] end, __newindex = tbl @@ -1884,8 +1949,8 @@ end ) ModUtil.Context.Env = ModUtil.Context( function( info ) local func = info.arg - local fenv = _G.newfenv( func ) - _G.setfenv( func, fenv ) + local fenv = ModUtil.Node.Data.Env.New( func ) + ModUtil.Node.Data.Env.Set( func, fenv ) info.env = setmetatable( { }, { __index = function( _, key ) return fenv[ key ] or info.penv[ key ] end, __newindex = fenv @@ -1927,17 +1992,15 @@ function ModUtil.Context.Wrap( func, context, mod ) return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( base, context, ... ) end, mod ) end --- Special traversal nodes +-- Special Traversal Nodes -ModUtil.Nodes = ModUtil.Entangled.Map.Unique( ) +ModUtil.Node = ModUtil.Entangled.Map.Unique( ) -function ModUtil.Nodes.New( parent, key ) - local nodeType = ModUtil.Nodes.Inverse[ key ] +function ModUtil.Node.New( parent, key ) + local nodeType = ModUtil.Node.Inverse[ key ] if nodeType then - return ModUtil.Nodes.Data[ nodeType ].New( parent ) + return ModUtil.Node.Data[ nodeType ].New( parent ) end - local call = ModUtil.Callable( key ) - if call then return call( parent ) end local tbl = parent[ key ] if type( tbl ) ~= "table" then tbl = { } @@ -1946,7 +2009,61 @@ function ModUtil.Nodes.New( parent, key ) return tbl end -ModUtil.Nodes.Data.Metatable = { +local fenvData = setmetatable( { }, { __mode = "k" } ) + +ModUtil.Node.Data.Env = { + New = function( func ) + local fenv = _G.getfenv( func ) + if not fenv then + fenv = { } + fenvData[ func ] = fenv + end + return fenv + end, + Get = function( func ) + local fenv = fenvData[ func ] + if not fenv then + fenv = getfenv( func ) + if fenv == _ENV then + fenv = nil + end + end + return fenv + end, + Set = function( func, fenv ) + + fenvData[ func ] = fenv + + setfenv( func, setmetatable( { }, { + __index = function( _, key ) + local val + local env = threadEnvironments[ coroutine.running( ) ] + if env then + val = env[ key ] + end + if val ~= nil then return val end + val = fenv[ key ] + if val ~= nil then return val end + return _G[ key ] + end, + __newindex = function( _, key, val ) + local env = threadEnvironments[ coroutine.running( ) ] + if env and env[ key ] ~= nil then + env[ key ] = val + return + end + if fenv[ key ] ~= nil then + fenv[ key ] = val + return + end + _G[ key ] = val + end + } ) ) + + end +} + +ModUtil.Node.Data.Metatable = { New = function( obj ) local meta = getmetatable( obj ) if meta == nil then @@ -1964,23 +2081,22 @@ ModUtil.Nodes.Data.Metatable = { end } -ModUtil.Nodes.Data.Call = { +ModUtil.Node.Data.Call = { New = function( obj ) - local call = ModUtil.Callable( obj ) + local _, call = ModUtil.Callable.Get( obj ) return call or error( "node new rejected, new call nodes are not meaningfully mutable.", 2 ) end, Get = function( obj ) - local call = ModUtil.Callable( obj ) + local _, call = ModUtil.Callable.Get( obj ) return call end, Set = function( obj, value ) - local _, meta, parent = ModUtil.Callable( obj ) - rawset( getmetatable( setmetatable( parent, meta or { } ) ), "__call", value ) + ModUtil.Callable.Set( ModUtil.Callable.Get( obj ), value ) return true end } -ModUtil.Nodes.Data.UpValues = { +ModUtil.Node.Data.UpValues = { New = function( obj ) return ModUtil.UpValues( obj ) end, @@ -2017,7 +2133,7 @@ local function wrapDecorator( wrap ) return function( base ) return function( ... ) return wrap( base, ... ) end end end -ModUtil.Decorate = ModUtil.SetCall( { }, function( base, func, mod ) +ModUtil.Decorate = ModUtil.Callable.Set( { }, function( base, func, mod ) local out = func( base ) decorators[ out ] = { Base = base, Func = func, Mod = mod } return out @@ -2119,7 +2235,7 @@ function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) end -ModUtil.IndexArray.Decorate = ModUtil.SetCall( { }, function( baseTable, indexArray, func, mod ) +ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( baseTable, indexArray, func, mod ) ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -2171,7 +2287,7 @@ function ModUtil.Path.Context.Env( path, context ) ModUtil.Path.Map( path, ModUtil.Context.Env, context ) end -ModUtil.Path.Decorate = ModUtil.SetCall( { }, function( path, func, mod ) +ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( path, func, mod ) ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) @@ -2205,6 +2321,8 @@ end -- Internal access +ModUtil.Internal = ModUtil.Entangled.Union( ) + do local ups = ModUtil.UpValues( function( ) return _G, @@ -2215,9 +2333,10 @@ do stackLevelFunction, stackLevelInterface, stackLevelProperty, passByValueTypes, callableCandidateTypes, excludedFieldNames end ) - setmetatable( ModUtil.Internal, { __index = ups, __newindex = ups } ) + ModUtil.Entangled.Union.Add( ModUtil.Internal, ups ) end -- Final Actions -replaceGlobalEnvironment( ) \ No newline at end of file +replaceGlobalEnvironment( ) + From 5afacf3e4704077e558aebc186799189a7a80be4 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Thu, 19 Aug 2021 03:16:46 +1000 Subject: [PATCH 24/32] update compat with renames --- ModUtil.Compat.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index 6e967f9..5045cae 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -43,7 +43,7 @@ ModUtil.Compat.PrintVariables = ModUtil.Print.Variables ModUtil.Compat.Slice = ModUtil.Array.Slice -ModUtil.Compat.NewTable = ModUtil.Table.New +ModUtil.Compat.NewTable = ModUtil.Node.New ModUtil.Compat.SafeGet = ModUtil.IndexArray.Get @@ -53,7 +53,7 @@ ModUtil.Compat.MapNilTable = ModUtil.Table.NilMerge ModUtil.Compat.MapSetTable = ModUtil.Table.Merge -ModUtil.Compat.JoinIndexArrays = ModUtil.IndexArray.Join +ModUtil.Compat.JoinIndexArrays = ModUtil.Array.Join ModUtil.Compat.PathToIndexArray = ModUtil.Path.IndexArray From ce704d13b035f5c6643adc6b5a4786eae36a6d2d Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Thu, 19 Aug 2021 03:49:56 +1000 Subject: [PATCH 25/32] decoration suite added to the callable target --- ModUtil.lua | 113 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 89 insertions(+), 24 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index b574289..330db23 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -329,19 +329,32 @@ function ModUtil.Callable.Set( o, f ) function m.__call( _, ... ) return f( ... ) end - return setmetatable( o, m ) + return setmetatable( o, m ), f end -ModUtil.Callable.Set( ModUtil.Callable, function ( obj ) +function ModUtil.Callable.GetFunc( o ) local meta while obj do local t = type( obj ) - if t == "function" then return true end - if not callableCandidateTypes[ t ] then return false end + if t == "function" then return obj end + if not callableCandidateTypes[ t ] then return end meta = getmetatable( obj ) if not meta then break end obj = rawget( meta, "__call" ) end +end + +function ModUtil.Callable.Map( o, f, ... ) + local pobj, obj = ModUtil.Callable.Get( o ) + if not pobj then + return f( obj, ... ), false + end + ModUtil.Callable.Set( pobj, f( obj, ... ) ) + return o, true +end + +ModUtil.Callable.Set( ModUtil.Callable, function ( obj ) + return ModUtil.Callable.GetFunc( obj ) ~= nil end ) -- Data Misc @@ -2216,47 +2229,99 @@ end --- +ModUtil.Callable.Context = { } + +function ModUtil.Callable.Wrap( obj, wrap, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Wrap, wrap, mod ) +end + +function ModUtil.Callable.Context.Wrap( obj, context, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Context.Wrap, context, mod ) +end + +function ModUtil.Callable.Context.StaticWrap( obj, context, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Context.StaticWrap, context, mod ) +end + +function ModUtil.Callable.Context.Env( obj, context ) + return ModUtil.Callable.Map( obj, ModUtil.Context.Env, context ) +end + +ModUtil.Callable.Decorate = ModUtil.Callable.Set( { }, function( obj, func, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate, func, mod ) +end ) + +function ModUtil.Callable.Decorate.Undo( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate.Undo ) +end + +function ModUtil.Callable.Decorate.Redo( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate.Redo ) +end + +function ModUtil.Callable.Override( obj, value, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Override, value, mod ) +end + +function ModUtil.Callable.Overriden( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Overriden ) +end + +function ModUtil.Callable.Original( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Original ) +end + +function ModUtil.Callable.ReferFunction( obj ) + return ModUtil.ReferFunction( ModUtil.Callable.GetFunc, obj ) +end + +function ModUtil.Callable.ReferTable( obj ) + return ModUtil.ReferTable( ModUtil.Callable.Get, obj ) +end + +--- + ModUtil.IndexArray.Context = { } function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrap, mod ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrap, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrap, mod ) end function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) end function ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, context, mod ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.StaticWrap, context, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.StaticWrap, context, mod ) end function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context ) end ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( baseTable, indexArray, func, mod ) - ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) + return ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) function ModUtil.IndexArray.Decorate.Undo( baseTable, indexArray ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Undo ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Undo ) end function ModUtil.IndexArray.Decorate.Redo( baseTable, indexArray ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Redo ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Redo ) end function ModUtil.IndexArray.Override( baseTable, indexArray, value, mod ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Override, value, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Override, value, mod ) end function ModUtil.IndexArray.Overriden( baseTable, indexArray ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Overriden ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Overriden ) end function ModUtil.IndexArray.Original( baseTable, indexArray ) - ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Original ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Original ) end function ModUtil.IndexArray.ReferFunction( baseTable, indexArray ) @@ -2272,43 +2337,43 @@ end ModUtil.Path.Context = { } function ModUtil.Path.Wrap( path, wrap, mod ) - ModUtil.Path.Map( path, ModUtil.Wrap, wrap, mod ) + return ModUtil.Path.Map( path, ModUtil.Wrap, wrap, mod ) end function ModUtil.Path.Context.Wrap( path, context, mod ) - ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) + return ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) end function ModUtil.Path.Context.StaticWrap( path, context, mod ) - ModUtil.Path.Map( path, ModUtil.Context.StaticWrap, context, mod ) + return ModUtil.Path.Map( path, ModUtil.Context.StaticWrap, context, mod ) end function ModUtil.Path.Context.Env( path, context ) - ModUtil.Path.Map( path, ModUtil.Context.Env, context ) + return ModUtil.Path.Map( path, ModUtil.Context.Env, context ) end ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( path, func, mod ) - ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) + return ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) function ModUtil.Path.Decorate.Undo( path ) - ModUtil.Path.Map( path, ModUtil.Decorate.Undo ) + return ModUtil.Path.Map( path, ModUtil.Decorate.Undo ) end function ModUtil.Path.Decorate.Redo( path ) - ModUtil.Path.Map( path, ModUtil.Decorate.Redo ) + return ModUtil.Path.Map( path, ModUtil.Decorate.Redo ) end function ModUtil.Path.Override( path, value, mod ) - ModUtil.Path.Map( path, ModUtil.Override, value, mod ) + return ModUtil.Path.Map( path, ModUtil.Override, value, mod ) end function ModUtil.Path.Overriden( path ) - ModUtil.Path.Map( path, ModUtil.Overriden ) + return ModUtil.Path.Map( path, ModUtil.Overriden ) end function ModUtil.Path.Original( path ) - ModUtil.Path.Map( path, ModUtil.Original ) + return ModUtil.Path.Map( path, ModUtil.Original ) end function ModUtil.Path.ReferFunction( path ) From 0face86c89209a200a48b18ff579bebc9be534f3 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Thu, 19 Aug 2021 04:15:11 +1000 Subject: [PATCH 26/32] split off some uninteresting definitions --- ModUtil.Extra.lua | 162 +++++++++++++++++++++++++++++++++++++++++++++ ModUtil.lua | 164 +--------------------------------------------- modfile.txt | 1 + 3 files changed, 166 insertions(+), 161 deletions(-) create mode 100644 ModUtil.Extra.lua diff --git a/ModUtil.Extra.lua b/ModUtil.Extra.lua new file mode 100644 index 0000000..3163669 --- /dev/null +++ b/ModUtil.Extra.lua @@ -0,0 +1,162 @@ +ModUtil.Callable.Context = { } + +function ModUtil.Callable.Wrap( obj, wrap, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Wrap, wrap, mod ) +end + +function ModUtil.Callable.Context.Wrap( obj, context, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Context.Wrap, context, mod ) +end + +function ModUtil.Callable.Context.StaticWrap( obj, context, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Context.StaticWrap, context, mod ) +end + +function ModUtil.Callable.Context.Env( obj, context ) + return ModUtil.Callable.Map( obj, ModUtil.Context.Env, context ) +end + +ModUtil.Callable.Decorate = ModUtil.Callable.Set( { }, function( obj, func, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate, func, mod ) +end ) + +function ModUtil.Callable.Decorate.Undo( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate.Undo ) +end + +function ModUtil.Callable.Decorate.Redo( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate.Redo ) +end + +function ModUtil.Callable.Override( obj, value, mod ) + return ModUtil.Callable.Map( obj, ModUtil.Override, value, mod ) +end + +function ModUtil.Callable.Overriden( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Overriden ) +end + +function ModUtil.Callable.Original( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Original ) +end + +function ModUtil.Callable.ReferFunction( obj ) + return ModUtil.ReferFunction( ModUtil.Callable.GetFunc, obj ) +end + +function ModUtil.Callable.ReferTable( obj ) + return ModUtil.ReferTable( ModUtil.Callable.Get, obj ) +end + +--- + +ModUtil.IndexArray.Context = { } + +function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrap, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Wrap, wrap, mod ) +end + +function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Context.Wrap, context, mod ) +end + +function ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, context, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Context.StaticWrap, context, mod ) +end + +function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Context.Wrap, context ) +end + + +ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( baseTable, indexArray, func, mod ) + return ModUtil.Path.Map( baseTable, indexArray, ModUtil.Callable.Decorate, func, mod ) +end ) + +function ModUtil.IndexArray.Decorate.Undo( baseTable, indexArray ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Undo ) +end + +function ModUtil.IndexArray.Decorate.Redo( baseTable, indexArray ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Redo ) +end + +function ModUtil.IndexArray.Override( baseTable, indexArray, value, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Override, value, mod ) +end + +function ModUtil.IndexArray.Overriden( baseTable, indexArray ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Overriden ) +end + +function ModUtil.IndexArray.Original( baseTable, indexArray ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Original ) +end + +function ModUtil.IndexArray.ReferFunction( baseTable, indexArray ) + return ModUtil.ReferFunction( function( ... ) + ModUtil.Callable.GetFunc( ModUtil.IndexArray.Get( ... ) ) + end, baseTable, indexArray ) +end + +function ModUtil.IndexArray.ReferTable( baseTable, indexArray ) + return ModUtil.ReferTable( function( ... ) + ModUtil.Callable.Get( ModUtil.IndexArray.Get( ... ) ) + end, baseTable, indexArray ) +end + +--- + +ModUtil.Path.Context = { } + +function ModUtil.Path.Wrap( path, wrap, mod ) + return ModUtil.Path.Map( path, ModUtil.Callable.Wrap, wrap, mod ) +end + +function ModUtil.Path.Context.Wrap( path, context, mod ) + return ModUtil.Path.Map( path, ModUtil.Callable.Context.Wrap, context, mod ) +end + +function ModUtil.Path.Context.StaticWrap( path, context, mod ) + return ModUtil.Path.Map( path, ModUtil.Callable.Context.StaticWrap, context, mod ) +end + +function ModUtil.Path.Context.Env( path, context ) + return ModUtil.Path.Map( path, ModUtil.Callable.Context.Env, context ) +end + +ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( path, func, mod ) + return ModUtil.Path.Map( path, ModUtil.Callable.Decorate, func, mod ) +end ) + +function ModUtil.Path.Decorate.Undo( path ) + return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Undo ) +end + +function ModUtil.Path.Decorate.Redo( path ) + return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Redo ) +end + +function ModUtil.Path.Override( path, value, mod ) + return ModUtil.Path.Map( path, ModUtil.Callable.Override, value, mod ) +end + +function ModUtil.Path.Overriden( path ) + return ModUtil.Path.Map( path, ModUtil.Callable.Overriden ) +end + +function ModUtil.Path.Original( path ) + return ModUtil.Path.Map( path, ModUtil.Callable.Original ) +end + +function ModUtil.Path.ReferFunction( path ) + return ModUtil.ReferFunction( function( ... ) + ModUtil.Callable.GetFunc( ModUtil.Path.Get( ... ) ) + end, path ) +end + +function ModUtil.Path.ReferTable( path ) + return ModUtil.ReferTable( function( ... ) + ModUtil.Callable.Get( ModUtil.Path.Get( ... ) ) + end, path ) +end \ No newline at end of file diff --git a/ModUtil.lua b/ModUtil.lua index 330db23..b24cacc 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -894,7 +894,7 @@ function ModUtil.IndexArray.Set( baseTable, indexArray, value ) end function ModUtil.IndexArray.Map( baseTable, indexArray, map, ... ) - ModUtil.IndexArray.Set( baseTable, indexArray, map( ModUtil.IndexArray.Get( baseTable, indexArray ), ... ) ) + return ModUtil.IndexArray.Set( baseTable, indexArray, map( ModUtil.IndexArray.Get( baseTable, indexArray ), ... ) ) end -- Path Manipulation @@ -908,7 +908,7 @@ function ModUtil.Path.Join( p, ... ) end function ModUtil.Path.Map( path, map, ... ) - ModUtil.IndexArray.Map( _ENV, ModUtil.Path.IndexArray( path ), map, ... ) + return ModUtil.IndexArray.Map( _ENV, ModUtil.Path.IndexArray( path ), map, ... ) end --[[ @@ -2227,163 +2227,6 @@ function ModUtil.ReferTable( obtainer, ... ) return ModUtil.ObjectDataProxy( { obtain = obtain }, ModUtil.Metatables.ReferTable ) end ---- - -ModUtil.Callable.Context = { } - -function ModUtil.Callable.Wrap( obj, wrap, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Wrap, wrap, mod ) -end - -function ModUtil.Callable.Context.Wrap( obj, context, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Context.Wrap, context, mod ) -end - -function ModUtil.Callable.Context.StaticWrap( obj, context, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Context.StaticWrap, context, mod ) -end - -function ModUtil.Callable.Context.Env( obj, context ) - return ModUtil.Callable.Map( obj, ModUtil.Context.Env, context ) -end - -ModUtil.Callable.Decorate = ModUtil.Callable.Set( { }, function( obj, func, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate, func, mod ) -end ) - -function ModUtil.Callable.Decorate.Undo( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate.Undo ) -end - -function ModUtil.Callable.Decorate.Redo( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate.Redo ) -end - -function ModUtil.Callable.Override( obj, value, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Override, value, mod ) -end - -function ModUtil.Callable.Overriden( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Overriden ) -end - -function ModUtil.Callable.Original( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Original ) -end - -function ModUtil.Callable.ReferFunction( obj ) - return ModUtil.ReferFunction( ModUtil.Callable.GetFunc, obj ) -end - -function ModUtil.Callable.ReferTable( obj ) - return ModUtil.ReferTable( ModUtil.Callable.Get, obj ) -end - ---- - -ModUtil.IndexArray.Context = { } - -function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrap, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrap, mod ) -end - -function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) -end - -function ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, context, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.StaticWrap, context, mod ) -end - -function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context ) -end - - -ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( baseTable, indexArray, func, mod ) - return ModUtil.Path.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) -end ) - -function ModUtil.IndexArray.Decorate.Undo( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Undo ) -end - -function ModUtil.IndexArray.Decorate.Redo( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Redo ) -end - -function ModUtil.IndexArray.Override( baseTable, indexArray, value, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Override, value, mod ) -end - -function ModUtil.IndexArray.Overriden( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Overriden ) -end - -function ModUtil.IndexArray.Original( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Original ) -end - -function ModUtil.IndexArray.ReferFunction( baseTable, indexArray ) - return ModUtil.ReferFunction( ModUtil.IndexArray.Get, baseTable, indexArray ) -end - -function ModUtil.IndexArray.ReferTable( baseTable, indexArray ) - return ModUtil.ReferTable( ModUtil.IndexArray.Get, baseTable, indexArray ) -end - ---- - -ModUtil.Path.Context = { } - -function ModUtil.Path.Wrap( path, wrap, mod ) - return ModUtil.Path.Map( path, ModUtil.Wrap, wrap, mod ) -end - -function ModUtil.Path.Context.Wrap( path, context, mod ) - return ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) -end - -function ModUtil.Path.Context.StaticWrap( path, context, mod ) - return ModUtil.Path.Map( path, ModUtil.Context.StaticWrap, context, mod ) -end - -function ModUtil.Path.Context.Env( path, context ) - return ModUtil.Path.Map( path, ModUtil.Context.Env, context ) -end - -ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( path, func, mod ) - return ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) -end ) - -function ModUtil.Path.Decorate.Undo( path ) - return ModUtil.Path.Map( path, ModUtil.Decorate.Undo ) -end - -function ModUtil.Path.Decorate.Redo( path ) - return ModUtil.Path.Map( path, ModUtil.Decorate.Redo ) -end - -function ModUtil.Path.Override( path, value, mod ) - return ModUtil.Path.Map( path, ModUtil.Override, value, mod ) -end - -function ModUtil.Path.Overriden( path ) - return ModUtil.Path.Map( path, ModUtil.Overriden ) -end - -function ModUtil.Path.Original( path ) - return ModUtil.Path.Map( path, ModUtil.Original ) -end - -function ModUtil.Path.ReferFunction( path ) - return ModUtil.ReferFunction( ModUtil.Path.Get, path ) -end - -function ModUtil.Path.ReferTable( path ) - return ModUtil.ReferTable( ModUtil.Path.Get, path ) -end - -- Internal access ModUtil.Internal = ModUtil.Entangled.Union( ) @@ -2403,5 +2246,4 @@ end -- Final Actions -replaceGlobalEnvironment( ) - +replaceGlobalEnvironment( ) \ No newline at end of file diff --git a/modfile.txt b/modfile.txt index 4a55702..6dfa0cf 100644 --- a/modfile.txt +++ b/modfile.txt @@ -3,6 +3,7 @@ Load Priority 0 To "Scripts/Main.lua" Top Import "ModUtil.lua" + Import "ModUtil.Extra.lua" Import "ModUtil.Main.lua" Import "ModUtil.Compat.lua" To "Scripts/RoomManager.lua" From f7081d48c0a67e03bf256f3de9bebda40bd9c0ae Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Sat, 21 Aug 2021 17:16:25 +1000 Subject: [PATCH 27/32] attempt fixing Content.Env (incomplete) --- ModUtil.Compat.lua | 10 +- ModUtil.lua | 281 ++++++++++++++++++++++++++++----------------- 2 files changed, 180 insertions(+), 111 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index 5045cae..5645093 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -19,9 +19,9 @@ ModUtil.Compat.ToShallowString = ModUtil.ToString.Shallow ModUtil.Compat.ToDeepString = ModUtil.ToString.Deep -ModUtil.Compat.ToDeepNoNamespacesString = ModUtil.ToString.DeepNoNamespaces +ModUtil.Compat.ToDeepNoNamespacesString = ModUtil.ToString.Deep.NoNamespaces -ModUtil.Compat.ToDeepNamespacesString = ModUtil.ToString.DeepNamespaces +ModUtil.Compat.ToDeepNamespacesString = ModUtil.ToString.Deep.Namespaces ModUtil.Compat.JoinStrings = ModUtil.String.Join @@ -81,14 +81,16 @@ ModUtil.Compat.GetOriginalValue = ModUtil.IndexArray.Original ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original +ModUtil.Compat.RawInterface = ModUtil.Raw + function ModUtil.Compat.WrapWithinFunction( baseTable, indexArray, envIndexArray, wrapFunc, mod ) - ModUtil.IndexArray.Context.Env( baseTable, indexArray, function( ) + ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, function( ) ModUtil.IndexArray.Wrap( _G, envIndexArray, wrapFunc, mod ) end ) end function ModUtil.Compat.WrapBaseWithinFunction( funcPath, baseFuncPath, wrapFunc, mod ) - ModUtil.Path.Context.Env( baseFuncPath, function( ) + ModUtil.Path.Context.Wrap( baseFuncPath, function( ) ModUtil.Path.Wrap( funcPath, wrapFunc, mod ) end ) end diff --git a/ModUtil.lua b/ModUtil.lua index b24cacc..753b7a4 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -203,9 +203,9 @@ local rawpairs, rawipairs, qrawpairs, qrawipairs, tostring, getfenv, setfenv --[[ - local version of ToLookup as to not depend on Main.lua + local version of toLookup as to not depend on Main.lua ]] -local function ToLookup( tableArg ) +local function toLookup( tableArg ) local lookup = { } for _, value in pairs( tableArg ) do lookup[ value ] = true @@ -215,9 +215,9 @@ end -- Type/Syntax Constants -local passByValueTypes = ToLookup{ "number", "boolean", "nil" } -local callableCandidateTypes = ToLookup{ "function", "table", "userdata" } -- string excluded because their references are managed -local excludedFieldNames = ToLookup{ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" } +local passByValueTypes = toLookup{ "number", "boolean", "nil" } +local callableCandidateTypes = toLookup{ "function", "table", "userdata" } -- string excluded because their references are managed +local excludedFieldNames = toLookup{ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" } -- Environment Manipulation @@ -261,6 +261,7 @@ local function replaceGlobalEnvironment( ) if v == _G then reg[ i ] = __G end end ModUtil.Identifiers.Inverse._ENV = __G + rawset( __G, "_DEBUG_G", _G ) end -- Managed Object Data @@ -277,34 +278,60 @@ local function getObjectData( obj, key ) return objectData[ obj ][ key ] end -function ModUtil.ObjectDataProxy( data, meta ) - return setmetatable( newObjectData( data ), meta ) +ModUtil.Metatables.Proxy = { + __index = function( self, key ) + return objectData[ self ][ key ] + end, + __newindex = function( self, key, value ) + objectData[ self ][ key ] = value + end, + __len = function( self, ...) + return #objectdata( self ) + end, + __next = function( self, ... ) + return next( objectData[ self ], ... ) + end, + __inext = function( self, ... ) + return inext( objectData[ self ], ... ) + end, + __pairs = function( self, ... ) + return pairs( objectData[ self ], ... ) + end, + __ipairs = function( self, ... ) + return ipairs( objectData[ self ], ... ) + end +} + +function ModUtil.Proxy( data, meta ) + return setmetatable( newObjectData( data ), meta or ModUtil.Metatables.Proxy ) end -function ModUtil.RawInterface( obj ) - return setmetatable( { }, { - __index = function( _, ... ) - return rawget( obj, ... ) - end, - __newindex = function( _, ... ) - return rawset( obj, ... ) - end, - __len = function( _, ...) - return rawlen( obj, ... ) - end, - __next = function( _, ... ) - return rawnext( obj, ... ) - end, - __inext = function( _, ... ) - return rawinext( obj, ... ) - end, - __pairs = function( _, ... ) - return rawpairs( obj, ... ) - end, - __ipairs = function( _, ... ) - return rawipairs( obj, ... ) - end - } ) +ModUtil.Metatables.Raw = { + __index = function( self, ... ) + return rawget( getObjectData( self, "data" ), ... ) + end, + __newindex = function( self, ... ) + return rawset( getObjectData( self, "data" ), ... ) + end, + __len = function( self, ...) + return rawlen( getObjectData( self, "data" ), ... ) + end, + __next = function( self, ... ) + return rawnext( getObjectData( self, "data" ), ... ) + end, + __inext = function( self, ... ) + return rawinext( getObjectData( self, "data" ), ... ) + end, + __pairs = function( self, ... ) + return rawpairs( getObjectData( self, "data" ), ... ) + end, + __ipairs = function( self, ... ) + return rawipairs( getObjectData( self, "data" ), ... ) + end +} + +function ModUtil.Raw( obj ) + return ModUtil.Proxy( { data = obj }, ModUtil.Metatables.Raw ) end -- Operations on Callables @@ -521,7 +548,7 @@ function ModUtil.ToString.Shallow( o ) end end -function ModUtil.ToString.Deep( o, seen ) +ModUtil.ToString.Deep = ModUtil.Callable.Set( { }, function( o, seen ) seen = seen or { } if type( o ) == "table" and not seen[ o ] then seen[ o ] = true @@ -537,9 +564,14 @@ function ModUtil.ToString.Deep( o, seen ) else return ModUtil.ToString.Value( o ) end +end ) + +local function isNamespace( obj ) + return obj == _G or obj == _ENV or obj == objectData or ModUtil.Mods.Inverse[ obj ] + or ( getmetatable( obj ) == ModUtil.Metatables.Raw and isNamespace( getObjectData( obj, "data" ) ) ) end -function ModUtil.ToString.DeepNoNamespaces( o, seen ) +function ModUtil.ToString.Deep.NoNamespaces( o, seen ) local first = false if not seen then first = true @@ -549,10 +581,10 @@ function ModUtil.ToString.DeepNoNamespaces( o, seen ) seen[ o ] = true local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do - if v ~= _G and v ~= _ENV and not ModUtil.Mods.Inverse[ v ] then + if not isNamespace( v ) then table.insert( out, ModUtil.ToString.Key( k ) ) table.insert( out, ' = ' ) - table.insert( out, ModUtil.ToString.DeepNoNamespaces( v, seen ) ) + table.insert( out, ModUtil.ToString.Deep.NoNamespaces( v, seen ) ) table.insert( out , ", " ) end end @@ -563,7 +595,7 @@ function ModUtil.ToString.DeepNoNamespaces( o, seen ) end end -function ModUtil.ToString.DeepNamespaces( o, seen ) +function ModUtil.ToString.Deep.Namespaces( o, seen ) local first = false if not seen then first = true @@ -573,10 +605,10 @@ function ModUtil.ToString.DeepNamespaces( o, seen ) seen[ o ] = true local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do - if v == _G or v == _ENV or ModUtil.Mods.Inverse[ v ] then + if isNamespace( v ) then table.insert( out, ModUtil.ToString.Key( k ) ) table.insert( out, ' = ' ) - table.insert( out, ModUtil.ToString.DeepNamespaces( v, seen ) ) + table.insert( out, ModUtil.ToString.Deep.Namespaces( v, seen ) ) table.insert( out , ", " ) end end @@ -658,11 +690,11 @@ function ModUtil.Print.Namespaces( level ) level = level or 1 local text ModUtil.Print("Namespaces:") - text = ModUtil.ToString.DeepNamespaces( ModUtil.Locals( level + 1 ) ) + text = ModUtil.ToString.Deep.Namespaces( ModUtil.Locals( level + 1 ) ) ModUtil.Print( "\t" .. "Locals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - text = ModUtil.ToString.DeepNamespaces( ModUtil.UpValues( level + 1 ) ) + text = ModUtil.ToString.Deep.Namespaces( ModUtil.UpValues( level + 1 ) ) ModUtil.Print( "\t" .. "UpValues:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - text = ModUtil.ToString.DeepNamespaces( _ENV ) + text = ModUtil.ToString.Deep.Namespaces( _ENV ) ModUtil.Print( "\t" .. "Globals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) end @@ -670,11 +702,11 @@ function ModUtil.Print.Variables( level ) level = level or 1 local text ModUtil.Print("Variables:") - text = ModUtil.ToString.DeepNoNamespaces( ModUtil.Locals( level + 1 ) ) + text = ModUtil.ToString.Deep.NoNamespaces( ModUtil.Locals( level + 1 ) ) ModUtil.Print( "\t" .. "Locals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - text = ModUtil.ToString.DeepNoNamespaces( ModUtil.UpValues( level + 1 ) ) + text = ModUtil.ToString.Deep.NoNamespaces( ModUtil.UpValues( level + 1 ) ) ModUtil.Print( "\t" .. "UpValues:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) - text = ModUtil.ToString.DeepNoNamespaces( _ENV ) + text = ModUtil.ToString.Deep.NoNamespaces( _ENV ) ModUtil.Print( "\t" .. "Globals:" .. "\t" .. text:sub( 1 + text:find( ">" ) ) ) end @@ -743,6 +775,38 @@ function ModUtil.Array.Join( a, ... ) return ModUtil.Array.Join( c, ModUtil.Args.Drop( 1, ... ) ) end +function ModUtil.Table.Copy( t ) + c = { } + for k, v in pairs( t ) do + c[ k ] = v + end + return c +end + +function ModUtil.Table.Clear( t ) + for k in pairs( t ) do + t[ k ] = nil + end + return t +end + +function ModUtil.Table.Transpose( t ) + local i = { } + for k, v in pairs( t ) do + i[ v ] = k + end + return i +end + +function ModUtil.Table.Flip( t ) + local i = ModUtil.Table.Transpose( t ) + ModUtil.Table.Clear( t ) + for k, v in pairs( i ) do + t[ k ] = v + end + return t +end + --[[ Set all the values in inTable corresponding to keys in nilTable to nil. @@ -784,6 +848,7 @@ function ModUtil.Table.NilMerge( inTable, nilTable ) inTable[ nilKey ] = nil end end + return inTable end --[[ @@ -822,6 +887,7 @@ function ModUtil.Table.Merge( inTable, setTable ) inTable[ setKey ] = setVal end end + return inTable end -- Index Array Manipulation @@ -1079,7 +1145,7 @@ function ModUtil.StackLevel( level ) end size = size - level - 1 if size > 0 then - return ModUtil.ObjectDataProxy( { level = level, size = size, thread = thread }, ModUtil.Metatables.StackLevel ) + return ModUtil.Proxy( { level = level, size = size, thread = thread }, ModUtil.Metatables.StackLevel ) end end @@ -1106,11 +1172,11 @@ ModUtil.Metatables.StackLevels.__ipairs = ModUtil.Metatables.StackLevels.__pairs ModUtil.Metatables.StackLevels.__inext = ModUtil.Metatables.StackLevels.__next function ModUtil.StackLevels( level ) - return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( level or 0 ) }, ModUtil.Metatables.StackLevels ) + return ModUtil.Proxy( { level = ModUtil.StackLevel( level or 0 ) }, ModUtil.Metatables.StackLevels ) end -local excludedUpValueNames = ToLookup{ "_ENV" } +local excludedUpValueNames = toLookup{ "_ENV" } ModUtil.Metatables.UpValues = { __index = function( self, name ) @@ -1172,7 +1238,7 @@ ModUtil.UpValues = ModUtil.Callable.Set( { }, function( func ) if type( func ) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end - return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues ) + return ModUtil.Proxy( { func = func }, ModUtil.Metatables.UpValues ) end ) local idData = { } @@ -1245,7 +1311,7 @@ function ModUtil.UpValues.Ids( func ) if type(func) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end - return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues.Ids ) + return ModUtil.Proxy( { func = func }, ModUtil.Metatables.UpValues.Ids ) end ModUtil.Metatables.UpValues.Values = { @@ -1288,7 +1354,7 @@ function ModUtil.UpValues.Values( func ) if type(func) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end - return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues.Values ) + return ModUtil.Proxy( { func = func }, ModUtil.Metatables.UpValues.Values ) end ModUtil.Metatables.UpValues.Names = { @@ -1322,7 +1388,7 @@ function ModUtil.UpValues.Names( func ) if type(func) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end - return ModUtil.ObjectDataProxy( { func = func }, ModUtil.Metatables.UpValues.Names ) + return ModUtil.Proxy( { func = func }, ModUtil.Metatables.UpValues.Names ) end ModUtil.Metatables.UpValues.Stacked = { @@ -1386,10 +1452,10 @@ ModUtil.Metatables.UpValues.Stacked = { } function ModUtil.UpValues.Stacked( level ) - return ModUtil.ObjectDataProxy( { levels = ModUtil.StackLevels( ( level or 1 ) ) }, ModUtil.Metatables.UpValues.Stacked ) + return ModUtil.Proxy( { levels = ModUtil.StackLevels( ( level or 1 ) ) }, ModUtil.Metatables.UpValues.Stacked ) end -local excludedLocalNames = ToLookup{ "(*temporary)", "(for generator)", "(for state)", "(for control)" } +local excludedLocalNames = toLookup{ "(*temporary)", "(for generator)", "(for state)", "(for control)" } ModUtil.Metatables.Locals = { __index = function( self, name ) @@ -1448,7 +1514,7 @@ ModUtil.Metatables.Locals = { } ModUtil.Locals = ModUtil.Callable.Set( { }, function( level ) - return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) + return ModUtil.Proxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) end ) ModUtil.Metatables.Locals.Values = { @@ -1501,7 +1567,7 @@ ModUtil.Metatables.Locals.Values.__inext = ModUtil.Metatables.Locals.Values.__ne end --]] function ModUtil.Locals.Values( level ) - return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals.Values ) + return ModUtil.Proxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals.Values ) end ModUtil.Metatables.Locals.Names = { @@ -1539,7 +1605,7 @@ ModUtil.Metatables.Locals.Names.__inext = ModUtil.Metatables.Locals.Names.__next end --]] function ModUtil.Locals.Names( level ) - return ModUtil.ObjectDataProxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals.Names ) + return ModUtil.Proxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals.Names ) end ModUtil.Metatables.Locals.Stacked = { @@ -1612,7 +1678,7 @@ ModUtil.Metatables.Locals.Stacked = { and its 'local hasRequirement' as ModUtil.Locals.Stacked( ).hasRequirement. --]] function ModUtil.Locals.Stacked( level ) - return ModUtil.ObjectDataProxy( { levels = ModUtil.StackLevels( level or 1 ) }, ModUtil.Metatables.Locals.Stacked ) + return ModUtil.Proxy( { levels = ModUtil.StackLevels( level or 1 ) }, ModUtil.Metatables.Locals.Stacked ) end -- Entangled Data Structures @@ -1681,21 +1747,21 @@ ModUtil.Metatables.Entangled.Union = { } ModUtil.Entangled.Union = ModUtil.Callable.Set( { }, function( ... ) - local keys, members = { }, ToLookup{ ... } + local keys, members = { }, toLookup{ ... } local union = { Reserve = { }, Keys = keys, Members = members } for t in pairs( members ) do for k in pairs( t ) do keys[ k ] = true end end - return ModUtil.ObjectDataProxy( union, ModUtil.Metatables.Entangled.Union ) + return ModUtil.Proxy( union, ModUtil.Metatables.Entangled.Union ) end ) function ModUtil.Entangled.Union.Add( union, ... ) local members = getObjectData( union, "Members" ) local keys = getObjectData( union, "Keys" ) local reserve = getObjectData( union, "Reserve" ) - for t in pairs( ToLookup{ ... } ) do + for t in pairs( toLookup{ ... } ) do members[ t ] = true for k in pairs( t ) do keys[ k ] = true @@ -1707,7 +1773,7 @@ end function ModUtil.Entangled.Union.Sub( union, ... ) local members = getObjectData( union, "Members" ) local keys = getObjectData( union, "Keys" ) - for t in pairs( ToLookup{ ... } ) do + for t in pairs( toLookup{ ... } ) do members[ t ] = nil end for k in pairs( keys ) do @@ -1883,16 +1949,16 @@ ModUtil.Metatables.Entangled.Map = { ModUtil.Entangled.Map = ModUtil.Callable.Set( { Unique = { } }, function( ) local data, preImage = { }, { } data, preImage = { Data = data, PreImage = preImage }, { Data = data, PreImage = preImage } - data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Data ) - preImage = ModUtil.ObjectDataProxy( preImage, ModUtil.Metatables.Entangled.Map.PreImage ) + data = ModUtil.Proxy( data, ModUtil.Metatables.Entangled.Map.Data ) + preImage = ModUtil.Proxy( preImage, ModUtil.Metatables.Entangled.Map.PreImage ) return { Data = data, Index = preImage, PreImage = preImage } end ) ModUtil.Entangled.Map.Unique = ModUtil.Callable.Set( { }, function( ) local data, inverse = { }, { } data, inverse = { Data = data, Inverse = inverse }, { Data = data, Inverse = inverse } - data = ModUtil.ObjectDataProxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) - inverse = ModUtil.ObjectDataProxy( inverse, ModUtil.Metatables.Entangled.Map.Unique.Inverse ) + data = ModUtil.Proxy( data, ModUtil.Metatables.Entangled.Map.Unique.Data ) + inverse = ModUtil.Proxy( inverse, ModUtil.Metatables.Entangled.Map.Unique.Inverse ) return { Data = data, Index = inverse, Inverse = inverse } end ) @@ -1922,7 +1988,7 @@ ModUtil.Metatables.Context = { contextInfo.args = table.pack( ... ) contextInfo.arg = arg contextInfo.data = { } - contextInfo.params = table.pack( getObjectData( self, "callContextProcessor" )( contextInfo ) ) + contextInfo.params = table.pack( getObjectData( self, "prepContext" )( contextInfo ) ) threadEnvironments[ thread ] = contextInfo.env contextInfo.response = table.pack( contextInfo.wrap( table.unpack( contextInfo.params ) ) ) @@ -1940,8 +2006,8 @@ ModUtil.Metatables.Context = { end } -ModUtil.Context = ModUtil.Callable.Set( { }, function( callContextProcessor, postCall ) - return ModUtil.ObjectDataProxy( { callContextProcessor = callContextProcessor, postCall = postCall }, ModUtil.Metatables.Context ) +ModUtil.Context = ModUtil.Callable.Set( { }, function( prepContext, postCall ) + return ModUtil.Proxy( { prepContext = prepContext, postCall = postCall }, ModUtil.Metatables.Context ) end ) ModUtil.Context.Data = ModUtil.Context( function( info ) @@ -1963,7 +2029,6 @@ end ) ModUtil.Context.Env = ModUtil.Context( function( info ) local func = info.arg local fenv = ModUtil.Node.Data.Env.New( func ) - ModUtil.Node.Data.Env.Set( func, fenv ) info.env = setmetatable( { }, { __index = function( _, key ) return fenv[ key ] or info.penv[ key ] end, __newindex = fenv @@ -1985,7 +2050,12 @@ ModUtil.Context.Call = ModUtil.Context( end ) -ModUtil.Context.StaticWrap = ModUtil.Context( +ModUtil.Context.Wrap = ModUtil.Callable.Set( { }, function( func, context, mod ) + return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( base, context, ... ) end, mod ) +end ) + + +ModUtil.Context.Wrap.Static = ModUtil.Context( function( info ) info.env = setmetatable( { }, { __index = info.penv } ) end, @@ -2001,10 +2071,6 @@ ModUtil.Context.StaticWrap = ModUtil.Context( end ) -function ModUtil.Context.Wrap( func, context, mod ) - return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( base, context, ... ) end, mod ) -end - -- Special Traversal Nodes ModUtil.Node = ModUtil.Entangled.Map.Unique( ) @@ -2024,13 +2090,41 @@ end local fenvData = setmetatable( { }, { __mode = "k" } ) +ModUtil.Metatables.Env = { + __index = function( self, key ) + local val + local env = threadEnvironments[ coroutine.running( ) ] + if env then + val = env[ key ] + end + if val ~= nil then return val end + val = getObjectData( self, "fenv" )[ key ] + if val ~= nil then return val end + return _G[ key ] + end, + __newindex = function( self, key, val ) + local env = threadEnvironments[ coroutine.running( ) ] + if env and env[ key ] ~= nil then + env[ key ] = val + return + end + local fenv = getObjectData( self, "fenv" ) + if fenv[ key ] ~= nil then + fenv[ key ] = val + return + end + _G[ key ] = val + end +} + ModUtil.Node.Data.Env = { New = function( func ) - local fenv = _G.getfenv( func ) - if not fenv then + local fenv = getfenv( func ) + if not fenv or fenv == __G then fenv = { } fenvData[ func ] = fenv end + setfenv( func, ModUtil.Proxy( { fenv = fenv }, ModUtil.Metatables.Env ) ) return fenv end, Get = function( func ) @@ -2044,39 +2138,12 @@ ModUtil.Node.Data.Env = { return fenv end, Set = function( func, fenv ) - fenvData[ func ] = fenv - - setfenv( func, setmetatable( { }, { - __index = function( _, key ) - local val - local env = threadEnvironments[ coroutine.running( ) ] - if env then - val = env[ key ] - end - if val ~= nil then return val end - val = fenv[ key ] - if val ~= nil then return val end - return _G[ key ] - end, - __newindex = function( _, key, val ) - local env = threadEnvironments[ coroutine.running( ) ] - if env and env[ key ] ~= nil then - env[ key ] = val - return - end - if fenv[ key ] ~= nil then - fenv[ key ] = val - return - end - _G[ key ] = val - end - } ) ) - + setfenv( func, ModUtil.Proxy( { fenv = fenv }, ModUtil.Metatables.Env ) ) end } -ModUtil.Node.Data.Metatable = { +ModUtil.Node.Data.Meta = { New = function( obj ) local meta = getmetatable( obj ) if meta == nil then @@ -2224,7 +2291,7 @@ function ModUtil.ReferTable( obtainer, ... ) local obtain = function( ) return obtainer( table.unpack( args ) ) end - return ModUtil.ObjectDataProxy( { obtain = obtain }, ModUtil.Metatables.ReferTable ) + return ModUtil.Proxy( { obtain = obtain }, ModUtil.Metatables.ReferTable ) end -- Internal access @@ -2237,7 +2304,7 @@ do objectData, newObjectData, getObjectData, decorators, overrides, threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, - pusherror, getname, ToLookup, wrapDecorator, + pusherror, getname, toLookup, wrapDecorator, isNamespace, stackLevelFunction, stackLevelInterface, stackLevelProperty, passByValueTypes, callableCandidateTypes, excludedFieldNames end ) From 16afff2f358e5caa3ebb534c8ab3174e35f80c86 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Sat, 21 Aug 2021 17:20:14 +1000 Subject: [PATCH 28/32] remove Context.Env --- ModUtil.lua | 71 +++-------------------------------------------------- 1 file changed, 3 insertions(+), 68 deletions(-) diff --git a/ModUtil.lua b/ModUtil.lua index 753b7a4..3b57e50 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -577,7 +577,7 @@ function ModUtil.ToString.Deep.NoNamespaces( o, seen ) first = true seen = { } end - if type( o ) == "table" and not seen[ o ] and o ~= _G and o ~= _ENV and ( first or not ModUtil.Mods.Inverse[ o ] ) then + if type( o ) == "table" and not seen[ o ] and not isNamespace( o ) then seen[ o ] = true local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do @@ -601,7 +601,7 @@ function ModUtil.ToString.Deep.Namespaces( o, seen ) first = true seen = { } end - if type( o ) == "table" and not seen[ o ] and ( first or o == _G or o == _ENV or ModUtil.Mods.Inverse[ o ] ) then + if type( o ) == "table" and not seen[ o ] and isNamespace( o ) then seen[ o ] = true local out = { ModUtil.ToString.Value( o ), "( " } for k, v in pairs( o ) do @@ -2026,16 +2026,6 @@ ModUtil.Context.Meta = ModUtil.Context( function( info ) } ) end ) -ModUtil.Context.Env = ModUtil.Context( function( info ) - local func = info.arg - local fenv = ModUtil.Node.Data.Env.New( func ) - info.env = setmetatable( { }, { - __index = function( _, key ) return fenv[ key ] or info.penv[ key ] end, - __newindex = fenv - } ) - end -) - ModUtil.Context.Call = ModUtil.Context( function( info ) info.env = setmetatable( { }, { __index = info.penv } ) @@ -2088,61 +2078,6 @@ function ModUtil.Node.New( parent, key ) return tbl end -local fenvData = setmetatable( { }, { __mode = "k" } ) - -ModUtil.Metatables.Env = { - __index = function( self, key ) - local val - local env = threadEnvironments[ coroutine.running( ) ] - if env then - val = env[ key ] - end - if val ~= nil then return val end - val = getObjectData( self, "fenv" )[ key ] - if val ~= nil then return val end - return _G[ key ] - end, - __newindex = function( self, key, val ) - local env = threadEnvironments[ coroutine.running( ) ] - if env and env[ key ] ~= nil then - env[ key ] = val - return - end - local fenv = getObjectData( self, "fenv" ) - if fenv[ key ] ~= nil then - fenv[ key ] = val - return - end - _G[ key ] = val - end -} - -ModUtil.Node.Data.Env = { - New = function( func ) - local fenv = getfenv( func ) - if not fenv or fenv == __G then - fenv = { } - fenvData[ func ] = fenv - end - setfenv( func, ModUtil.Proxy( { fenv = fenv }, ModUtil.Metatables.Env ) ) - return fenv - end, - Get = function( func ) - local fenv = fenvData[ func ] - if not fenv then - fenv = getfenv( func ) - if fenv == _ENV then - fenv = nil - end - end - return fenv - end, - Set = function( func, fenv ) - fenvData[ func ] = fenv - setfenv( func, ModUtil.Proxy( { fenv = fenv }, ModUtil.Metatables.Env ) ) - end -} - ModUtil.Node.Data.Meta = { New = function( obj ) local meta = getmetatable( obj ) @@ -2303,7 +2238,7 @@ do return _G, objectData, newObjectData, getObjectData, decorators, overrides, - threadEnvironments, fenvData, getEnv, replaceGlobalEnvironment, + threadEnvironments, getEnv, replaceGlobalEnvironment, pusherror, getname, toLookup, wrapDecorator, isNamespace, stackLevelFunction, stackLevelInterface, stackLevelProperty, passByValueTypes, callableCandidateTypes, excludedFieldNames From 41df6697e7cd9ff26c84582389e9292686158b90 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Sat, 21 Aug 2021 23:36:42 +1000 Subject: [PATCH 29/32] Change patch stack operations --- ModUtil.Compat.lua | 28 ++++++++++++++++--- ModUtil.Extra.lua | 36 ++++++++++++++++-------- ModUtil.Hades.lua | 43 ++++++++++++++++------------ ModUtil.lua | 70 ++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 132 insertions(+), 45 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index 5645093..59ff5f5 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -63,15 +63,15 @@ ModUtil.Compat.PathSet = ModUtil.Path.Set ModUtil.Compat.WrapFunction = ModUtil.IndexArray.Wrap -ModUtil.Compat.RewrapFunction = ModUtil.IndexArray.Decorate.Redo +ModUtil.Compat.RewrapFunction = ModUtil.IndexArray.Decorate.Refresh -ModUtil.Compat.UnwrapFunction = ModUtil.IndexArray.Decorate.Undo +ModUtil.Compat.UnwrapFunction = ModUtil.IndexArray.Decorate.Pop ModUtil.Compat.WrapBaseFunction = ModUtil.Path.Wrap -ModUtil.Compat.RewrapBaseFunction = ModUtil.Path.Decorate.Redo +ModUtil.Compat.RewrapBaseFunction = ModUtil.Path.Decorate.Refresh -ModUtil.Compat.UnwrapBaseFunction = ModUtil.Path.Decorate.Undo +ModUtil.Compat.UnwrapBaseFunction = ModUtil.Path.Decorate.Pop ModUtil.Compat.Override = ModUtil.IndexArray.Override @@ -83,6 +83,20 @@ ModUtil.Compat.GetOriginalBaseValue = ModUtil.Path.Original ModUtil.Compat.RawInterface = ModUtil.Raw +ModUtil.Compat.MapVars = ModUtil.Args.Map + +ModUtil.Compat.StackedUpValues = ModUtil.UpValues.Stacked + +ModUtil.Compat.StackedLocals = ModUtil.Locals.Stacked + +ModUtil.Compat.LocalValues = ModUtil.Locals.Values + +ModUtil.Compat.LocalNames = ModUtil.Locals.Names + +function ModUtil.Compat.MapTable( mapFunc, tableArg ) + return ModUtil.Table.Map( tableArg, mapFunc ) +end + function ModUtil.Compat.WrapWithinFunction( baseTable, indexArray, envIndexArray, wrapFunc, mod ) ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, function( ) ModUtil.IndexArray.Wrap( _G, envIndexArray, wrapFunc, mod ) @@ -94,3 +108,9 @@ function ModUtil.Compat.WrapBaseWithinFunction( funcPath, baseFuncPath, wrapFunc ModUtil.Path.Wrap( funcPath, wrapFunc, mod ) end ) end + +function ModUtil.BaseOverrideWithinFunction( funcPath, basePath, value, mod ) + ModUtil.Path.Context.Wrap( funcPath, function( ) + ModUtil.Path.Override( basePath, value, mod ) + end ) +end diff --git a/ModUtil.Extra.lua b/ModUtil.Extra.lua index 3163669..de7c347 100644 --- a/ModUtil.Extra.lua +++ b/ModUtil.Extra.lua @@ -20,18 +20,22 @@ ModUtil.Callable.Decorate = ModUtil.Callable.Set( { }, function( obj, func, mod return ModUtil.Callable.Map( obj, ModUtil.Decorate, func, mod ) end ) -function ModUtil.Callable.Decorate.Undo( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate.Undo ) +function ModUtil.Callable.Decorate.Pop( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate.Pop ) end -function ModUtil.Callable.Decorate.Redo( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate.Redo ) +function ModUtil.Callable.Decorate.Refresh( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Decorate.Refresh ) end function ModUtil.Callable.Override( obj, value, mod ) return ModUtil.Callable.Map( obj, ModUtil.Override, value, mod ) end +function ModUtil.Callable.Restore( obj ) + return ModUtil.Callable.Map( obj, ModUtil.Restore ) +end + function ModUtil.Callable.Overriden( obj ) return ModUtil.Callable.Map( obj, ModUtil.Overriden ) end @@ -73,18 +77,22 @@ ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( baseTable, in return ModUtil.Path.Map( baseTable, indexArray, ModUtil.Callable.Decorate, func, mod ) end ) -function ModUtil.IndexArray.Decorate.Undo( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Undo ) +function ModUtil.IndexArray.Decorate.Pop( baseTable, indexArray ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Pop ) end -function ModUtil.IndexArray.Decorate.Redo( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Redo ) +function ModUtil.IndexArray.Decorate.Refresh( baseTable, indexArray ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Refresh ) end function ModUtil.IndexArray.Override( baseTable, indexArray, value, mod ) return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Override, value, mod ) end +function ModUtil.IndexArray.Restore( baseTable, indexArray ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Restore ) +end + function ModUtil.IndexArray.Overriden( baseTable, indexArray ) return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Overriden ) end @@ -129,18 +137,22 @@ ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( path, func, mod ) return ModUtil.Path.Map( path, ModUtil.Callable.Decorate, func, mod ) end ) -function ModUtil.Path.Decorate.Undo( path ) - return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Undo ) +function ModUtil.Path.Decorate.Pop( path ) + return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Pop ) end -function ModUtil.Path.Decorate.Redo( path ) - return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Redo ) +function ModUtil.Path.Decorate.Refresh( path ) + return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Refresh ) end function ModUtil.Path.Override( path, value, mod ) return ModUtil.Path.Map( path, ModUtil.Callable.Override, value, mod ) end +function ModUtil.Path.Restore( path ) + return ModUtil.Path.Map( path, ModUtil.Callable.Restore ) +end + function ModUtil.Path.Overriden( path ) return ModUtil.Path.Map( path, ModUtil.Callable.Overriden ) end diff --git a/ModUtil.Hades.lua b/ModUtil.Hades.lua index 092f169..a38ccd5 100644 --- a/ModUtil.Hades.lua +++ b/ModUtil.Hades.lua @@ -1,13 +1,6 @@ ModUtil.Mod.Register( "Hades", ModUtil ) -ModUtil.Table.Merge( ModUtil.Hades, { - PrintStackHeight = 10, - PrintStackCapacity = 80 -} ) - -ModUtil.Anchors.PrintOverhead = {} - -- Global Interception local function isPath( path ) @@ -21,17 +14,31 @@ end Intercept global keys which are objects to return themselves This way we can use other namespaces for UI etc --]] -ModUtil.IndexArray.Wrap( getmetatable( _ENV ), { "__index" }, function( baseFunc, self, key ) - local value = baseFunc( self, key ) - if value ~= nil then return value end - local t = type( key ) - if t == "string" and isPath( key ) then - return ModUtil.Path.Get( key ) - end - if ModUtil.Internal.callableCandidateTypes[ t ] then - return key - end -end, ModUtil.Hades ) +do + + local meta = getmetatable( _ENV ) or { __index = rawget } + ModUtil.IndexArray.Wrap( meta, { "__index" }, function( baseFunc, self, key ) + local value = baseFunc( self, key ) + if value ~= nil then return value end + local t = type( key ) + if t == "string" and isPath( key ) then + return ModUtil.Path.Get( key ) + end + if ModUtil.Internal.callableCandidateTypes[ t ] then + return key + end + end, ModUtil.Hades ) + setmetatable( _ENV, meta ) + +end +--- + +ModUtil.Table.Merge( ModUtil.Hades, { + PrintStackHeight = 10, + PrintStackCapacity = 80 +} ) + +ModUtil.Anchors.PrintOverhead = {} -- Menu Handling diff --git a/ModUtil.lua b/ModUtil.lua index 3b57e50..68574d9 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -775,12 +775,23 @@ function ModUtil.Array.Join( a, ... ) return ModUtil.Array.Join( c, ModUtil.Args.Drop( 1, ... ) ) end -function ModUtil.Table.Copy( t ) +ModUtil.Table.Copy = ModUtil.Callable.Set( { }, function( t ) c = { } for k, v in pairs( t ) do c[ k ] = v end return c +end ) + +function ModUtil.Table.Copy.Deep( t ) + c = { } + for k, v in pairs( t ) do + if type( v ) == "table" then + v = ModUtil.Table.Copy( v ) + end + c[ k ] = v + end + return c end function ModUtil.Table.Clear( t ) @@ -2158,21 +2169,58 @@ function ModUtil.Wrap( base, wrap, mod ) return ModUtil.Decorate( base, wrapDecorator( wrap ), mod ) end -function ModUtil.Decorate.Undo( obj ) +function ModUtil.Decorate.Pop( obj ) local callback = decorators[ obj ] - return callback and callback.Base or obj + if not callback then + error( "object has no decorators", 2 ) + return obj -- if error is ignored + end + return callback.Base end -function ModUtil.Decorate.Redo( obj ) - local node = decorators[ obj ] - if not node then return ModUtil.Overriden( obj ) end - return ModUtil.Decorate( ModUtil.Decorate.Redo( node.Base ), node.Func, node.Mod ) +local function refresh( parent ) + local node = decorators[ parent ].Base + node = decorators[ node ] and refresh( node ) or node + local new = decorators[ parent ].Func( node ) + decorators[ new ] = { Base = node, decorators[ parent ].Func, decorators[ parent ].Mod } + return new +end + +function ModUtil.Decorate.Refresh( obj ) + if decorators[ obj ] then + return refresh( obj ) + end + return obj end function ModUtil.Override( base, value, mod ) - local obj = { Base = ModUtil.Original( base ), Mod = mod } - overrides[ value ] = obj - return ModUtil.Decorate.Redo( value ) + local node, parent = base + while decorators[ node ] do + parent = node + node = decorators[ node ].Base + end + overrides[ value ] = { Base = node, Mod = mod } + if parent then + decorators[ parent ].Base = value + end + return ModUtil.Decorate.Refresh( base ) +end + +function ModUtil.Restore( base ) + local node, parent = base + while decorators[ node ] do + parent = node + node = decorators[ node ].Base + end + if overrides[ node ] then + node = overrides[ node ].Base + else + error( "object has no overrides", 2 ) + end + if parent then + decorators[ parent ].Base = node.Base + end + return ModUtil.Decorate.Refresh( base ) end function ModUtil.Overriden( obj ) @@ -2237,7 +2285,7 @@ do local ups = ModUtil.UpValues( function( ) return _G, objectData, newObjectData, getObjectData, - decorators, overrides, + decorators, overrides, refresh, threadEnvironments, getEnv, replaceGlobalEnvironment, pusherror, getname, toLookup, wrapDecorator, isNamespace, stackLevelFunction, stackLevelInterface, stackLevelProperty, From b4c5125e200ef2a15587b6337661e8f3ade2b711 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Sun, 22 Aug 2021 04:15:56 +1000 Subject: [PATCH 30/32] Rollback callable oriented extras --- ModUtil.Compat.lua | 4 ++ ModUtil.Extra.lua | 123 +++++++++++---------------------------------- ModUtil.lua | 43 +++++++++------- 3 files changed, 58 insertions(+), 112 deletions(-) diff --git a/ModUtil.Compat.lua b/ModUtil.Compat.lua index 59ff5f5..60ceb5b 100644 --- a/ModUtil.Compat.lua +++ b/ModUtil.Compat.lua @@ -93,6 +93,10 @@ ModUtil.Compat.LocalValues = ModUtil.Locals.Values ModUtil.Compat.LocalNames = ModUtil.Locals.Names +function ModUtil.Compat.GetBaseBottomUpValues( funcPath ) + return ModUtil.UpValues( ModUtil.Path.Original( funcPath ) ) +end + function ModUtil.Compat.MapTable( mapFunc, tableArg ) return ModUtil.Table.Map( tableArg, mapFunc ) end diff --git a/ModUtil.Extra.lua b/ModUtil.Extra.lua index de7c347..6df3c80 100644 --- a/ModUtil.Extra.lua +++ b/ModUtil.Extra.lua @@ -1,115 +1,56 @@ -ModUtil.Callable.Context = { } - -function ModUtil.Callable.Wrap( obj, wrap, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Wrap, wrap, mod ) -end - -function ModUtil.Callable.Context.Wrap( obj, context, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Context.Wrap, context, mod ) -end - -function ModUtil.Callable.Context.StaticWrap( obj, context, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Context.StaticWrap, context, mod ) -end - -function ModUtil.Callable.Context.Env( obj, context ) - return ModUtil.Callable.Map( obj, ModUtil.Context.Env, context ) -end - -ModUtil.Callable.Decorate = ModUtil.Callable.Set( { }, function( obj, func, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate, func, mod ) -end ) - -function ModUtil.Callable.Decorate.Pop( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate.Pop ) -end - -function ModUtil.Callable.Decorate.Refresh( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Decorate.Refresh ) -end - -function ModUtil.Callable.Override( obj, value, mod ) - return ModUtil.Callable.Map( obj, ModUtil.Override, value, mod ) -end - -function ModUtil.Callable.Restore( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Restore ) -end - -function ModUtil.Callable.Overriden( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Overriden ) -end - -function ModUtil.Callable.Original( obj ) - return ModUtil.Callable.Map( obj, ModUtil.Original ) -end - -function ModUtil.Callable.ReferFunction( obj ) - return ModUtil.ReferFunction( ModUtil.Callable.GetFunc, obj ) -end - -function ModUtil.Callable.ReferTable( obj ) - return ModUtil.ReferTable( ModUtil.Callable.Get, obj ) -end - --- ModUtil.IndexArray.Context = { } function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrap, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Wrap, wrap, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrap, mod ) end -function ModUtil.IndexArray.Context.Wrap( baseTable, indexArray, context, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Context.Wrap, context, mod ) -end - -function ModUtil.IndexArray.Context.StaticWrap( baseTable, indexArray, context, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Context.StaticWrap, context, mod ) -end +ModUtil.IndexArray.Context.Wrap = ModUtil.Callable.Set( { }, function( baseTable, indexArray, context, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) +end ) -function ModUtil.IndexArray.Context.Env( baseTable, indexArray, context ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Context.Wrap, context ) +function ModUtil.IndexArray.Context.Wrap.Static( baseTable, indexArray, context, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap.Static, context, mod ) end - ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( baseTable, indexArray, func, mod ) - return ModUtil.Path.Map( baseTable, indexArray, ModUtil.Callable.Decorate, func, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) function ModUtil.IndexArray.Decorate.Pop( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Pop ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Pop ) end function ModUtil.IndexArray.Decorate.Refresh( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Decorate.Refresh ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate.Refresh ) end function ModUtil.IndexArray.Override( baseTable, indexArray, value, mod ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Override, value, mod ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Override, value, mod ) end function ModUtil.IndexArray.Restore( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Restore ) + return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Restore ) end function ModUtil.IndexArray.Overriden( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Overriden ) + return ModUtil.Overriden( ModUtil.IndexArray.Get( baseTable, indexArray ) ) end function ModUtil.IndexArray.Original( baseTable, indexArray ) - return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Callable.Original ) + return ModUtil.Original( ModUtil.IndexArray.Get( baseTable, indexArray ) ) end function ModUtil.IndexArray.ReferFunction( baseTable, indexArray ) return ModUtil.ReferFunction( function( ... ) - ModUtil.Callable.GetFunc( ModUtil.IndexArray.Get( ... ) ) + ModUtil.Get( ModUtil.IndexArray.Get( ... ) ) end, baseTable, indexArray ) end function ModUtil.IndexArray.ReferTable( baseTable, indexArray ) return ModUtil.ReferTable( function( ... ) - ModUtil.Callable.Get( ModUtil.IndexArray.Get( ... ) ) + ModUtil.Get( ModUtil.IndexArray.Get( ... ) ) end, baseTable, indexArray ) end @@ -118,57 +59,53 @@ end ModUtil.Path.Context = { } function ModUtil.Path.Wrap( path, wrap, mod ) - return ModUtil.Path.Map( path, ModUtil.Callable.Wrap, wrap, mod ) + return ModUtil.Path.Map( path, ModUtil.Wrap, wrap, mod ) end -function ModUtil.Path.Context.Wrap( path, context, mod ) - return ModUtil.Path.Map( path, ModUtil.Callable.Context.Wrap, context, mod ) -end - -function ModUtil.Path.Context.StaticWrap( path, context, mod ) - return ModUtil.Path.Map( path, ModUtil.Callable.Context.StaticWrap, context, mod ) -end +ModUtil.Path.Context.Wrap = ModUtil.Callable.Set( { }, function( path, context, mod ) + return ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) +end ) -function ModUtil.Path.Context.Env( path, context ) - return ModUtil.Path.Map( path, ModUtil.Callable.Context.Env, context ) +function ModUtil.Path.Context.Wrap.Static( path, context, mod ) + return ModUtil.Path.Map( path, ModUtil.Context.Wrap.Static, context, mod ) end ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( path, func, mod ) - return ModUtil.Path.Map( path, ModUtil.Callable.Decorate, func, mod ) + return ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) function ModUtil.Path.Decorate.Pop( path ) - return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Pop ) + return ModUtil.Path.Map( path, ModUtil.Decorate.Pop ) end function ModUtil.Path.Decorate.Refresh( path ) - return ModUtil.Path.Map( path, ModUtil.Callable.Decorate.Refresh ) + return ModUtil.Path.Map( path, ModUtil.Decorate.Refresh ) end function ModUtil.Path.Override( path, value, mod ) - return ModUtil.Path.Map( path, ModUtil.Callable.Override, value, mod ) + return ModUtil.Path.Map( path, ModUtil.Override, value, mod ) end function ModUtil.Path.Restore( path ) - return ModUtil.Path.Map( path, ModUtil.Callable.Restore ) + return ModUtil.Path.Map( path, ModUtil.Restore ) end function ModUtil.Path.Overriden( path ) - return ModUtil.Path.Map( path, ModUtil.Callable.Overriden ) + return ModUtil.Overriden( ModUtil.Path.Get( path ) ) end function ModUtil.Path.Original( path ) - return ModUtil.Path.Map( path, ModUtil.Callable.Original ) + return ModUtil.Original( ModUtil.Path.Get( path ) ) end function ModUtil.Path.ReferFunction( path ) return ModUtil.ReferFunction( function( ... ) - ModUtil.Callable.GetFunc( ModUtil.Path.Get( ... ) ) + ModUtil.Path.Get( ... ) end, path ) end function ModUtil.Path.ReferTable( path ) return ModUtil.ReferTable( function( ... ) - ModUtil.Callable.Get( ModUtil.Path.Get( ... ) ) + ModUtil.Path.Get( ... ) end, path ) end \ No newline at end of file diff --git a/ModUtil.lua b/ModUtil.lua index 68574d9..4b0543a 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -336,7 +336,7 @@ end -- Operations on Callables -ModUtil.Callable = { } +ModUtil.Callable = { Func = { } } function ModUtil.Callable.Get( obj ) local meta, pobj @@ -359,29 +359,31 @@ function ModUtil.Callable.Set( o, f ) return setmetatable( o, m ), f end -function ModUtil.Callable.GetFunc( o ) - local meta - while obj do - local t = type( obj ) - if t == "function" then return obj end - if not callableCandidateTypes[ t ] then return end - meta = getmetatable( obj ) - if not meta then break end - obj = rawget( meta, "__call" ) - end -end - function ModUtil.Callable.Map( o, f, ... ) local pobj, obj = ModUtil.Callable.Get( o ) if not pobj then - return f( obj, ... ), false + return nil, f( obj, ... ) end - ModUtil.Callable.Set( pobj, f( obj, ... ) ) - return o, true + return ModUtil.Callable.Set( pobj, f( obj, ... ) ) +end + +function ModUtil.Callable.Func.Get( ... ) + local _, f = ModUtil.Callable.Get( ... ) + return f +end + +function ModUtil.Callable.Func.Set( ... ) + local _, f = ModUtil.Callable.Set( ... ) + return f +end + +function ModUtil.Callable.Func.Map( ... ) + local _, f = ModUtil.Callable.Map( ... ) + return f end ModUtil.Callable.Set( ModUtil.Callable, function ( obj ) - return ModUtil.Callable.GetFunc( obj ) ~= nil + return ModUtil.Callable.Func.Get( obj ) ~= nil end ) -- Data Misc @@ -2082,10 +2084,13 @@ function ModUtil.Node.New( parent, key ) return ModUtil.Node.Data[ nodeType ].New( parent ) end local tbl = parent[ key ] - if type( tbl ) ~= "table" then + if tbl == nil then tbl = { } parent[ key ] = tbl end + if type( tbl ) ~= "table" then + error( "key already occupied by a non-table", 2 ) + end return tbl end @@ -2226,7 +2231,7 @@ end function ModUtil.Overriden( obj ) local node = decorators[ obj ] if not node then return obj end - return ModUtil.Original( node.Base ) + return ModUtil.Overriden( node.Base ) end function ModUtil.Original( obj ) From 831cdbc529f78593100135049e80db147c8e460c Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 1 Sep 2021 06:35:10 +1000 Subject: [PATCH 31/32] Add persistent and safe mod data system --- ModUtil.Extra.lua | 8 +-- ModUtil.Hades.lua | 53 ++++++++++----- ModUtil.Main.lua | 165 +++++++++++++++++++++++++++++++++++++++++----- ModUtil.lua | 69 +++++++++---------- 4 files changed, 224 insertions(+), 71 deletions(-) diff --git a/ModUtil.Extra.lua b/ModUtil.Extra.lua index 6df3c80..8837fae 100644 --- a/ModUtil.Extra.lua +++ b/ModUtil.Extra.lua @@ -6,7 +6,7 @@ function ModUtil.IndexArray.Wrap( baseTable, indexArray, wrap, mod ) return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Wrap, wrap, mod ) end -ModUtil.IndexArray.Context.Wrap = ModUtil.Callable.Set( { }, function( baseTable, indexArray, context, mod ) +ModUtil.IndexArray.Context.Wrap = ModUtil.Callable.Set( { }, function( _, baseTable, indexArray, context, mod ) return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap, context, mod ) end ) @@ -14,7 +14,7 @@ function ModUtil.IndexArray.Context.Wrap.Static( baseTable, indexArray, context, return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Context.Wrap.Static, context, mod ) end -ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( baseTable, indexArray, func, mod ) +ModUtil.IndexArray.Decorate = ModUtil.Callable.Set( { }, function( _, baseTable, indexArray, func, mod ) return ModUtil.IndexArray.Map( baseTable, indexArray, ModUtil.Decorate, func, mod ) end ) @@ -62,7 +62,7 @@ function ModUtil.Path.Wrap( path, wrap, mod ) return ModUtil.Path.Map( path, ModUtil.Wrap, wrap, mod ) end -ModUtil.Path.Context.Wrap = ModUtil.Callable.Set( { }, function( path, context, mod ) +ModUtil.Path.Context.Wrap = ModUtil.Callable.Set( { }, function( _, path, context, mod ) return ModUtil.Path.Map( path, ModUtil.Context.Wrap, context, mod ) end ) @@ -70,7 +70,7 @@ function ModUtil.Path.Context.Wrap.Static( path, context, mod ) return ModUtil.Path.Map( path, ModUtil.Context.Wrap.Static, context, mod ) end -ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( path, func, mod ) +ModUtil.Path.Decorate = ModUtil.Callable.Set( { }, function( _, path, func, mod ) return ModUtil.Path.Map( path, ModUtil.Decorate, func, mod ) end ) diff --git a/ModUtil.Hades.lua b/ModUtil.Hades.lua index a38ccd5..c4540ca 100644 --- a/ModUtil.Hades.lua +++ b/ModUtil.Hades.lua @@ -3,6 +3,13 @@ ModUtil.Mod.Register( "Hades", ModUtil ) -- Global Interception +--[[ + Intercept global keys which are objects to return themselves + This way we can use other namespaces for UI etc +--]] + +local callableCandidateTypes = ModUtil.Internal.callableCandidateTypes + local function isPath( path ) return path:find("[.]") and not path:find("[.][.]+") @@ -10,24 +17,29 @@ local function isPath( path ) and not path:find("[.]$") end ---[[ - Intercept global keys which are objects to return themselves - This way we can use other namespaces for UI etc ---]] +local function routeKey( self, key ) + local t = type( key ) + if t == "string" and isPath( key ) then + return ModUtil.Path.Get( key ) + end + if callableCandidateTypes[ t ] then + return key + end +end + do - local meta = getmetatable( _ENV ) or { __index = rawget } - ModUtil.IndexArray.Wrap( meta, { "__index" }, function( baseFunc, self, key ) - local value = baseFunc( self, key ) - if value ~= nil then return value end - local t = type( key ) - if t == "string" and isPath( key ) then - return ModUtil.Path.Get( key ) - end - if ModUtil.Internal.callableCandidateTypes[ t ] then - return key - end - end, ModUtil.Hades ) + local meta = getmetatable( _ENV ) or { } + if meta.__index then + meta.__index = ModUtil.Wrap( meta.__index, function( base, self, key ) + local value = base( self, key ) + if value ~= nil then return value end + return routeKey( self, key ) + end, ModUtil.Hades ) + else + meta.__index = routeKey + end + setmetatable( _ENV, meta ) end @@ -415,4 +427,13 @@ end function ModUtil.Hades.RandomElement( tableArg, rng ) local Collapsed = CollapseTable( tableArg ) return Collapsed[RandomInt( 1, #Collapsed, rng )] +end + +-- Internal Access + +do + local ups = ModUtil.UpValues( function( ) + return callableCandidateTypes, isPath, routeKey + end ) + ModUtil.Entangled.Union.Add( ModUtil.Internal, ups ) end \ No newline at end of file diff --git a/ModUtil.Main.lua b/ModUtil.Main.lua index caaa1fa..fe042e1 100644 --- a/ModUtil.Main.lua +++ b/ModUtil.Main.lua @@ -16,6 +16,9 @@ local ModUtil, pairs, ipairs, table, SaveIgnores, _G SaveIgnores[ "ModUtil" ] = true +rawset( _ENV, "_DEBUG_G", _G ) +SaveIgnores[ "_DEBUG_G" ] = true + --[[ Create a namespace that can be used for the mod's functions and data, and ensure that it doesn't end up in save files. @@ -23,31 +26,158 @@ SaveIgnores[ "ModUtil" ] = true modName - the name of the mod parent - the parent mod, or nil if this mod stands alone --]] -function ModUtil.Mod.Register( modName, parent, content ) +function ModUtil.Mod.Register( first, second ) + local modName, parent + if type( first ) == "string" then + modName, parent = first, second + else + modName, parent = second, first + end if not parent then parent = _G SaveIgnores[ modName ] = true end - local mod = parent[ modName ] - if not mod then - mod = { } - parent[ modName ] = mod - local path = ModUtil.Mods.Inverse[ parent ] - if path ~= nil then - path = path .. '.' + local mod = { } + parent[ modName ] = mod + local path = ModUtil.Mods.Inverse[ parent ] + if path ~= nil then + path = path .. '.' + else + path = '' + end + path = path .. modName + ModUtil.Mods.Data[ path ] = mod + ModUtil.Identifiers.Inverse[ path ] = mod + return setmetatable( mod, { __index = ModUtil.Mod } ) +end + +local objectData = ModUtil.Internal.objectData +local passByValueTypes = ModUtil.Internal.passByValueTypes + +local function modDataProxy( value, level ) + level = ( level or 1 ) + 1 + local t = type( value ) + if passByValueTypes[ t ] or t == "string" then + return value + end + if t == "table" then + if getmetatable( value ) then + error( "saved data tables cannot have values with metatables", level ) + end + return ModUtil.Entangled.ModData( value, level ) + end + error( "saved data tables cannot have values of type "..t..".", level ) +end + +local function modDataKey( key, level ) + local t = type( key ) + if passByValueTypes[ t ] or t == "string" then + return key + end + error( "saved data tables cannot have keys of type "..t..".", ( level or 1 ) + 1 ) +end + +local function modDataPlain( obj, key, value, level ) + level = ( level or 1 ) + 1 + if modDataKey( key, level ) ~= nil then + local t = type( value ) + if passByValueTypes[ t ] or t == "string" then + obj[ key ] = value + elseif t == "table" then + if getmetatable( value ) then + local state, value = pcall( function( ) return objectData[ value ] end ) + if not state then + error( "saved data tables cannot have values with metatables", level ) + end + end + for k, v in pairs( value ) do + modDataPlain( value, k, v, level ) + end else - path = '' + error( "saved data tables cannot have values of type "..t..".", level ) end - path = path .. modName - ModUtil.Mods.Data[ path ] = mod - ModUtil.Identifiers.Inverse[ path ] = mod end - if content then - ModUtil.Table.SetMap( parent[ modName ], content ) +end + +ModUtil.Metatables.Entangled.ModData = { + __index = function( self, key ) + return modDataProxy( objectData[ self ][ key ], 2 ) + end, + __newindex = function( self, key, value ) + modDataPlain( objectData[ self ], key, value, 2 ) + end, + __len = function( self ) + return #objectData[ self ] + end, + __next = function( self, key ) + local key = next( objectData[ self ], key ) + if modDataKey( key, 2 ) ~= nil then + return key, modDataProxy( objectData[ self ][ key ], 2 ) + end + end, + __inext = function( self, idx ) + local idx = inext( objectData[ self ], idx ) + if modDataKey( idx, 2 ) ~= nil then + return idx, modDataProxy( objectData[ self ][ idx ], 2 ) + end + end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return qrawipairs( self ) end - return parent[ modName ] +} + +function ModUtil.Entangled.ModData( value ) + return ModUtil.Proxy( value, ModUtil.Metatables.Entangled.ModData ) end +ModUtil.Mod.Data = setmetatable( { }, { + __call = function( _, mod ) + ModData = ModData or { } + local key = ModUtil.Mods.Inverse[ mod ] + local data = ModData[ key ] + if not data then + data = { } + ModData[ key ] = data + end + return modDataProxy( data, 2 ) + end, + __index = function( _, key ) + ModData = ModData or { } + return modDataProxy( ModData[ key ], 2 ) + end, + __newindex = function( _, key, value ) + ModData = ModData or { } + modDataPlain( ModData, key, value, 2 ) + end, + __len = function( ) + ModData = ModData or { } + return #ModData + end, + __next = function( _, key ) + ModData = ModData or { } + local key = next( ModData, key ) + if modDataKey( key, 2 ) ~= nil then + return key, modDataProxy( ModData[ key ], 2 ) + end + end, + __inext = function( _, idx ) + ModData = ModData or { } + local idx = inext( ModData, idx ) + if modDataKey( idx, 2 ) ~= nil then + return idx, modDataProxy( ModData[ idx ], 2 ) + end + end, + __pairs = function( self ) + return qrawpairs( self ) + end, + __ipairs = function( self ) + return qrawipairs( self ) + end +} ) + --[[ Tell each screen anchor that they have been forced closed by the game --]] @@ -96,7 +226,8 @@ end do local ups = ModUtil.UpValues( function( ) - return forceClosed, funcsToLoad, loadFuncs + return _G, forceClosed, funcsToLoad, loadFuncs, + objectData, passByValueTypes, modDataKey, modDataProxy, modDataPlain end ) - rawset( ModUtil.Internal, "Main", setmetatable( { }, { __index = ups, __newindex = ups } ) ) + ModUtil.Entangled.Union.Add( ModUtil.Internal, ups ) end \ No newline at end of file diff --git a/ModUtil.lua b/ModUtil.lua index 4b0543a..e4e5782 100644 --- a/ModUtil.lua +++ b/ModUtil.lua @@ -261,7 +261,6 @@ local function replaceGlobalEnvironment( ) if v == _G then reg[ i ] = __G end end ModUtil.Identifiers.Inverse._ENV = __G - rawset( __G, "_DEBUG_G", _G ) end -- Managed Object Data @@ -353,9 +352,7 @@ end function ModUtil.Callable.Set( o, f ) local m = getmetatable( o ) or { } - function m.__call( _, ... ) - return f( ... ) - end + m.__call = f return setmetatable( o, m ), f end @@ -382,17 +379,17 @@ function ModUtil.Callable.Func.Map( ... ) return f end -ModUtil.Callable.Set( ModUtil.Callable, function ( obj ) +ModUtil.Callable.Set( ModUtil.Callable, function ( _, obj ) return ModUtil.Callable.Func.Get( obj ) ~= nil end ) -- Data Misc -function ModUtil.Args.Map( mapFunc, ... ) +function ModUtil.Args.Map( map, ... ) local out = { } local args = table.pack( ... ) for i = 1, args.n do - table.insert( out, mapFunc( args[ i ] ) ) + out[ i ] = map( args[ i ] ) end return table.unpack( out ) end @@ -407,17 +404,17 @@ function ModUtil.Args.Drop( n, ... ) return table.unpack( args, n + 1, args.n ) end -function ModUtil.Table.Map( tableArg, mapFunc ) +function ModUtil.Table.Map( tbl, map ) local out = { } - for k, v in pairs( tableArg ) do - out[ k ] = mapFunc( v ) + for k, v in pairs( tbl ) do + out[ k ] = map( v ) end return out end -function ModUtil.Table.Mutate( tableArg, mapFunc ) - for k, v in pairs( tableArg ) do - tableArg[ k ] = mapFunc( v ) +function ModUtil.Table.Mutate( tbl, map ) + for k, v in pairs( tbl ) do + tbl[ k ] = map( v ) end end @@ -445,7 +442,7 @@ function ModUtil.Table.UnKeyed( tableArg ) end function ModUtil.String.Join( sep, ... ) - local out = {} + local out = { } local args = table.pack( ... ) out[ 1 ] = args[ 1 ] for i = 2, args.n do @@ -478,8 +475,8 @@ end -- String Representations -ModUtil.ToString = ModUtil.Callable.Set( { }, function( o ) - local identifier = ModUtil.Identifiers.Data[ o ] +ModUtil.ToString = ModUtil.Callable.Set( { }, function( _, o ) + local identifier = o ~= nil and ModUtil.Identifiers.Data[ o ] identifier = identifier and identifier .. ":" or "" return identifier .. ModUtil.ToString.Static( o ) end ) @@ -550,7 +547,7 @@ function ModUtil.ToString.Shallow( o ) end end -ModUtil.ToString.Deep = ModUtil.Callable.Set( { }, function( o, seen ) +ModUtil.ToString.Deep = ModUtil.Callable.Set( { }, function( _, o, seen ) seen = seen or { } if type( o ) == "table" and not seen[ o ] then seen[ o ] = true @@ -623,7 +620,7 @@ end -- Print -ModUtil.Print = ModUtil.Callable.Set( { }, function ( ... ) +ModUtil.Print = ModUtil.Callable.Set( { }, function ( _, ... ) print( ... ) if DebugPrint then ModUtil.Print.Debug( ... ) end if io then @@ -777,7 +774,7 @@ function ModUtil.Array.Join( a, ... ) return ModUtil.Array.Join( c, ModUtil.Args.Drop( 1, ... ) ) end -ModUtil.Table.Copy = ModUtil.Callable.Set( { }, function( t ) +ModUtil.Table.Copy = ModUtil.Callable.Set( { }, function( _, t ) c = { } for k, v in pairs( t ) do c[ k ] = v @@ -1247,7 +1244,7 @@ ModUtil.Metatables.UpValues = { end } -ModUtil.UpValues = ModUtil.Callable.Set( { }, function( func ) +ModUtil.UpValues = ModUtil.Callable.Set( { }, function( _, func ) if type( func ) ~= "function" then func = debug.getinfo( ( func or 1 ) + 1, "f" ).func end @@ -1526,7 +1523,7 @@ ModUtil.Metatables.Locals = { end } -ModUtil.Locals = ModUtil.Callable.Set( { }, function( level ) +ModUtil.Locals = ModUtil.Callable.Set( { }, function( _, level ) return ModUtil.Proxy( { level = ModUtil.StackLevel( ( level or 1 ) + 1 ) }, ModUtil.Metatables.Locals ) end ) @@ -1759,7 +1756,7 @@ ModUtil.Metatables.Entangled.Union = { } -ModUtil.Entangled.Union = ModUtil.Callable.Set( { }, function( ... ) +ModUtil.Entangled.Union = ModUtil.Callable.Set( { }, function( _, ... ) local keys, members = { }, toLookup{ ... } local union = { Reserve = { }, Keys = keys, Members = members } for t in pairs( members ) do @@ -2019,7 +2016,7 @@ ModUtil.Metatables.Context = { end } -ModUtil.Context = ModUtil.Callable.Set( { }, function( prepContext, postCall ) +ModUtil.Context = ModUtil.Callable.Set( { }, function( _, prepContext, postCall ) return ModUtil.Proxy( { prepContext = prepContext, postCall = postCall }, ModUtil.Metatables.Context ) end ) @@ -2053,7 +2050,7 @@ ModUtil.Context.Call = ModUtil.Context( end ) -ModUtil.Context.Wrap = ModUtil.Callable.Set( { }, function( func, context, mod ) +ModUtil.Context.Wrap = ModUtil.Callable.Set( { }, function( _, func, context, mod ) return ModUtil.Wrap( func, function( base, ... ) ModUtil.Context.Call( base, context, ... ) end, mod ) end ) @@ -2114,12 +2111,10 @@ ModUtil.Node.Data.Meta = { ModUtil.Node.Data.Call = { New = function( obj ) - local _, call = ModUtil.Callable.Get( obj ) - return call or error( "node new rejected, new call nodes are not meaningfully mutable.", 2 ) + return ModUtil.Callable.Func.Get( obj ) or error( "node new rejected, new call nodes are not meaningfully mutable.", 2 ) end, Get = function( obj ) - local _, call = ModUtil.Callable.Get( obj ) - return call + return ModUtil.Callable.Func.Get( obj ) end, Set = function( obj, value ) ModUtil.Callable.Set( ModUtil.Callable.Get( obj ), value ) @@ -2155,17 +2150,20 @@ ModUtil.Mods.Data.ModUtil = ModUtil -- Function Wrapping, Decoration, Overriding, Referral -local decorators = { } -setmetatable( decorators, { __mode = "k" } ) -local overrides = { } -setmetatable( overrides, { __mode = "k" } ) +local decorators = setmetatable( { }, { __mode = "k" } ) +local overrides = setmetatable( { }, { __mode = "k" } ) local function wrapDecorator( wrap ) - return function( base ) return function( ... ) return wrap( base, ... ) end end + return function( base ) + return function( ... ) return wrap( base, ... ) end + end end -ModUtil.Decorate = ModUtil.Callable.Set( { }, function( base, func, mod ) +ModUtil.Decorate = ModUtil.Callable.Set( { }, function( _, base, func, mod ) local out = func( base ) + if decorators[ out ] then + error( "decorator produced duplicate reference", 2 ) + end decorators[ out ] = { Base = base, Func = func, Mod = mod } return out end ) @@ -2199,6 +2197,9 @@ function ModUtil.Decorate.Refresh( obj ) end function ModUtil.Override( base, value, mod ) + if overrides[ value ] then + error( "cannot override with existing reference", 2 ) + end local node, parent = base while decorators[ node ] do parent = node From ca938bd3ecb3375837736d2d89fa1404301decf1 Mon Sep 17 00:00:00 2001 From: Andre Issa Date: Wed, 1 Sep 2021 07:03:36 +1000 Subject: [PATCH 32/32] fix subtable data --- ModUtil.Main.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/ModUtil.Main.lua b/ModUtil.Main.lua index fe042e1..dabe274 100644 --- a/ModUtil.Main.lua +++ b/ModUtil.Main.lua @@ -93,6 +93,7 @@ local function modDataPlain( obj, key, value, level ) for k, v in pairs( value ) do modDataPlain( value, k, v, level ) end + obj[ key ] = value else error( "saved data tables cannot have values of type "..t..".", level ) end