diff --git a/7z.dll b/7z.dll deleted file mode 100644 index b028a37..0000000 Binary files a/7z.dll and /dev/null differ diff --git a/7z.exe b/7z.exe deleted file mode 100644 index 6a34fc6..0000000 Binary files a/7z.exe and /dev/null differ diff --git a/README.md b/README.md index ee7fda9..d07e17c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ Mod Manager for Grocery Store Simulator built using Godot. Fork the repository and apply changes in Godot. After you're done making changes, you can make a pull request. +To test you will need the latest release, unzip it and grab 7z.exe, 7z.dll, mod folder, UE4SS folder. +Then put it into where you built your release. + # How to use After downloading, open the gss-mod-manager.exe and select your game folder (if not automatically detected). After selecting the game folder you should see if you have installed the mod loader and if you have any mods. diff --git a/UE4SS/Mods/ActorDumperMod/Scripts/main.lua b/UE4SS/Mods/ActorDumperMod/Scripts/main.lua deleted file mode 100644 index e6f6c55..0000000 --- a/UE4SS/Mods/ActorDumperMod/Scripts/main.lua +++ /dev/null @@ -1,20 +0,0 @@ -RegisterCustomProperty({ - ["Name"] = "Actors", - ["Type"] = PropertyTypes.ArrayProperty, - ["BelongsToClass"] = "/Script/Engine.Level", - ["OffsetInternal"] = 0x98, - ["ArrayProperty"] = { - ["Type"] = PropertyTypes.ObjectProperty - } -}) - -RegisterKeyBind(Key.NUM_THREE, {ModifierKey.CONTROL}, function() - local Level = FindFirstOf("Level") - local Actors = Level.Actors - - Actors:ForEach(function(Index, ElemWrapper) - local Actor = ElemWrapper:get() - - print(string.format("0x%X %s\n", Actor:GetAddress(), Actor:GetFullName())) - end) -end) diff --git a/UE4SS/Mods/BPML_GenericFunctions/Scripts/main.lua b/UE4SS/Mods/BPML_GenericFunctions/Scripts/main.lua deleted file mode 100644 index 7e8017d..0000000 --- a/UE4SS/Mods/BPML_GenericFunctions/Scripts/main.lua +++ /dev/null @@ -1,67 +0,0 @@ ---[[ - This is a mod where all BP functions available to BP mods goes. - Only functions that don't need any information from BPModLoader goes in here. -]] - -local VerboseLogging = true - -local function Log(Message, AlwaysLog) - if not VerboseLogging and not AlwaysLog then return end - print(Message) -end - --- Explodes a string by a delimiter into a table -local function Explode(String, Delimiter) - local ExplodedString = {} - local Iterator = 1 - local DelimiterFrom, DelimiterTo = string.find(String, Delimiter, Iterator) - - while DelimiterTo do - table.insert(ExplodedString, string.sub(String, Iterator, DelimiterFrom-1)) - Iterator = DelimiterTo + 1 - DelimiterFrom, DelimiterTo = string.find(String, Delimiter, Iterator) - end - table.insert(ExplodedString, string.sub(String, Iterator)) - - return ExplodedString -end - -RegisterCustomEvent("PrintToModLoader", function(ParamContext, ParamMessage) - -- Retrieve the param value from the param container. - local Message = ParamMessage:get() - - -- We must do type-checking here! - -- This is to guard against mods that don't use the correct params for their custom event. - -- There's no way to avoid it. - if Message:type() ~= "FString" then error(string.format("PrintToModLoader Param #1 must be FString but was %s", Message:type())) end - - -- Now the 'Message' param is validated and we're safe to use it. - local NameParts = Explode(ParamContext:get():GetClass():GetFullName(), "/"); - local ModName = NameParts[#NameParts - 1] - Log(string.format("[%s] %s\n", ModName, Message:ToString())) -end) - -local UClassStaticRef = nil -RegisterCustomEvent("ConstructPersistentObject", function(ParamContext, ParamClass, OutParam) - -- Param Type Checking - local Class = ParamClass:get() - if not Class:IsValid() then error("ConstructPersistentObject Param #1 must be a valid UClass") end - if not UClassStaticRef then - UClassStaticRef = StaticFindObject("/Script/CoreUObject.Class") - end - if not UClassStaticRef:IsValid() then error("ConstructPersistentObject could not find /Script/CoreUObject.Class") end - if not Class:IsA(UClassStaticRef) then error("ConstructPersistentObject Param #1 must be a UClass or UClass derivative") end - local OutValue = OutParam:get() - if not OutValue:type() == "UObject" then error("ConstructPersistentObject Return Value must be a UObject") end - - -- Function Logic - local GameInstance = FindFirstOf("GameInstance") - local GarbageCollectionKeepFlags = 0x0E000000 - local PersistentObject = StaticConstructObject(Class, GameInstance, 0, 0, GarbageCollectionKeepFlags, false, false, nil, nil, nil) - if not PersistentObject:IsValid() then - Log(string.format("Was unable to construct persistent object: %s", Class:GetFullName())) - end - - -- Return Value - OutParam:set(PersistentObject) -end) diff --git a/UE4SS/Mods/BPModLoaderMod/Scripts/main.lua b/UE4SS/Mods/BPModLoaderMod/Scripts/main.lua deleted file mode 100644 index bfc07b8..0000000 --- a/UE4SS/Mods/BPModLoaderMod/Scripts/main.lua +++ /dev/null @@ -1,279 +0,0 @@ -local UEHelpers = require("UEHelpers") - -local VerboseLogging = false - -local function Log(Message, OnlyLogIfVerbose) - if not VerboseLogging and OnlyLogIfVerbose then return end - print(Message) -end - -package.path = '.\\Mods\\ModLoaderMod\\?.lua;' .. package.path -package.path = '.\\Mods\\ModLoaderMod\\BPMods\\?.lua;' .. package.path - -local Mods = {} -local OrderedMods = {} - --- Contains mod names from Mods/BPModLoaderMod/load_order.txt and is used to determine the load order of BP mods. -local ModOrderList = {} - -local DefaultModConfig = {} -DefaultModConfig.AssetName = "ModActor_C" -DefaultModConfig.AssetNameAsFName = UEHelpers.FindOrAddFName("ModActor_C") - --- Checks if the beginning of a string contains a certain pattern. -local function StartsWith(String, StringToCompare) - return string.sub(String,1,string.len(StringToCompare))==StringToCompare -end - -local function FileExists(file) - local f = io.open(file, "rb") - if f then f:close() end - return f ~= nil -end - --- Reads lines from the specified file and returns a table of lines read. --- Second argument takes a string that can be used to exclude lines starting with that string. Default ; -local function LinesFrom(file, ignoreLinesStartingWith) - if not FileExists(file) then return {} end - - if ignoreLinesStartingWith == nil then - ignoreLinesStartingWith = ";" - end - - local lines = {} - for line in io.lines(file) do - if not StartsWith(line, ignoreLinesStartingWith) then - lines[#lines + 1] = line - end - end - return lines -end - --- Loads mod order data from load_order.txt and pushes it into ModOrderList. -local function LoadModOrder() - local file = 'Mods/BPModLoaderMod/load_order.txt' - local lines = LinesFrom(file) - - local entriesAdded = 0 - - for _, line in pairs(lines) do - ModAlreadyExists = false - for _, ModName in pairs(ModOrderList) do - if ModName == line then - ModAlreadyExists = true - end - end - -- Checks for double mod entries in the file and if a mod was already included, skip it. - if not ModAlreadyExists then - table.insert(ModOrderList, line) - entriesAdded = entriesAdded + 1 - end - end - - if entriesAdded <= 0 then - Log(string.format("Mods/BPModLoaderMod/load_order.txt not present or no matching mods, loading all BP mods in random order.")) - end -end - -local function SetupModOrder() - local Priority = 1 - - -- Adds priority mods first by their respective order as specified in load_order.txt - for _, ModOrderEntry in pairs(ModOrderList) do - for ModName, ModInfo in pairs(Mods) do - if type(ModInfo) == "table" then - if ModOrderEntry == ModName then - OrderedMods[Priority] = ModInfo - OrderedMods[Priority].Name = ModName - OrderedMods[Priority].Priority = Priority - Priority = Priority + 1 - end - end - end - end - - -- Adds the remaining mods in a random order after the prioritized mods. - for ModName, ModInfo in pairs(Mods) do - ModAlreadyIncluded = false - for _, OrderedModInfo in ipairs(OrderedMods) do - if type(OrderedModInfo) == "table" then - if OrderedModInfo.Name == ModName then - ModAlreadyIncluded = true - end - end - end - - if not ModAlreadyIncluded then - ModInfo.Name = ModName - table.insert(OrderedMods, ModInfo) - end - end -end - -local function LoadModConfigs() - -- Load configurations for mods. - local Dirs = IterateGameDirectories(); - if not Dirs then - error("[BPModLoader] UE4SS does not support loading mods for this game.") - end - local LogicModsDir = Dirs.Game.Content.Paks.LogicMods - if not Dirs then error("[BPModLoader] IterateGameDirectories failed, cannot load BP mod configurations.") end - if not LogicModsDir then - CreateLogicModsDirectory(); - Dirs = IterateGameDirectories(); - LogicModsDir = Dirs.Game.Content.Paks.LogicMods - if not LogicModsDir then error("[BPModLoader] Unable to find or create Content/Paks/LogicMods directory. Try creating manually.") end - end - for ModDirectoryName,ModDirectory in pairs(LogicModsDir) do - Log(string.format("Mod: %s\n", ModDirectoryName)) - for _,ModFile in pairs(ModDirectory.__files) do - Log(string.format(" ModFile: %s\n", ModFile.__name)) - if ModFile.__name == "config.lua" then - dofile(ModFile.__absolute_path) - if type(Mods[ModDirectoryName]) ~= "table" then break end - if not Mods[ModDirectoryName].AssetName then break end - Mods[ModDirectoryName].AssetNameAsFName = UEHelpers.FindOrAddFName(Mods[ModDirectoryName].AssetName) - break - end - end - end - - -- Load a default configuration for mods that didn't have their own configuration. - for _, ModFile in pairs(LogicModsDir.__files) do - local ModName = ModFile.__name - local ModNameNoExtension = ModName:match("(.+)%..+$") - local FileExtension = ModName:match("^.+(%..+)$"); - if FileExtension == ".pak" and not Mods[ModNameNoExtension] then - --Log("--------------\n") - --Log(string.format("ModFile: '%s'\n", ModFile.__name)) - --Log(string.format("ModNameNoExtension: '%s'\n", ModNameNoExtension)) - --Log(string.format("FileExtension: %s\n", FileExtension)) - Mods[ModNameNoExtension] = {} - Mods[ModNameNoExtension].AssetName = DefaultModConfig.AssetName - Mods[ModNameNoExtension].AssetNameAsFName = DefaultModConfig.AssetNameAsFName - Mods[ModNameNoExtension].AssetPath = string.format("/Game/Mods/%s/ModActor", ModNameNoExtension) - end - end - - LoadModOrder() - - SetupModOrder() -end - -LoadModConfigs() - -for _,v in ipairs(OrderedMods) do - Log(string.format("%s == %s\n", v.Name, v)) - if type(v) == "table" then - for k2,v2 in pairs(v) do - Log(string.format(" %s == %s\n", k2, v2)) - end - end -end - -local AssetRegistryHelpers = nil -local AssetRegistry = nil - -local function LoadMod(ModName, ModInfo, World) - if ModInfo.Priority ~= nil then - Log(string.format("Loading mod [Priority: #%i]: %s\n", ModInfo.Priority, ModName)) - else - Log(string.format("Loading mod: %s\n", ModName)) - end - - if ModInfo.AssetPath == nil or ModInfo.AssetPath == nil then - Log(string.format("Could not load mod '%s' because it has no asset path or name.\n", ModName)) - return - end - - local AssetData = nil - if UnrealVersion.IsBelow(5, 1) then - AssetData = { - ["ObjectPath"] = UEHelpers.FindOrAddFName(string.format("%s.%s", ModInfo.AssetPath, ModInfo.AssetName)), - } - else - AssetData = { - ["PackageName"] = UEHelpers.FindOrAddFName(ModInfo.AssetPath), - ["AssetName"] = UEHelpers.FindOrAddFName(ModInfo.AssetName), - } - end - - ExecuteInGameThread(function() - local ModClass = AssetRegistryHelpers:GetAsset(AssetData) - if not ModClass:IsValid() then - local ObjectPath = AssetData.ObjectPath and AssetData.ObjectPath:ToString() or "" - local PackageName = AssetData.PackageName and AssetData.PackageName:ToString() or "" - local AssetName = AssetData.AssetName and AssetData.AssetName:ToString() or "" - Log(string.format("ModClass for '%s' is not valid\nObjectPath: %s\nPackageName: %s\nAssetName: %s", ModName, ObjectPath,PackageName, AssetName)) - return - end - - if not World:IsValid() then Log(string.format("World is not valid for '%s' to spawn in", ModName)) return end - - local Actor = World:SpawnActor(ModClass, {}, {}) - if not Actor:IsValid() then - Log(string.format("Actor for mod '%s' is not valid\n", ModName)) - else - Log(string.format("Actor: %s\n", Actor:GetFullName())) - local PreBeginPlay = Actor.PreBeginPlay - if PreBeginPlay:IsValid() then - Log(string.format("Executing 'PreBeginPlay' for mod '%s', with path: '%s'\n", ModName, Actor:GetFullName())) - PreBeginPlay() - else - Log(string.format("PreBeginPlay not valid for mod %s\n", ModName), true) - end - end - end) -end - -local function CacheAssetRegistry() - if AssetRegistryHelpers and AssetRegistry then return end - - AssetRegistryHelpers = StaticFindObject("/Script/AssetRegistry.Default__AssetRegistryHelpers") - if not AssetRegistryHelpers:IsValid() then print("AssetRegistryHelpers is not valid\n") end - - if AssetRegistryHelpers then - AssetRegistry = AssetRegistryHelpers:GetAssetRegistry() - if AssetRegistry:IsValid() then return end - end - - AssetRegistry = StaticFindObject("/Script/AssetRegistry.Default__AssetRegistryImpl") - if AssetRegistry:IsValid() then return end - - error("AssetRegistry is not valid\n") -end - - - -local function LoadMods(World) - CacheAssetRegistry() - for _, ModInfo in ipairs(OrderedMods) do - if type(ModInfo) == "table" then - LoadMod(ModInfo.Name, ModInfo, World) - end - end -end - -local function LoadModsManual() - LoadMods(UEHelpers.GetWorld()) -end - -RegisterLoadMapPostHook(function(Engine, World) - LoadMods(World:get()) -end) - -RegisterBeginPlayPostHook(function(ContextParam) - local Context = ContextParam:get() - for _,ModConfig in ipairs(OrderedMods) do - if Context:GetClass():GetFName() ~= ModConfig.AssetNameAsFName then return end - local PostBeginPlay = Context.PostBeginPlay - if PostBeginPlay:IsValid() then - Log(string.format("Executing 'PostBeginPlay' for mod '%s'\n", Context:GetFullName())) - PostBeginPlay() - else - Log(string.format("PostBeginPlay not valid for mod %s\n", Context:GetFullName(), true)) - end - end -end) - -RegisterKeyBind(Key.INS, LoadModsManual) diff --git a/UE4SS/Mods/BPModLoaderMod/load_order.txt b/UE4SS/Mods/BPModLoaderMod/load_order.txt deleted file mode 100644 index eab75a1..0000000 --- a/UE4SS/Mods/BPModLoaderMod/load_order.txt +++ /dev/null @@ -1,2 +0,0 @@ -; You only have to include BP mods where load order matters, mods not included here will be loaded in any random order after loading the prioritized mods. -; Add your BP mods below by their name without .pak at the end, they will be loaded in top to bottom order. diff --git a/UE4SS/Mods/CheatManagerEnablerMod/Scripts/main.lua b/UE4SS/Mods/CheatManagerEnablerMod/Scripts/main.lua deleted file mode 100644 index a9a1d31..0000000 --- a/UE4SS/Mods/CheatManagerEnablerMod/Scripts/main.lua +++ /dev/null @@ -1,25 +0,0 @@ -RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(self, NewPawn) - local PlayerController = self:get() - - local CheatManagerClass = PlayerController.CheatClass - if not CheatManagerClass:IsValid() then - print("[CheatManager Creator] Controller:CheatClass is nullptr, using default CheatClass instead\n") - - CheatManagerClass = StaticFindObject("/Script/Engine.CheatManager") - end - - if not CheatManagerClass:IsValid() then - print("[CheatManager Creator] Couldn't find default CheatClass, therefore, could not enable Cheat Manager\n") - return - end - - local CreatedCheatManager = StaticConstructObject(CheatManagerClass, PlayerController, 0, 0, 0, nil, false, false, nil) - if CreatedCheatManager:IsValid() then - print(string.format("[CheatManager Creator] Constructed CheatManager [0x%X]\n", CreatedCheatManager:GetAddress())) - - PlayerController.CheatManager = CreatedCheatManager - print("[CheatManager Creator] Enabled CheatManager\n") - else - print("[CheatManager Creator] Was unable to construct CheatManager, therefor, could not enable Cheat Manager\n") - end -end) diff --git a/UE4SS/Mods/ConsoleCommandsMod/Scripts/dump_object.lua b/UE4SS/Mods/ConsoleCommandsMod/Scripts/dump_object.lua deleted file mode 100644 index 88ac1b8..0000000 --- a/UE4SS/Mods/ConsoleCommandsMod/Scripts/dump_object.lua +++ /dev/null @@ -1,316 +0,0 @@ --- This is a custom implementation of UEs "obj dump " command. --- It doesn't have a 1:1 feature set. - -local UEHelpers = require("UEHelpers") - ---[[ - TODO: Expand on the console command format. - You should be able to specify a sub-object, sub-struct, sub-array, sub-map, etc. - You do 'dump_object /Engine/Transient.GameEngine_2147482624'. - You notice '(ArrayProperty) ShaderComplexityColors=StructProperty ...'. - To get the first element, you do: 'dump_object /Engine/Transient.GameEngine_2147482624 ShaderComplexityColors 0'. - This will likely see the type-prefix (i.e. UClass /Engine/Script/...) needing to be unsupported just to simplify the code. - UPDATE: This is currently working with ArrayProperty and StructProperty. - Need to add support eventually for MapProperty when UE4SS Lua supports MapProperty. -]] - -string.padleft = function(InString, Length, PadWithChar) - -- We pad with spaces by default. - if not PadWithChar then PadWithChar = " " end - return InString .. PadWithChar:rep(Length - #InString) -end - -local OriginalLog = Log -local Buffer = "" -function Log(Message) - Buffer = string.format("%s%s\n", Buffer, Message) - OriginalLog(Message) -end - -local UClassStaticClass = StaticFindObject("/Script/CoreUObject.Class") -local UScriptStructStaticClass = StaticFindObject("/Script/CoreUObject.ScriptStruct") -local UEnumStaticClass = StaticFindObject("/Script/CoreUObject.Enum") -local UPropertyStaticClass = StaticFindObject("/Script/CoreUObject.Property") - -local DumpPropertyWithinObject = nil -local DumpObject = nil - -DumpPropertyWithinObject = function(Object, Property, DumpRecursively) - local ValueStr = "" - - -- Cannot resolve the value here because of unhandled types. - if Property:IsA(PropertyTypes.Int8Property) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value) - elseif Property:IsA(PropertyTypes.Int16Property) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value) - elseif Property:IsA(PropertyTypes.IntProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value) - elseif Property:IsA(PropertyTypes.Int64Property) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value) - elseif Property:IsA(PropertyTypes.NameProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value:ToString()) - elseif Property:IsA(PropertyTypes.FloatProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value) - elseif Property:IsA(PropertyTypes.StrProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value:ToString()) - elseif Property:IsA(PropertyTypes.ByteProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value) - elseif Property:IsA(PropertyTypes.ArrayProperty) then - local Value = Object[Property:GetFName():ToString()] - local Inner = Property:GetInner() - - -- Inner Type - if Inner:IsA(PropertyTypes.StructProperty) then - ValueStr = string.format("%s\n", Inner:GetStruct():GetFullName()) - else - ValueStr = string.format("%s\n", Inner:GetFullName()) - end - - -- Size & Capacity - if Value:GetArrayNum() == 0 then - ValueStr = string.format("%s ---empty---", ValueStr) - else - ValueStr = string.format("%s %i/%i", ValueStr, Value:GetArrayNum(), Value:GetArrayMax()) - end - - -- Inner Value - if Value:GetArrayNum() > 0 then - ValueStr = string.format("%s\n", ValueStr) - if Inner:IsA(PropertyTypes.ObjectProperty) then - Value:ForEach(function(Index, Elem) - ValueStr = string.format("%s [%i]: %s\n", ValueStr, Index - 1, Elem:get():GetFullName()) - end) - end - end - elseif Property:IsA(PropertyTypes.MapProperty) then - ValueStr = "UNHANDLED_VALUE" - elseif Property:IsA(PropertyTypes.StructProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value:GetFullName()) - if DumpRecursively then - DumpObject(Value) - end - elseif Property:IsA(PropertyTypes.ClassProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value:GetFullName()) - elseif Property:IsA(PropertyTypes.WeakObjectProperty) then - --local Value = Object[Property:GetFName():ToString()] - ValueStr = "UNHANDLED_VALUE" - elseif Property:IsA(PropertyTypes.EnumProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s(%s)", Property:GetEnum():GetNameByValue(Value):ToString(), Value) - elseif Property:IsA(PropertyTypes.TextProperty) then - local Value = Object[Property:GetFName():ToString()] - ValueStr = string.format("%s", Value:ToString()) - elseif Property:IsA(PropertyTypes.ObjectProperty) then - local Value = Object[Property:GetFName():ToString()] - if DumpRecursively then - DumpObject(Value) - else - ValueStr = string.format("%s", Value:GetFullName()) - end - elseif Property:IsA(PropertyTypes.BoolProperty) then - local Value = Object[Property:GetFName():ToString()] - local FieldMask = Property:GetFieldMask() - if FieldMask == 255 then - ValueStr = string.format("%s", (Value and "True" or "False")) - else - ValueStr = string.format("%s (FM: 0x%X, BM: 0x%X)", (Value and "True" or "False"), FieldMask, Property:GetByteMask()) - end - else - ValueStr = "UNHANDLED_VALUE" - end - - return string.format("0x%04X %s %s=%s", Property:GetOffset_Internal(), Property:GetClass():GetFName():ToString(), Property:GetFName():ToString(), ValueStr) -end - -local function GetObjectByName(ObjectName) - local Object = nil - if FPackageName.IsShortPackageName(ObjectName) then - Object = FindObject(nil, ObjectName, nil, nil) - else - Object = FindObject(nil, nil, ObjectName, false) - end - return Object -end - -local function GetPropertyByName(ObjectIn, PropertyName) - local PropertyFName = UEHelpers.FindOrAddFName(PropertyName) - local Object = nil - - if ObjectIn:IsA(UClassStaticClass) or ObjectIn:IsA(UScriptStructStaticClass) then - Object = ObjectIn - else - Object = ObjectIn:GetClass() - end - - local PropertyFound = nil - while Object:IsValid() do - Object:ForEachProperty(function(Property) - if Property:GetFName():Equals(PropertyFName) then - PropertyFound = Property - return true - end - end) - Object = Object:GetSuperStruct() - end - - return PropertyFound -end - -DumpObject = function(Object) - Log(string.format("*** Property dump for object '%s ***", Object:GetFullName())) - - -- Lets make sure that this is an object type that can be dumped. - local IsClassCompatible = false - if Object:IsA(UClassStaticClass) then IsClassCompatible = true end - local IsUScriptStruct = Object:IsA(UScriptStructStaticClass) - if IsUScriptStruct and not Object:IsMappedToObject() then IsClassCompatible = true end - - if IsClassCompatible then - -- A UClass or UScriptStruct. - local Class = Object - while Class and Class:IsValid() do - Log(string.format("=== %s properties ===", Class:GetFullName())) - Class:ForEachProperty(function(Property) - local OutputBuffer = string.format("0x%04X %s %s", Property:GetOffset_Internal(), Property:GetClass():GetFName():ToString(), Property:GetFName():ToString()) - if Property:IsA(PropertyTypes.ObjectProperty) then - OutputBuffer = string.format("%s (%s)", OutputBuffer, Property:GetPropertyClass():GetFullName()) - elseif Property:IsA(PropertyTypes.BoolProperty) then - local FieldMask = Property:GetFieldMask() - if FieldMask ~= 255 then - OutputBuffer = string.format("%s (FM: 0x%X, BM: 0x%X)", OutputBuffer, FieldMask, Property:GetByteMask()) - end - end - Log(OutputBuffer) - end) - - Class = Class:GetSuperStruct() - end - elseif Object:IsA(UEnumStaticClass) then - Object:ForEachName(function(Name, Value) - Log(string.format("%s (%i)", Name:ToString(), Value)) - end) - elseif not Object:IsA(UPropertyStaticClass) then - -- A UObject that isn't a UClass, UScriptStruct, or UProperty (<4.25 only) - local ObjectClass = nil - if IsUScriptStruct then - ObjectClass = Object - else - ObjectClass = Object:GetClass() - end - while ObjectClass and ObjectClass:IsValid() do - Log(string.format("=== %s ===", ObjectClass:GetFullName())) - ObjectClass:ForEachProperty(function(Property) - Log(DumpPropertyWithinObject(Object, Property)) - end) - - ObjectClass = ObjectClass:GetSuperStruct() - end - end -end - -local State = { - ["StoreObjectContext"] = 1, - ["FindProperty"] = 2, - ["FoundObject"] = 3, - ["FoundProperty"] = 4, -} - -local ObjectContext = nil -local PropertyContext = nil -local CurrentState = State.StoreObjectContext - -function ExecStateMachine(Param) - if CurrentState == State.StoreObjectContext then - if not Param or Param == "" or Param == " " then - Log("No object name supplied") - return true - else - ObjectContext = GetObjectByName(Param) - if (ObjectContext:IsA(UScriptStructStaticClass)) or (ObjectContext and ObjectContext:IsValid()) then - CurrentState = State.FindProperty - else - Log(string.format("No class found with name %s", Param)) - return true - end - end - elseif CurrentState == State.FindProperty then - PropertyContext = GetPropertyByName(ObjectContext, Param) - if PropertyContext and PropertyContext:IsValid() then - if PropertyContext:IsA(PropertyTypes.ObjectProperty) then - --CurrentState = State.FindProperty - --return ExecStateMachine(Param) - end - CurrentState = State.FoundProperty - else - Log(string.format("Property '%s' not found in '%s'", Param, ObjectContext:GetFullName())) - return true - end - elseif CurrentState == State.FoundProperty then - if PropertyContext:IsA(PropertyTypes.ArrayProperty) then - PropertyContext = PropertyContext:GetInner() - ObjectContext = ObjectContext[PropertyContext:GetFName():ToString()] - - local ArrayIndex = tonumber(Param) - if not ArrayIndex then - Log(string.format("Value '%s' is not a valid array index", Param)) - return true - elseif ObjectContext:GetArrayNum() < ArrayIndex + 1 then - Log(string.format("Array index '%i' out of bounds.", ArrayIndex)) - return true - else - ObjectContext = ObjectContext[ArrayIndex + 1] - CurrentState = State.FindProperty - return false - end - end - - ObjectContext = ObjectContext[PropertyContext:GetFName():ToString()] - CurrentState = State.FindProperty - return ExecStateMachine(Param) - end -end - -RegisterConsoleCommandHandler("dump_object", function(FullCommand, Parameters, Ar) - ObjectContext = nil - PropertyContext = nil - CurrentState = State.StoreObjectContext - - if #Parameters < 1 then return false end - local ShouldSaveToFile = Parameters[1]:find(".txt") - if ShouldSaveToFile and #Parameters < 2 then return false end - - GlobalAr = Ar - - for i = ShouldSaveToFile and 2 or 1, #Parameters, 1 do - local Param = Parameters[i] - if ExecStateMachine(Param) then - Buffer = "" - return true - end - end - - if CurrentState == State.FoundProperty then - Log(DumpPropertyWithinObject(ObjectContext, PropertyContext, true)) - else - DumpObject(ObjectContext) - end - - if ShouldSaveToFile then - local File = io.open(Parameters[1], "w+") - File:write(Buffer) - File:close() - - end - Buffer = "" - return true -end) diff --git a/UE4SS/Mods/ConsoleCommandsMod/Scripts/main.lua b/UE4SS/Mods/ConsoleCommandsMod/Scripts/main.lua deleted file mode 100644 index d86a513..0000000 --- a/UE4SS/Mods/ConsoleCommandsMod/Scripts/main.lua +++ /dev/null @@ -1,12 +0,0 @@ -GlobalAr = nil - -function Log(Message) - print(Message .. "\n") - if type(GlobalAr) == "userdata" and GlobalAr:type() == "FOutputDevice" then - GlobalAr:Log(Message) - end -end - -require("summon_unloaded_assets") -require("set") -require("dump_object") \ No newline at end of file diff --git a/UE4SS/Mods/ConsoleCommandsMod/Scripts/set.lua b/UE4SS/Mods/ConsoleCommandsMod/Scripts/set.lua deleted file mode 100644 index d23929a..0000000 --- a/UE4SS/Mods/ConsoleCommandsMod/Scripts/set.lua +++ /dev/null @@ -1,49 +0,0 @@ -RegisterConsoleCommandHandler("set", function(FullCommand, Parameters, Ar) - -- If we have no parameters then just let someone else handle this command - if #Parameters < 3 then return false end - - GlobalAr = Ar - - local ClassOrObjectName = Parameters[1] - local PropertyName = Parameters[2] - local NewPropertyValue = Parameters[3] - - local BannedFlags = EObjectFlags.RF_ClassDefaultObject | EObjectFlags.RF_ArchetypeObject - - if not ClassOrObjectName or ClassOrObjectName == "" or ClassOrObjectName == " " then - Log("No class or object name supplied") - return true - end - - local ObjectOrClass = FindObject(nil, ClassOrObjectName, nil, BannedFlags) - if not ObjectOrClass:IsValid() then - Log(string.format("Unrecognized class or object %s", ClassOrObjectName)) - return true - end - - -- Replace with a call to "IsA" when it exists - if (ObjectOrClass:IsClass()) then - local Property = ObjectOrClass:Reflection():GetProperty(PropertyName) - if Property:IsValid() then - local Objects = FindObjects(0, ObjectOrClass, nil, nil, BannedFlags, false) - for ObjectNum, Object in pairs(Objects) do - Property:ImportText(NewPropertyValue, Property:ContainerPtrToValuePtr(Object), 0, Object) - end - - if #Objects == 0 then - Log(string.format("No objects found with class %s", ClassOrObjectName)) - end - else - Log(string.format("Unrecognized property %s on class %s", PropertyName, ClassOrObjectName)) - end - else - local Property = ObjectOrClass:Reflection():GetProperty(PropertyName) - if Property:IsValid() then - Property:ImportText(NewPropertyValue, Property:ContainerPtrToValuePtr(ObjectOrClass), 0, ObjectOrClass) - else - Log(string.format("Unrecognized property %s on class %s", PropertyName, ClassOrObjectName)) - end - end - - return true -end) diff --git a/UE4SS/Mods/ConsoleCommandsMod/Scripts/summon_unloaded_assets.lua b/UE4SS/Mods/ConsoleCommandsMod/Scripts/summon_unloaded_assets.lua deleted file mode 100644 index ae3431b..0000000 --- a/UE4SS/Mods/ConsoleCommandsMod/Scripts/summon_unloaded_assets.lua +++ /dev/null @@ -1,11 +0,0 @@ -RegisterConsoleCommandHandler("summon", function(FullCommand, Parameters) - -- If we have no parameters then just let someone else handle this command - if #Parameters < 1 then return false end - - LoadAsset(Parameters[1]) - - -- Return true if this is the final handler for this command - -- Return false if you want another handler to be able to handle this command - -- In this case, we want the CheatManager to also handle this command - return false -end) \ No newline at end of file diff --git a/UE4SS/Mods/ConsoleEnablerMod/Scripts/main.lua b/UE4SS/Mods/ConsoleEnablerMod/Scripts/main.lua deleted file mode 100644 index f78e7d4..0000000 --- a/UE4SS/Mods/ConsoleEnablerMod/Scripts/main.lua +++ /dev/null @@ -1,55 +0,0 @@ -local Engine = FindFirstOf("Engine") -local PlayerControllerHookActive = false -local WasFirstConsoleCreated = false - -local function RemapConsoleKeys() - -- Change console key - local InputSettings = StaticFindObject("/Script/Engine.Default__InputSettings") - if not InputSettings:IsValid() then print("[ConsoleEnabler] InputSettings not found, could not change console key\n") return end - - local ConsoleKeys = InputSettings.ConsoleKeys - - -- This sets the first console key to F10 - ConsoleKeys[1].KeyName = FName("F10", EFindName.FNAME_Find) - - ConsoleKeys:ForEach(function(index, elem_wrapper) - local KeyStruct = elem_wrapper:get() - local KeyFName = KeyStruct.KeyName - -- The ToString() call here will go bad if the FName is not ansi - print(string.format("[ConsoleEnabler] ConsoleKey[%d]: %s\n", index, KeyFName:ToString())) - end) -end - -local function CreateConsole() - if not Engine:IsValid() then - Engine = FindFirstOf("Engine") - end - - if not Engine:IsValid() then print("[ConsoleEnabler] Was unable to find an instance of UEngine\n") return end - - local ConsoleClass = Engine.ConsoleClass - local GameViewport = Engine.GameViewport - - if GameViewport.ViewportConsole:IsValid() then - -- Console already exists, let's just remap the keys - RemapConsoleKeys() - elseif ConsoleClass:IsValid() and GameViewport:IsValid() then - local CreatedConsole = StaticConstructObject(ConsoleClass, GameViewport, 0, 0, 0, nil, false, false, nil) - GameViewport.ViewportConsole = CreatedConsole - - PlayerControllerHookActive = true - WasFirstConsoleCreated = true - - RemapConsoleKeys() - else - print("ConsoleClass, GameViewport, or ViewportConsole is invalid\n") - end -end - -CreateConsole() - -NotifyOnNewObject("/Script/Engine.PlayerController", function(CreatedObject) - if PlayerControllerHookActive or not WasFirstConsoleCreated then - CreateConsole() - end -end) diff --git a/UE4SS/Mods/Keybinds/Scripts/main.lua b/UE4SS/Mods/Keybinds/Scripts/main.lua deleted file mode 100644 index a2a2188..0000000 --- a/UE4SS/Mods/Keybinds/Scripts/main.lua +++ /dev/null @@ -1,208 +0,0 @@ ---[[ - This file contains bindings for all built-in tools. - If you have a legacy bindings mod (listed below) then the binding in that mod takes precedence. - - List of legacy bindings mods: - ObjectDumperMod - CXXHeaderGeneratorMod - UHTCompatibleHeaderGeneratorMod - - You can modify the configuration below if you're not happy with the default key bindings. - Valid keys and modifier keys can be found at the bottom of this file. ---]] -Keybinds = { - ["ObjectDumper"] = {["Key"] = Key.J, ["ModifierKeys"] = {ModifierKey.CONTROL}}, - ["CXXHeaderGenerator"] = {["Key"] = Key.H, ["ModifierKeys"] = {ModifierKey.CONTROL}}, - ["UHTCompatibleHeaderGenerator"] = {["Key"] = Key.NUM_NINE, ["ModifierKeys"] = {ModifierKey.CONTROL}}, - ["DumpStaticMeshes"] = {["Key"] = Key.NUM_EIGHT, ["ModifierKeys"] = {ModifierKey.CONTROL}}, - ["DumpAllActors"] = {["Key"] = Key.NUM_SEVEN, ["ModifierKeys"] = {ModifierKey.CONTROL}}, - ["DumpUSMAP"] = {["Key"] = Key.NUM_SIX, ["ModifierKeys"] = {ModifierKey.CONTROL}}, -} - --- Logic, DO NOT CHANGE! -local function RegisterKey(KeyBindName, Callable) - if (Keybinds[KeyBindName] and not IsKeyBindRegistered(Keybinds[KeyBindName].Key, Keybinds[KeyBindName].ModifierKeys)) then - RegisterKeyBindAsync(Keybinds[KeyBindName].Key, Keybinds[KeyBindName].ModifierKeys, Callable) - end -end - -RegisterKey("ObjectDumper", function() DumpAllObjects() end) -RegisterKey("CXXHeaderGenerator", function() GenerateSDK() end) -RegisterKey("UHTCompatibleHeaderGenerator", function() GenerateUHTCompatibleHeaders() end) -RegisterKey("DumpStaticMeshes", function() DumpStaticMeshes() end) -RegisterKey("DumpAllActors", function() DumpAllActors() end) -RegisterKey("DumpUSMAP", function() DumpUSMAP() end) - ---[[ - Valid keys: - LEFT_MOUSE_BUTTON - RIGHT_MOUSE_BUTTON - CANCEL - MIDDLE_MOUSE_BUTTON - XBUTTON_ONE - XBUTTON_TWO - BACKSPACE - TAB - CLEAR - RETURN - PAUSE - CAPS_LOCK - IME_KANA - IME_HANGUEL - IME_HANGUL - IME_ON - IME_JUNJA - IME_FINAL - IME_HANJA - IME_KANJI - IME_OFF - ESCAPE - IME_CONVERT - IME_NONCONVERT - IME_ACCEPT - IME_MODECHANGE - SPACE - PAGE_UP - PAGE_DOWN - END - HOME - LEFT_ARROW - UP_ARROW - RIGHT_ARROW - DOWN_ARROW - SELECT - PRINT - EXECUTE - PRINT_SCREEN - INS - DEL - HELP - ZERO - ONE - TWO - THREE - FOUR - FIVE - SIX - SEVEN - EIGHT - NINE - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - LEFT_WIN - RIGHT_WIN - APPS - SLEEP - NUM_ZERO - NUM_ONE - NUM_TWO - NUM_THREE - NUM_FOUR - NUM_FIVE - NUM_SIX - NUM_SEVEN - NUM_EIGHT - NUM_NINE - MULTIPLY - ADD - SEPARATOR - SUBTRACT - DECIMAL - DIVIDE - F1 - F2 - F3 - F4 - F5 - F6 - F7 - F8 - F9 - F10 - F11 - F12 - F13 - F14 - F15 - F16 - F17 - F18 - F19 - F20 - F21 - F22 - F23 - F24 - NUM_LOCK - SCROLL_LOCK - BROWSER_BACK - BROWSER_FORWARD - BROWSER_REFRESH - BROWSER_STOP - BROWSER_SEARCH - BROWSER_FAVORITES - BROWSER_HOME - VOLUME_MUTE - VOLUME_DOWN - VOLUME_UP - MEDIA_NEXT_TRACK - MEDIA_PREV_TRACK - MEDIA_STOP - MEDIA_PLAY_PAUSE - LAUNCH_MAIL - LAUNCH_MEDIA_SELECT - LAUNCH_APP1 - LAUNCH_APP2 - OEM_ONE - OEM_PLUS - OEM_COMMA - OEM_MINUS - OEM_PERIOD - OEM_TWO - OEM_THREE - OEM_FOUR - OEM_FIVE - OEM_SIX - OEM_SEVEN - OEM_EIGHT - OEM_102 - IME_PROCESS - PACKET - ATTN - CRSEL - EXSEL - EREOF - PLAY - ZOOM - PA1 - OEM_CLEAR - - Valid modifier keys: - SHIFT - CONTROL - ALT ---]] diff --git a/UE4SS/Mods/LineTraceMod/Scripts/main.lua b/UE4SS/Mods/LineTraceMod/Scripts/main.lua deleted file mode 100644 index 2f6ab3f..0000000 --- a/UE4SS/Mods/LineTraceMod/Scripts/main.lua +++ /dev/null @@ -1,77 +0,0 @@ --- LineTrace -local UEHelpers = require("UEHelpers") - --- Importing functions to the global namespace of this mod just so that we don't have to retype 'UEHelpers.' over and over again. -local GetKismetSystemLibrary = UEHelpers.GetKismetSystemLibrary -local GetKismetMathLibrary = UEHelpers.GetKismetMathLibrary -local GetPlayerController = UEHelpers.GetPlayerController - -local IsInitialized = false - -local function Init() - if not GetKismetSystemLibrary():IsValid() then error("KismetSystemLibrary not valid\n") end - - print(string.format("KismetSystemLibrary: %s\n", GetKismetSystemLibrary():GetFullName())) - - if not GetKismetMathLibrary():IsValid() then error("KismetMathLibrary not valid\n") end - - print(string.format("KismetMathLibrary: %s\n", GetKismetMathLibrary():GetFullName())) - - IsInitialized = true -end - -Init() - -local function GetActorFromHitResult(HitResult) - if UnrealVersion:IsBelow(5, 0) then - return HitResult.Actor:Get() - else - return HitResult.HitObjectHandle.Actor:Get() - end -end - -local function GetObjectName() - if not IsInitialized then return end - local PlayerController = GetPlayerController() - local PlayerPawn = PlayerController.Pawn - local CameraManager = PlayerController.PlayerCameraManager - local StartVector = CameraManager:GetCameraLocation() - local AddValue = GetKismetMathLibrary():Multiply_VectorInt(GetKismetMathLibrary():GetForwardVector(CameraManager:GetCameraRotation()), 50000.0) - local EndVector = GetKismetMathLibrary():Add_VectorVector(StartVector, AddValue) - local TraceColor = { - ["R"] = 0, - ["G"] = 0, - ["B"] = 0, - ["A"] = 0, - } - local TraceHitColor = TraceColor - local EDrawDebugTrace_Type_None = 0 - local ETraceTypeQuery_TraceTypeQuery1 = 0 - local ActorsToIgnore = { - } - print("Doing line trace\n") - local HitResult = {} - local WasHit = GetKismetSystemLibrary():LineTraceSingle( - PlayerPawn, - StartVector, - EndVector, - ETraceTypeQuery_TraceTypeQuery1, - false, - ActorsToIgnore, - EDrawDebugTrace_Type_None, - HitResult, - true, - TraceColor, - TraceHitColor, - 0.0 - ) - - if WasHit then - HitActor = GetActorFromHitResult(HitResult) - print(string.format("HitActor: %s\n", HitActor:GetFullName())) - else - return print("Nothing hit.\n") - end -end - -RegisterKeyBind(Key.F3, GetObjectName) diff --git a/UE4SS/Mods/SplitScreenMod/Scripts/main.lua b/UE4SS/Mods/SplitScreenMod/Scripts/main.lua deleted file mode 100644 index 01a3a47..0000000 --- a/UE4SS/Mods/SplitScreenMod/Scripts/main.lua +++ /dev/null @@ -1,109 +0,0 @@ -local UEHelpers = require("UEHelpers") - --- Importing functions to the global namespace of this mod just so that we don't have to retype 'UEHelpers.' over and over again. -local GetGameplayStatics = UEHelpers.GetGameplayStatics -local GetGameMapsSettings = UEHelpers.GetGameMapsSettings - --- Set this value to true if you wish for the first controller to control player 1, or false if you want the first controller to control player 2 -local bOffsetGamepad = true - -local PlayerControllerTable = {} - -local function Init() - GetGameMapsSettings().bUseSplitscreen = true - GetGameMapsSettings().bOffsetPlayerGamepadIds = bOffsetGamepad - print(string.format("UseSplitScreen: %s\n", GetGameMapsSettings().bUseSplitscreen)) - print(string.format("OffsetPlayerGamepadIds: %s\n", GetGameMapsSettings().bOffsetPlayerGamepadIds)) - - IsInitialized = true -end - -local function CachePlayerControllers() - PlayerControllerTable = {} - local AllPlayerControllers = FindAllOf("PlayerController") or FindAllOf("Controller") - for Index, PlayerController in pairs(AllPlayerControllers) do - if PlayerController:IsValid() and PlayerController.Player:IsValid() and not PlayerController:HasAnyInternalFlags(EInternalObjectFlags.PendingKill) then - PlayerControllerTable[PlayerController.Player.ControllerId + 1] = PlayerController - end - end -end - -Init() - -local function CreatePlayer() - - print("Creating player..\n") - CachePlayerControllers() - - print(string.format("GameplayStatics: %s\n", GetGameplayStatics():GetFullName())) - ExecuteInGameThread(function() - NewController = GetGameplayStatics():CreatePlayer(PlayerControllerTable[1], #PlayerControllerTable, true) - end) - if NewController:IsValid() then - table.insert(PlayerControllerTable, NewController) - print(string.format("Player %s created.\n", #PlayerControllerTable)) - else - print("Player could not be created.\n") - end - -end - -function DestroyPlayer() - - -- The caller is caching the player controllers so that it can output that the correct player is being destroyed. - CachePlayerControllers() - - if #PlayerControllerTable == 1 then - print("Player could not be destroyed, only 1 player exists.\n") - return - end - print(string.format("GameplayStatics: %s\n", GetGameplayStatics():GetFullName())) - - local ControllerToRemove = PlayerControllerTable[#PlayerControllerTable] - print(string.format("Removing %s\n", ControllerToRemove:GetFullName())) - if not ControllerToRemove:IsValid() then print("PlayerController to be removed is not valid.\nPlayerController could not be destroyed.\n") return end - - ExecuteInGameThread(function() - GetGameplayStatics():RemovePlayer(ControllerToRemove, true) - end) -end - -function TeleportPlayers() - - CachePlayerControllers() - - if #PlayerControllerTable == 1 then - print("Players could not be teleported, only 1 player exists.\n") - return - end - - local DidTeleport = false - - print(string.format("Attempting to Teleport to Player 1..\n")) - - ExecuteInGameThread(function() - PlayerPawn = PlayerControllerTable[1].Pawn - PlayerPawnLocationVec = PlayerPawn.RootComponent:K2_GetComponentLocation() - PlayerPawnLocationRot = PlayerPawn.RootComponent:K2_GetComponentRotation() - local HitResult = {} - for i, EachPlayerController in ipairs(PlayerControllerTable) do - if i > 1 and EachPlayerController.Pawn:IsValid() then - EachPlayerController.Pawn:K2_SetActorLocationAndRotation(PlayerPawnLocationVec, PlayerPawnLocationRot, false, HitResult, false) - DidTeleport = true - end - end - end) - - if DidTeleport then - print("Players teleport to Player 1.\n") - else - print("No players could be teleported\n") - end -end - - -RegisterKeyBind(Key.Y, {ModifierKey.CONTROL}, CreatePlayer) - -RegisterKeyBind(Key.U, {ModifierKey.CONTROL}, DestroyPlayer) - -RegisterKeyBind(Key.I, {ModifierKey.CONTROL}, TeleportPlayers) diff --git a/UE4SS/Mods/jsbLuaProfilerMod/Scripts/main.lua b/UE4SS/Mods/jsbLuaProfilerMod/Scripts/main.lua deleted file mode 100644 index b61795b..0000000 --- a/UE4SS/Mods/jsbLuaProfilerMod/Scripts/main.lua +++ /dev/null @@ -1,15 +0,0 @@ -local jsb = require "jsbProfi" - --- jsb.simpleBenchMulti("test123", 50, print, "testing") - --- jsb.simpleBench("looptest", ForEachUObject, function(Object, ChunkIndex, ObjectIndex) --- print(string.format("Chunk: %X | Object: %X | Name: %s\n", ChunkIndex, ObjectIndex, Object:GetFullName())) --- end) - --- jsb.profile(15, "testing vm_hook") - --- ForEachUObject( function(Object, ChunkIndex, ObjectIndex) --- print(string.format("Chunk: %X | Object: %X | Name: %s\n", ChunkIndex, ObjectIndex, Object:GetFullName())) --- end) - --- for i = 1, 50 do print("TEST"..i) end \ No newline at end of file diff --git a/UE4SS/Mods/mods.txt b/UE4SS/Mods/mods.txt deleted file mode 100644 index 34551b6..0000000 --- a/UE4SS/Mods/mods.txt +++ /dev/null @@ -1,15 +0,0 @@ -CheatManagerEnablerMod : 1 -ActorDumperMod : 0 -ConsoleCommandsMod : 1 -ConsoleEnablerMod : 1 -SplitScreenMod : 0 -LineTraceMod : 0 -BPModLoaderMod : 1 -BPML_GenericFunctions : 1 -jsbLuaProfilerMod : 0 - - - - -; Built-in keybinds, do not move up! -Keybinds : 1 diff --git a/UE4SS/Mods/shared/UEHelpers/UEHelpers.lua b/UE4SS/Mods/shared/UEHelpers/UEHelpers.lua deleted file mode 100644 index da209e3..0000000 --- a/UE4SS/Mods/shared/UEHelpers/UEHelpers.lua +++ /dev/null @@ -1,103 +0,0 @@ -local UEHelpers = {} --- Uncomment the below require to use the Lua VM profiler on these functions --- local jsb = require "jsbProfi" - --- Version 1 does not exist, we start at version 2 because the original version didn't have a version at all. -local Version = 2 - --- Functions local to this module, do not attempt to use! -local CacheDefaultObject = function(ObjectFullName, VariableName, ForceInvalidateCache) - local DefaultObject - - if not ForceInvalidateCache then - DefaultObject = ModRef:GetSharedVariable(VariableName) - if DefaultObject and DefaultObject:IsValid() then return DefaultObject end - end - - DefaultObject = StaticFindObject(ObjectFullName) - ModRef:SetSharedVariable(VariableName, DefaultObject) - if not DefaultObject:IsValid() then error(string.format("%s not found", ObjectFullName)) end - - return DefaultObject -end - --- Everything in this section can be used in any mod that requires this module. --- Exported functions -> START - -function UEHelpers.GetUEHelpersVersion() - return Version -end - ---- Returns the first valid PlayerController that is currently controlled by a player. ----@return APlayerController -local PlayerController = nil -function UEHelpers.GetPlayerController() - if PlayerController and PlayerController:IsValid() then return PlayerController end - -- local PlayerControllers = jsb.simpleBench("findallof", FindAllOf, "Controller") - -- Uncomment line above and comment line below to profile this function - local PlayerControllers = FindAllOf("PlayerController") or FindAllOf("Controller") - if not PlayerControllers then return Print("No PlayerControllers found\n") end - for _, Controller in pairs(PlayerControllers or {}) do - if Controller.Pawn:IsValid() and Controller.Pawn:IsPlayerControlled() then - PlayerController = Controller - break - -- else - -- print("Not valid or not player controlled\n") - end - end - if PlayerController and PlayerController:IsValid() then - return PlayerController - end - error("No PlayerController found\n") -end - ---- Returns the UWorld that the player is currenlty in. ----@return UWorld -function UEHelpers.GetWorld() - return UEHelpers.GetPlayerController():GetWorld() -end - ---- Returns the UGameViewportClient for the player. ----@return AActor -function UEHelpers.GetGameViewportClient() - return UEHelpers.GetPlayerController().Player.ViewportClient -end - ---- Returns an object that's useable with UFunctions that have a WorldContextObject param. ---- Prefer to use an actor that you already have access to whenever possible over this function. ----@return AActor -function UEHelpers.GetWorldContextObject() - return UEHelpers.GetPlayerController() -end - -function UEHelpers.GetGameplayStatics(ForceInvalidateCache) - return CacheDefaultObject("/Script/Engine.Default__GameplayStatics", "UEHelpers_GameplayStatics", ForceInvalidateCache) -end - -function UEHelpers.GetKismetSystemLibrary(ForceInvalidateCache) - return CacheDefaultObject("/Script/Engine.Default__KismetSystemLibrary", "UEHelpers_KismetSystemLibrary", ForceInvalidateCache) -end - -function UEHelpers.GetKismetMathLibrary(ForceInvalidateCache) - return CacheDefaultObject("/Script/Engine.Default__KismetMathLibrary", "UEHelpers_KismetMathLibrary", ForceInvalidateCache) -end - -function UEHelpers.GetKismetMathLibrary(ForceInvalidateCache) - return CacheDefaultObject("/Script/Engine.Default__KismetMathLibrary", "UEHelpers_KismetMathLibrary", ForceInvalidateCache) -end - -function UEHelpers.GetGameMapsSettings(ForceInvalidateCache) - return CacheDefaultObject("/Script/EngineSettings.Default__GameMapsSettings", "UEHelpers_GameMapsSettings", ForceInvalidateCache) -end - -function UEHelpers.FindOrAddFName(Name) - local NameFound = FName(Name, EFindName.FNAME_Find) - if NameFound == NAME_None then - NameFound = FName(Name, EFindName.FNAME_Add) - end - return NameFound -end - --- Exported functions -> END - -return UEHelpers diff --git a/UE4SS/Mods/shared/jsbProfiler/jsbProfi.lua b/UE4SS/Mods/shared/jsbProfiler/jsbProfi.lua deleted file mode 100644 index 2368f73..0000000 --- a/UE4SS/Mods/shared/jsbProfiler/jsbProfi.lua +++ /dev/null @@ -1,436 +0,0 @@ -local jsb = {} - --- options -local new_log_eachtime = false -local log_file_name = "jsb.log" - -function jsb.IntegratedbasicSerialize(s) - if s == nil then - return 'nil' - else - if type(s) == "number" or type(s) == "boolean" then - return tostring(s) - elseif type(s) == "function" or type(s) == "table" or type(s) == "userdata" then - return "" - elseif type(s) == "string" then - return string.format('%q',s) - end - end -end - -local function tbl_ibs(tbl) - local result = jsb.IntegratedbasicSerialize(tbl) - if string.find(tostring(result), 'table:') then - result = '' - end - return result -end - -function jsb.tbl(tbl, name, space, indent, recirc) - local fstr = string.format - local internal_call = recirc ~= nil - recirc = recirc or {} - space = space or ' ' - indent = indent or "" - name = name or "" - if type(tbl) == "table" then - recirc[tbl] = space - local result = {} - if internal_call then - result[#result+1] = fstr('%s{\n', name) - else - result[#result+1] = fstr('%s%s = {\n', indent, name) - end - for key,data in pairs(tbl) do - -- key - if type(key) == "number" then - result[#result+1] = fstr('%s%s[%s] = ', indent, space, tostring(key)) - else - result[#result+1] = fstr('%s%s[%s] = ', indent, space, tbl_ibs(key)) - end - -- data - if type(data) == "number" or type(data) == "boolean" then - result[#result+1] = fstr('%s,\n', tostring(data)) - elseif type(data) == "string" then - result[#result+1] = fstr('%s,\n', tbl_ibs(data)) - elseif type(data) == "table" then - recirc[data] = fstr('\n%s[%s]', space, tbl_ibs(key)) - result[#result+1] = fstr('%s\n', jsb.tbl(data, '', fstr('%s', space), fstr('%s ', indent), recirc)) - elseif type(data) == "boolean" then - result[#result+1] = fstr("%s\n",tostring(data)) - else - result[#result+1] = "nil,\n" - end - end - if not internal_call then result[#result+1] = fstr("%s}", indent) else result[#result+1] = fstr("%s},", indent) end - return table.concat(result) - end -end - -function jsb.write(data, file, method) - local File = io.open(file, method or "a") - if not File then return end - File:write(data):close() -end - -table.keys = function(t) - local keys = {} - local fmt = string.format - for k in pairs (t or {}) do - local type_obj = type(t[k]) - keys[#keys+1] = fmt("%s : (%s)", k, type_obj) - if type_obj == "string" or type_obj == "number" or type_obj == "boolean" then keys[#keys+1] = " " .. tostring(t[k]) end - keys[#keys+1] = "\n" - end - return table.concat(keys) -end - --- simple bench - -- 2 simple func that can stand inline of a call (former a single call and the latter can be made to run the call n times) - -- will output the call performance to log file as time to execute in seconds - -- see example UEHelpers line 33 - function jsb.simpleBench(name, func, ...) - if not name or type(name) ~= "string" then return print("Error in bench args!") end - local data_return - local start = os.clock() - data_return = {func(...)} - local fin = os.clock() - start - jsb.write(string.format("%s: Func %s took: %g\n", os.date(), name or "unk", fin), log_file_name, "a") - if not data_return[1] then return end - return table.unpack(data_return) - end - - function jsb.simpleBenchMulti(name, repeats, func, ...) - if (not name or type(name) ~= "string") or (not repeats or type(repeats) ~= "number") then return print("Error in bench args!") end - local data_return - local start = os.clock() - for i = 1, repeats or 1 do data_return = {func(...)} end - local fin = os.clock() - start - jsb.write(string.format("%s: Func %s took: %g and %g average per call\n", os.date(), name or "unk", fin, fin/(repeats or 1)), log_file_name, "a") - if not data_return[1] then return end - return table.unpack(data_return) - end --- - -jsb.write(string.format("\n\n%s: New test session\n\n", os.date()), log_file_name, new_log_eachtime and "w" or "a") - --- profiler - -local jsb_profi = {} -jsb.profi = {} - -jsb_profi.clock = os.clock - --- function labels -local _func_labels = {} --- function definitions -local _defined_funcs = {} --- time of last call -local _time_called = {} --- total execution time -local _time_elapsed = {} --- number of calls -local _number_of_calls = {} --- list of internal profiler functions -local _internal_funcs = {} -local running -local non_lua, line_calls, started = {}, 0, 0 -local call_tree = {} -local taken = 0 -local fstr = string.format -local real_world_adjust = 0.4582 -- adjust results knowing the process itself will inflate execution -local rwa = true -- enable performance report adjustment for overhead - ---- This is an internal function. -function jsb_profi.hooker(event, line, info) - info = info or debug.getinfo(2, 'fnS') - local f = info.func - -- ignore the profiler - if _internal_funcs[f] or info.what ~= "Lua" then - return - end - -- get the function name if available - if info.name then - _func_labels[f] = info.name - end - -- find the line definition - if not _defined_funcs[f] then - _defined_funcs[f] = info.short_src..":"..info.linedefined - _number_of_calls[f] = 0 - _time_elapsed[f] = 0 - end - if _time_called[f] then - local dt = jsb_profi.clock() - _time_called[f] - _time_elapsed[f] = _time_elapsed[f] + dt - _time_called[f] = nil - end - if event == "tail call" then - local prev = debug.getinfo(3, 'fnS') - jsb_profi.hooker("return", line, prev) - jsb_profi.hooker("call", line, info) - elseif event == 'call' then - _time_called[f] = jsb_profi.clock() - else - _number_of_calls[f] = _number_of_calls[f] + 1 - end -end - -local missed_events = {} -local no_record = {} - -jsb_profi.evlog = function(fmt, ...) missed_events[#missed_events+1] = fstr(fmt,...) end -jsb_profi.wlog = function(fmt, ...) non_lua[#non_lua+1] = fstr(fmt,...) end -local _log = function(fmt, ...) jsb.write(string.format("%s: %s\n", os.date(), string.format(fmt, ...)), log_file_name) end - -function jsb_profi.call_tree(alert_only) - local output = {} - local alert = {} - local prv_time - output[#output+1] = fstr("Call Tree :: %s\n\n", os.date()) - for call = 1,#call_tree do - if not prv_time then - output[#output+1] = fstr("First call: %s :: %s :: %s\n",tostring(call_tree[call][1]),tostring(call_tree[call][3]),tostring(call_tree[call][4])) - prv_time = call_tree[call][2] - elseif call_tree[call][2]-prv_time < 0.14 then - output[#output+1] = fstr("%d th call: %s :: %s :: %s\n",call,tostring(call_tree[call][1]),tostring(call_tree[call][3]),tostring(call_tree[call][4])) - output[#output+1] = fstr(" %f since last call\n",call_tree[call][2]-prv_time) - prv_time = call_tree[call][2] - else - output[#output+1] = fstr("%d th call: %s :: %s :: %s\n",call,tostring(call_tree[call][1]),tostring(call_tree[call][3]),tostring(call_tree[call][4])) - output[#output+1] = fstr(" ALERT %f since last call\n",call_tree[call][2]-prv_time) - alert[#alert+1] = fstr("%d th call: %s :: %s :: %s\n",call,tostring(call_tree[call][1]),tostring(call_tree[call][3]),tostring(call_tree[call][4])) - alert[#alert+1] = fstr(" ALERT %f since last call\n",call_tree[call][2]-prv_time) - prv_time = call_tree[call][2] - end - end - if not alert_only then jsb.write(table.concat(output), "CallTree.log", "w") end - jsb.write(table.concat(alert), "CallTreeAlert.log", "w") -end - -local lastSeen = {} - -function jsb_profi.vm_hook(event, line, info) - line_calls = line_calls + 1 - info = info or debug.getinfo(2, 'fnSl') - local f = info.func - -- ignore the profiler itself or non lua code - if _internal_funcs[f] then - return - elseif info.what == "C" or info.what == "?" then - jsb_profi.wlog("%s", info.what) - return - end - if info.name and no_record[info.name] then - return - elseif info.name then - call_tree[#call_tree+1] = {info.name, os.clock(), info.short_src, info.linedefined} - end - -- get the function name if available - if not _func_labels[f] and info.name then - _func_labels[f] = info.name - end - -- find the line definition - if not _defined_funcs[f] then - _defined_funcs[f] = fstr("%s:%s",info.short_src, info.linedefined) - _number_of_calls[f] = 0 - _time_elapsed[f] = 0 - end - - if _time_called[f] then - local dt = jsb_profi.clock() - _time_called[f] - _time_elapsed[f] = _time_elapsed[f] + dt - _time_called[f] = nil - end - - if event == "tail call" then - local prev = debug.getinfo(3, 'fnS') - jsb_profi.hooker("return", line, prev) - jsb_profi.hooker("call", line, info) - call_tree[#call_tree+1] = {prev.name,os.clock(),prev.short_src,prev.linedefined} - elseif event == 'call' then - _time_called[f] = jsb_profi.clock() - if info.name then - if not lastSeen[info.name] then - lastSeen[info.name] = os.clock() - else - local t = os.clock() - lastSeen[info.name] - if t > 10.4 and t < 13 then - _log("Function match :: %s",tostring(info.name)) - end - lastSeen[info.name] = nil - end - end - else - -- profile.evlog("%s",event) - _number_of_calls[f] = _number_of_calls[f] + 1 - end -end - ---- Starts collecting data. -function jsb_profi.start_collect(name) - if not running then - non_lua, line_calls = {}, 0 - call_tree = {} - started = os.clock() - running = true - jsb.write(string.format("%s: Profiler started for session: %s\n", os.date(), name or "logging"), log_file_name) - debug.sethook(jsb_profi.vm_hook, "cr") - else - jsb.write(string.format("%s: Error! Profiler already started!\n", os.date()), log_file_name) - end -end - ---- Stops collecting data. -function jsb_profi.stop() - debug.sethook() - jsb_profi.call_tree(true) - taken = jsb_profi.clock() - started - for f in pairs(_time_called) do - local dt = jsb_profi.clock() - _time_called[f] - _time_elapsed[f] = _time_elapsed[f] + dt - _time_called[f] = nil - end - -- merge closures - local lookup = {} - for f, d in pairs(_defined_funcs) do - local id = (_func_labels[f] or '?')..d - local f2 = lookup[id] - if f2 then - _number_of_calls[f2] = _number_of_calls[f2] + (_number_of_calls[f] or 0) - _time_elapsed[f2] = _time_elapsed[f2] + (_time_elapsed[f] or 0) - _defined_funcs[f], _func_labels[f] = nil, nil - _number_of_calls[f], _time_elapsed[f] = nil, nil - else - lookup[id] = f - end - end - local missed = {} - missed[#missed+1] = "jsbProfi stopped. Time took: " - missed[#missed+1] = taken - - local mnl = {} - missed[#missed+1] = " non_lua: " - for i = 1,#non_lua do - if not mnl[non_lua[i]] then - mnl[non_lua[i]] = true - missed[#missed+1] = non_lua[i] - missed[#missed+1] = " " - end - end - _log(table.concat(missed)) - collectgarbage('collect') -end - ---- Resets all collected data. -function jsb_profi.reset() - local data = {_time_elapsed, _number_of_calls} - for i = 1, 2 do - for f in pairs(data[i] or {}) do - data[i][f] = 0 - end - end - for f in pairs(_time_called or {}) do - _time_called[f] = nil - end - collectgarbage('collect') -end - ---- This is an internal function. -function jsb_profi.comp(a, b) - local dt = _time_elapsed[b] - _time_elapsed[a] - if dt == 0 then - return _number_of_calls[b] < _number_of_calls[a] - end - return dt < 0 -end - ---- Iterates all functions that have been called since the profile was started. -function jsb_profi.query(limit) - local t = {} - for f, n in pairs(_number_of_calls) do - if n > 0 then - t[#t + 1] = f - end - end - table.sort(t, jsb_profi.comp) - if limit then - while #t > limit do - table.remove(t) - end - end - for i, f in ipairs(t) do - local dt = 0 - if _time_called[f] then - dt = jsb_profi.clock() - _time_called[f] - end - t[i] = { i, _func_labels[f] or '?', _number_of_calls[f], string.format("%0.4f (%0.4f)",((_time_elapsed[f] + dt)/_number_of_calls[f])*(rwa and real_world_adjust or 1), (_time_elapsed[f] + dt)*(rwa and real_world_adjust or 1)), _defined_funcs[f] } - end - return t -end - -local cols = { 3, 29, 11, 24, 32 } - ---- Generates a text report. --- @tparam[opt] number limit Maximum number of rows -function jsb_profi.report() - local line_out = {} - local report = jsb_profi.query(50) - for i, row in ipairs(report) do - for j = 1, 5 do - local s = row[j] - local l2 = cols[j] - s = tostring(s) - local l1 = s:len() - if l1 < l2 then - s = s..(' '):rep(l2-l1) - elseif l1 > l2 then - s = s:sub(l1 - l2 + 1, l1) - end - row[j] = s - end - line_out[i] = table.concat(row, ' | ') - end - - local row = " +-----+-------------------------------+-------------+--------------------------+----------------------------------+ \n" - local col = " | # | FunctionName | nCalls | TimePerCall (total) | CodeLine | \n" - local header = row .. col .. row - if #line_out > 0 then - header = header .. ' | ' .. table.concat(line_out, ' | \n | ') .. ' | \n' - end - return '\n' .. header .. row -end - -function jsb_profi.stop_collect() - if not running then return end - _log("Profiler stopped!") - running = false - jsb_profi.stop() - local rep = jsb_profi.report() - _log(rep) - jsb_profi.reset() -end - --- user call to start lua vm profiler --- n is seconds to hook all lua execution --- name the session with a string for ease of differentiation in reporting --- can only be active in one state at a time, no async or multi sessions (can be made into a class if this is required) --- will automatically report the trace results to the log file -function jsb.profile(n, name) - jsb_profi.reset() - jsb_profi.start_collect(name) - -- only auto stop if implicit - if n then ExecuteWithDelay(n * 1000, jsb_profi.stop_collect) end -end - --- can manually call to stop and report -jsb.stop_trace = jsb_profi.start_collect - --- store all internal profiler functions - for _, v in pairs(jsb_profi) do - if type(v) == "function" then - _internal_funcs[v] = true - end - end --- - -return jsb \ No newline at end of file diff --git a/UE4SS/UE4SS-settings.ini b/UE4SS/UE4SS-settings.ini deleted file mode 100644 index e3d1856..0000000 --- a/UE4SS/UE4SS-settings.ini +++ /dev/null @@ -1,142 +0,0 @@ -[Overrides] -; Path to the 'Mods' folder -; Default: /Mods -ModsFolderPath = - -[General] -EnableHotReloadSystem = 1 - -; Whether the cache system for AOBs will be used. -; Default: 1 -UseCache = 1 - -; Whether caches will be invalidated if ue4ss.dll has changed -; Default: 1 -InvalidateCacheIfDLLDiffers = 1 - -; The number of seconds the scanner will scan for before giving up -; Default: 30 -SecondsToScanBeforeGivingUp = 30 - -; Whether to create UObject listeners in GUObjectArray to create a fast cache for use instead of iterating GUObjectArray. -; Setting this to false can help if you're experiencing a crash on startup. -; Default: true -bUseUObjectArrayCache = true - -[EngineVersionOverride] -MajorVersion = -MinorVersion = - -[ObjectDumper] -; Whether to force all assets to be loaded before dumping objects -; WARNING: Can require multiple gigabytes of extra memory -; WARNING: Is not stable & will crash the game if you load past the main menu after dumping -; Default: 0 -LoadAllAssetsBeforeDumpingObjects = 0 - -[CXXHeaderGenerator] -; Whether to property offsets and sizes -; Default: 1 -DumpOffsetsAndSizes = 1 - -; Whether memory layouts of classes and structs should be accurate -; This must be set to 1, if you want to use the generated headers in an actual C++ project -; When set to 0, padding member variables will not be generated -; NOTE: A VALUE OF 1 HAS NO PURPOSE YET! MEMORY LAYOUT IS NOT ACCURATE EITHER WAY! -; Default: 0 -KeepMemoryLayout = 0 - -; Whether to force all assets to be loaded before generating headers -; WARNING: Can require multiple gigabytes of extra memory -; WARNING: Is not stable & will crash the game if you load past the main menu after dumping -; Default: 0 -LoadAllAssetsBeforeGeneratingCXXHeaders = 0 - -[UHTHeaderGenerator] -; Whether to skip generating packages that belong to the engine -; Some games make alterations to the engine and for those games you might want to set this to 0 -; Default: 0 -IgnoreAllCoreEngineModules = 0 - -; Whether to skip generating the "Engine" and "CoreUObject" packages -; Default: 1 -IgnoreEngineAndCoreUObject = 1 - -; Whether to force all UFUNCTION macros to have "BlueprintCallable" -; Note: This will cause some errors in the generated headers that you will need to manually fix -; Default: 1 -MakeAllFunctionsBlueprintCallable = 1 - -; Whether to force all UPROPERTY macros to have "BlueprintReadWrite" -; Also forces all UPROPERTY macros to have "meta=(AllowPrivateAccess=true)" -; Default: 1 -MakeAllPropertyBlueprintsReadWrite = 1 - -; Whether to force UENUM macros on enums to have 'BlueprintType' if the underlying type was implicit or uint8 -; Note: This also forces the underlying type to be uint8 where the type would otherwise be implicit -; Default: 1 -MakeEnumClassesBlueprintType = 1 - -; Whether to force "Config = Engine" on all UCLASS macros that use either one of: -; "DefaultConfig", "GlobalUserConfig" or "ProjectUserConfig" -; Default: 1 -MakeAllConfigsEngineConfig = 1 - -[Debug] -; Whether to enable the external UE4SS debug console. -ConsoleEnabled = 0 -GuiConsoleEnabled = 1 -GuiConsoleVisible = 0 - -; Multiplier for Font Size within the Debug Gui -; Default: 1 -GuiConsoleFontScaling = 1 - -; The API that will be used to render the GUI debug window. -; Valid values (case-insensitive): dx11, d3d11, opengl -; Default: opengl -GraphicsAPI = opengl - -; How many objects to put in each group in the live view. -; A lower number means more groups but less lag when a group is open. -; A higher number means less groups but more lag when a group is open. -; Default: 32768 -LiveViewObjectsPerGroup = 32768 - -[Threads] -; The number of threads that the sig scanner will use (not real cpu threads, can be over your physical & hyperthreading max) -; If the game is modular then multi-threading will always be off regardless of the settings in this file -; Min: 1 -; Max: 4294967295 -; Default: 8 -SigScannerNumThreads = 8 - -; The minimum size that a module has to be in order for multi-threading to be enabled -; This should be large enough so that the cost of creating threads won't out-weigh the speed gained from scanning in multiple threads -; Min: 0 -; Max: 4294967295 -; Default: 16777216 -SigScannerMultithreadingModuleSizeThreshold = 16777216 - -[Memory] -; The maximum memory usage (in percentage, see Task Manager %) allowed before asset loading (when LoadAllAssetsBefore* is 1) cannot happen. -; Once this percentage is reached, the asset loader will stop loading and whatever operation was in progress (object dump, or cxx generator) will continue. -; Default: 85 -MaxMemoryUsageDuringAssetLoading = 80 - -[Hooks] -HookProcessInternal = 1 -HookProcessLocalScriptFunction = 1 -HookInitGameState = 1 -HookCallFunctionByNameWithArguments = 1 -HookBeginPlay = 1 -HookLocalPlayerExec = 1 -FExecVTableOffsetInLocalPlayer = 0x28 - -[CrashDump] -EnableDumping = 1 -FullMemoryDump = 0 - -[ExperimentalFeatures] -; Only enable these features if you know what you are doing. -GUIUFunctionCaller = 0 diff --git a/UE4SS/UE4SS.dll b/UE4SS/UE4SS.dll deleted file mode 100644 index cb4fb04..0000000 Binary files a/UE4SS/UE4SS.dll and /dev/null differ diff --git a/UE4SS/dwmapi.dll b/UE4SS/dwmapi.dll deleted file mode 100644 index 116dc6b..0000000 Binary files a/UE4SS/dwmapi.dll and /dev/null differ diff --git a/mod_container.tscn b/mod_container.tscn index 925c92d..15faced 100644 --- a/mod_container.tscn +++ b/mod_container.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://c46opjxqvwf5n"] [ext_resource type="Theme" uid="uid://dged4041swr1" path="res://theme.tres" id="1_iry1s"] -[ext_resource type="Script" path="res://mod_container.gd" id="2_008ft"] +[ext_resource type="Script" path="res://scripts/mod_container.gd" id="2_008ft"] [node name="ModContainer" type="HBoxContainer"] offset_right = 40.0 diff --git a/mod_manager.tscn b/mod_manager.tscn index d86238a..9312ee3 100644 --- a/mod_manager.tscn +++ b/mod_manager.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://c6570n2s1k1wv"] [ext_resource type="Theme" uid="uid://dged4041swr1" path="res://theme.tres" id="1_j4kl3"] -[ext_resource type="Script" path="res://mod_manager.gd" id="1_kosmn"] +[ext_resource type="Script" path="res://scripts/mod_manager.gd" id="1_kosmn"] [node name="ModManager" type="Control"] layout_mode = 3 @@ -62,6 +62,10 @@ layout_mode = 2 layout_mode = 2 text = "Mod list [0]" +[node name="RefreshButton" type="Button" parent="MarginContainer/MainContainer/ModListContainer"] +layout_mode = 2 +text = "Refresh" + [node name="InstallModButton" type="Button" parent="MarginContainer/MainContainer/ModListContainer"] layout_mode = 2 text = "Install mod" @@ -79,7 +83,7 @@ layout_mode = 2 [node name="ModManagerLabel" type="Label" parent="MarginContainer/MainContainer/ModManagerContainer"] layout_mode = 2 -text = "GSS Mod Manager v0.1.1" +text = "GSS Mod Manager v0.2" [node name="ConfigureButton" type="Button" parent="MarginContainer/MainContainer/ModManagerContainer"] layout_mode = 2 @@ -129,6 +133,7 @@ use_native_dialog = true [connection signal="pressed" from="MarginContainer/MainContainer/PathContainer/ChangePathButton" to="." method="_on_change_path_button_pressed"] [connection signal="pressed" from="MarginContainer/MainContainer/ModLoaderContainer/ModLoaderInstallButton" to="." method="_on_mod_loader_install_button_pressed"] +[connection signal="pressed" from="MarginContainer/MainContainer/ModListContainer/RefreshButton" to="." method="_on_refresh_list_button_pressed"] [connection signal="pressed" from="MarginContainer/MainContainer/ModListContainer/InstallModButton" to="." method="_on_install_mod_button_pressed"] [connection signal="pressed" from="MarginContainer/MainContainer/ModManagerContainer/ConfigureButton" to="." method="_on_configure_button_pressed"] [connection signal="dir_selected" from="FileDialog" to="." method="_on_file_dialog_dir_selected"] diff --git a/project.godot b/project.godot index 5ce2fb5..a725ace 100644 --- a/project.godot +++ b/project.godot @@ -16,6 +16,10 @@ run/main_scene="res://mod_manager.tscn" config/features=PackedStringArray("4.3", "GL Compatibility") config/icon="res://icon.svg" +[autoload] + +Files="*res://scripts/files.gd" + [rendering] renderer/rendering_method="gl_compatibility" diff --git a/scripts/files.gd b/scripts/files.gd new file mode 100644 index 0000000..47d55a1 --- /dev/null +++ b/scripts/files.gd @@ -0,0 +1,53 @@ +extends Node + +## Copies from path to destination_path recursively, destination_path must exist +## Returns error code +static func copy_recursive(from: String, to: String, folder_name: String = "") -> int: + var err = DirAccess.make_dir_absolute("%s%s" % [to, folder_name]) + if err != OK and err != ERR_ALREADY_EXISTS: + return err + var dir = DirAccess.open("%s%s" % [from, folder_name]) + if dir: + dir.list_dir_begin() + var file_name = dir.get_next() + var full_path = "%s%s/%s" % [from, folder_name, file_name] + while file_name != "": + if dir.current_is_dir(): + err = copy_recursive(from, to, "%s/%s" % [folder_name, file_name]) + if err: + return err + else: + err = DirAccess.copy_absolute(full_path, "%s%s/%s" % [to, folder_name, file_name]) + if err: + return err + else: + print("Copied %s to %s%s/%s" % [full_path, to, folder_name, file_name]) + file_name = dir.get_next() + full_path = "%s%s/%s" % [from, folder_name, file_name] + else: + return DirAccess.get_open_error() + return OK + +## Deletes directories recursively +## Returns error code +static func remove_recursive(path: String) -> int: + var dir = DirAccess.open(path) + if dir: + dir.list_dir_begin() + var file_name = dir.get_next() + var full_path = "%s/%s" % [path, file_name] + while file_name != "": + if dir.current_is_dir(): + remove_recursive(full_path) + else: + var err = DirAccess.remove_absolute(full_path) + if err: + return err + else: + print("Removed %s" % [full_path]) + file_name = dir.get_next() + full_path = "%s/%s" % [path, file_name] + DirAccess.remove_absolute(path) + else: + return DirAccess.get_open_error() + return OK diff --git a/mod_container.gd b/scripts/mod_container.gd similarity index 100% rename from mod_container.gd rename to scripts/mod_container.gd diff --git a/mod_manager.gd b/scripts/mod_manager.gd similarity index 74% rename from mod_manager.gd rename to scripts/mod_manager.gd index b9b3f22..34025f0 100644 --- a/mod_manager.gd +++ b/scripts/mod_manager.gd @@ -16,6 +16,7 @@ const BUILTIN_MODS: Array[String] = [ "jsbLuaProfilerMod", "Keybinds", "LineTraceMod", "SplitScreenMod" ] +var root_path := OS.get_executable_path().get_base_dir() var gss_path: String: set(value): path_label.text = "GSS Path: %s" % value @@ -49,11 +50,13 @@ var mod_loader_installed: bool: mod_loader_installed = value var config: ConfigFile var config_editor_path: String +var editor_thread := Thread.new() + +# NOTE: Only test in exported! (Unless you find a way to do it in the editor) # TODO: Make editor for editing config configurable # TODO: Clean up this mess # TODO: Get icon -# TODO: Add refresh button to mod list that just calls update_mod_list() ## Searches Steam paths for Grocery Store Simulator func detect_gss() -> void: @@ -90,30 +93,6 @@ func get_mod_list() -> Dictionary: error("Opening mods.txt file", err) return enabled -## Deletes directories recursively -func remove_recursive(path: String): - var dir = DirAccess.open(path) - if dir: - dir.list_dir_begin() - var file_name = dir.get_next() - var full_path = "%s/%s" % [path, file_name] - while file_name != "": - if dir.current_is_dir(): - remove_recursive(full_path) - else: - var err = DirAccess.remove_absolute(full_path) - if err: - if error("Remove from folder", err): return - else: - print("Removed %s" % [full_path]) - file_name = dir.get_next() - full_path = "%s/%s" % [path, file_name] - DirAccess.remove_absolute(path) - else: - var err = DirAccess.get_open_error() - error("Open folder", err) - return - ## Updates the UI for mods not built-in func update_mod_list() -> void: if !mod_loader_installed: @@ -142,12 +121,12 @@ func _on_configure_mod(mod_name: String) -> void: for file in DirAccess.get_files_at("%s/Simulatorita/Binaries/Win64/Mods/%s/Scripts" % [gss_path, mod_name]): if file.begins_with("config"): config_editor_path = "%s/Simulatorita/Binaries/Win64/Mods/%s/Scripts/%s" % [gss_path, mod_name, file] - var err = Thread.new().start(run_config_editor, Thread.PRIORITY_LOW) + var err = editor_thread.start(run_config_editor, Thread.PRIORITY_LOW) error("Execute notepad in thread", err) return func _on_delete_mod(mod_name: String) -> void: - remove_recursive("%s/Simulatorita/Binaries/Win64/Mods/%s" % [gss_path, mod_name]) + Files.remove_recursive("%s/Simulatorita/Binaries/Win64/Mods/%s" % [gss_path, mod_name]) var file = FileAccess.open("%s/Simulatorita/Binaries/Win64/Mods/mods.txt" % gss_path, FileAccess.READ) if file: var lines = [] @@ -207,6 +186,10 @@ func _on_toggle_mod(mod_name: String, on: bool) -> void: var err = FileAccess.get_open_error() error("Opening mods.txt file", err) +func _process(_delta: float) -> void: + if editor_thread.is_started() and !editor_thread.is_alive(): + editor_thread.wait_to_finish() + func _ready() -> void: config = ConfigFile.new() var err = config.load("user://config") @@ -223,42 +206,15 @@ func _ready() -> void: func _on_mod_loader_install_button_pressed() -> void: if mod_loader_installed: - remove_recursive("%s/Simulatorita/Binaries/Win64/Mods" % gss_path) + Files.remove_recursive("%s/Simulatorita/Binaries/Win64/Mods" % gss_path) DirAccess.remove_absolute("%s/Simulatorita/Binaries/Win64/UE4SS.dll" % gss_path) DirAccess.remove_absolute("%s/Simulatorita/Binaries/Win64/UE4SS-settings.ini" % gss_path) DirAccess.remove_absolute("%s/Simulatorita/Binaries/Win64/dwmapi.dll" % gss_path) else: - copy_recursive("%s/Simulatorita/Binaries/Win64" % gss_path, "res://UE4SS") + Files.copy_recursive("%s/UE4SS" % root_path, "%s/Simulatorita/Binaries/Win64" % gss_path) mod_loader_installed = !mod_loader_installed update_mod_list() -## Copies from path to destination_path recursively, destination_path must exist -func copy_recursive(destination_path: String, path: String, folder_name: String = "") -> void: - var err = DirAccess.make_dir_absolute("%s%s" % [destination_path, folder_name]) - if err != ERR_ALREADY_EXISTS: - error("Make folder", err) - - var dir = DirAccess.open("%s%s" % [path, folder_name]) - if dir: - dir.list_dir_begin() - var file_name = dir.get_next() - var full_path = "%s%s/%s" % [path, folder_name, file_name] - while file_name != "": - if dir.current_is_dir(): - copy_recursive(destination_path, path, "%s/%s" % [folder_name, file_name]) - else: - err = DirAccess.copy_absolute(full_path, "%s%s/%s" % [destination_path, folder_name, file_name]) - if err: - if error("Copy from folder", err): return - else: - print("Copied %s to %s%s/%s" % [full_path, destination_path, folder_name, file_name]) - file_name = dir.get_next() - full_path = "%s%s/%s" % [path, folder_name, file_name] - else: - err = DirAccess.get_open_error() - error("Open folder", err) - return - func _on_change_path_button_pressed() -> void: file_dialog.file_mode = FileDialog.FileMode.FILE_MODE_OPEN_DIR file_dialog.root_subfolder = gss_path @@ -279,29 +235,26 @@ func _on_install_mod_button_pressed() -> void: func _on_configure_button_pressed() -> void: config_panel.visible = !config_panel.visible +func _on_refresh_list_button_pressed() -> void: + update_mod_list() + func _on_file_dialog_file_selected(path: String) -> void: - var err: int - if !DirAccess.dir_exists_absolute("%s/GSS Mod Manager" % OS.get_environment("TEMP")): - err = DirAccess.make_dir_recursive_absolute("%s/GSS Mod Manager/mod" % OS.get_environment("TEMP")) - if error("Make directory in %TEMP%", err): return - err = DirAccess.copy_absolute("res://7z.exe", "%s/GSS Mod Manager/7z.exe" % OS.get_environment("TEMP")) - if error("Copy 7z.exe to %TEMP%", err): return - err = DirAccess.copy_absolute("res://7z.dll", "%s/GSS Mod Manager/7z.dll" % OS.get_environment("TEMP")) - if error("Copy 7z.dll to %TEMP%", err): return - - var args = ["x", path, "-o" + "%s/GSS Mod Manager/mod" % OS.get_environment("TEMP"), "-y"] - err = OS.execute("%s/GSS Mod Manager/7z.exe" % OS.get_environment("TEMP"), args) + var err = OS.execute("%s/7z.exe" % root_path, ["x", path, "-o" + "%s/mod" % root_path, "-y"]) if os_error("Execute 7z", err): return - var names = DirAccess.get_directories_at("%s/GSS Mod Manager/mod" % OS.get_environment("TEMP")) + var names = DirAccess.get_directories_at("%s/mod" % root_path) var mod_name = names[0] # there can be more, only if the program crashes. sucks to suck - DirAccess.make_dir_absolute("%s/Simulatorita/Binaries/Win64/Mods/%s" % [gss_path, mod_name]) - copy_recursive( - "%s/Simulatorita/Binaries/Win64/Mods/%s" % [gss_path, mod_name], - "%s/GSS Mod Manager/mod/%s" % [OS.get_environment("TEMP"), mod_name] + err = DirAccess.make_dir_absolute("%s/Simulatorita/Binaries/Win64/Mods/%s" % [gss_path, mod_name]) + if error("Make directory for mod", err): return + + err = Files.copy_recursive( + "%s/mod/%s" % [root_path, mod_name], + "%s/Simulatorita/Binaries/Win64/Mods/%s" % [gss_path, mod_name] ) - DirAccess.remove_absolute("%s/GSS Mod Manager/mod/%s" % [OS.get_environment("TEMP"), mod_name]) + if error("Copy from mod to mods folder", err): return + err = Files.remove_recursive("%s/mod/%s" % [root_path, mod_name]) + if error("Remove mod", err): return var file = FileAccess.open("%s/Simulatorita/Binaries/Win64/Mods/mods.txt" % gss_path, FileAccess.READ) if file: