-- This source code is adapted from the UE4SS repository. -- https://github.com/UE4SS-RE/RE-UE4SS -- See the following software license: -- MIT License -- -- Copyright (c) 2022 Narknon -- -- 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. local UEHelpers = {} -- Uncomment the below require to use the Lua VM profiler on these functions -- local jsb = require("jsbProfiler.jsbProfi") -- Version 1 does not exist, we start at version 2 because the original version didn't have a version at all. local Version = 3 -- Functions and classes local to this module, do not attempt to use! ---@param ObjectFullName string ---@param VariableName string ---@param ForceInvalidateCache boolean? ---@return UObject local function CacheDefaultObject(ObjectFullName, VariableName, ForceInvalidateCache) local DefaultObject = CreateInvalidObject() 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) 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 local EngineCache = CreateInvalidObject() ---@cast EngineCache UEngine ---Returns instance of UEngine ---@return UEngine function UEHelpers.GetEngine() if EngineCache:IsValid() then return EngineCache end EngineCache = FindFirstOf("Engine") ---@cast EngineCache UEngine return EngineCache end local GameInstanceCache = CreateInvalidObject() ---@cast GameInstanceCache UGameInstance ---Returns instance of UGameInstance ---@return UGameInstance function UEHelpers.GetGameInstance() if GameInstanceCache:IsValid() then return GameInstanceCache end GameInstanceCache = FindFirstOf("GameInstance") ---@cast GameInstanceCache UGameInstance return GameInstanceCache end ---Returns the main UGameViewportClient (doesn't exist on a server) ---@return UGameViewportClient function UEHelpers.GetGameViewportClient() local Engine = UEHelpers.GetEngine() if Engine:IsValid() and Engine.GameViewport then return Engine.GameViewport end return CreateInvalidObject() ---@type UGameViewportClient end ---Returns first player controller.
---In most games, a valid player controller is available from the start.
---There are no player controllers on the server until a player joins the server. ---@return APlayerController function UEHelpers.GetPlayerController() -- local Controllers = jsb.simpleBench("FindAllOf: PlayerController", FindAllOf, "PlayerController") -- Controllers = jsb.simpleBench("FindAllOf: Controller", FindAllOf, "Controller") local Controllers = FindAllOf("PlayerController") or FindAllOf("Controller") ---@type AController[]? if Controllers then for _, Controller in ipairs(Controllers) do if Controller:IsValid() and (Controller.IsPlayerController and Controller:IsPlayerController() or Controller:IsLocalPlayerController()) then return Controller end end end return CreateInvalidObject() ---@type APlayerController end ---Returns local player pawn ---@return APawn function UEHelpers.GetPlayer() local playerController = UEHelpers.GetPlayerController() if playerController:IsValid() and playerController.Pawn then return playerController.Pawn end return CreateInvalidObject() ---@type APawn end ---Returns the main UWorld ---@return UWorld function UEHelpers.GetWorld() local PlayerController = UEHelpers.GetPlayerController() if PlayerController:IsValid() then return PlayerController:GetWorld() else local GameInstance = UEHelpers.GetGameInstance() if GameInstance:IsValid() then return GameInstance:GetWorld() end end return CreateInvalidObject() ---@type UWorld end ---Returns UWorld->PersistentLevel ---@return ULevel function UEHelpers.GetPersistentLevel() local World = UEHelpers.GetWorld() if World:IsValid() and World.PersistentLevel then return World.PersistentLevel end return CreateInvalidObject() ---@type ULevel end ---Returns UWorld->AuthorityGameMode
---The function doesn't guarantee it to be an AGameMode, as many games derive their own game modes directly from AGameModeBase! ---@return AGameModeBase function UEHelpers.GetGameModeBase() local World = UEHelpers.GetWorld() if World:IsValid() and World.AuthorityGameMode then return World.AuthorityGameMode end return CreateInvalidObject() ---@type AGameModeBase end ---Returns UWorld->GameState
---The function doesn't guarantee it to be an AGameState, as many games derive their own game states directly from AGameStateBase! ---@return AGameStateBase function UEHelpers.GetGameStateBase() local World = UEHelpers.GetWorld() if World:IsValid() and World.GameState then return World.GameState end return CreateInvalidObject() ---@type AGameStateBase end ---Returns PersistentLevel->WorldSettings ---@return AWorldSettings function UEHelpers.GetWorldSettings() local PersistentLevel = UEHelpers.GetPersistentLevel() if PersistentLevel:IsValid() and PersistentLevel.WorldSettings then return PersistentLevel.WorldSettings end return CreateInvalidObject() ---@type AWorldSettings end --- Returns an object that's useable with UFunctions that have a WorldContext parameter.
--- Prefer to use an actor that you already have access to whenever possible over this function. --- Any UObject that has a GetWorld() function can be used as WorldContext. ---@return UObject function UEHelpers.GetWorldContextObject() return UEHelpers.GetWorld() end ---Returns an array of all players APlayerState ---@return APlayerState[] function UEHelpers.GetAllPlayerStates() local PlayerStates = {} local GameState = UEHelpers.GetGameStateBase() if GameState:IsValid() and GameState.PlayerArray then for i = 1, #GameState.PlayerArray do table.insert(PlayerStates, GameState.PlayerArray[i]) end end return PlayerStates end ---Returns all players as APawn.
---You can use `IsA` function to check the type of APawn to make sure it's the player class of the game. ---@return APawn[] function UEHelpers.GetAllPlayers() local PlayerPawns = {} local PlayerStates = UEHelpers.GetAllPlayerStates() if PlayerStates then for i = 1, #PlayerStates do local Pawn = PlayerStates[i].PawnPrivate if Pawn and Pawn:IsValid() then table.insert(PlayerPawns, Pawn) end end end return PlayerPawns end ---Returns hit actor from FHitResult.
---The function handles the struct difference between different UE versions ---@param HitResult FHitResult ---@return AActor|UObject function UEHelpers.GetActorFromHitResult(HitResult) if not HitResult then return CreateInvalidObject() end if UnrealVersion:IsBelow(5, 0) then return HitResult.Actor:Get() elseif UnrealVersion:IsBelow(5, 4) then return HitResult.HitObjectHandle.Actor:Get() end return HitResult.HitObjectHandle.ReferenceObject:Get() end ---@param ForceInvalidateCache boolean? # Force update the cache ---@return UGameplayStatics function UEHelpers.GetGameplayStatics(ForceInvalidateCache) ---@type UGameplayStatics return CacheDefaultObject("/Script/Engine.Default__GameplayStatics", "UEHelpers_GameplayStatics", ForceInvalidateCache) end ---@param ForceInvalidateCache boolean? # Force update the cache ---@return UKismetSystemLibrary function UEHelpers.GetKismetSystemLibrary(ForceInvalidateCache) ---@type UKismetSystemLibrary return CacheDefaultObject("/Script/Engine.Default__KismetSystemLibrary", "UEHelpers_KismetSystemLibrary", ForceInvalidateCache) end ---@param ForceInvalidateCache boolean? # Force update the cache ---@return UKismetMathLibrary function UEHelpers.GetKismetMathLibrary(ForceInvalidateCache) ---@type UKismetMathLibrary return CacheDefaultObject("/Script/Engine.Default__KismetMathLibrary", "UEHelpers_KismetMathLibrary", ForceInvalidateCache) end ---@param ForceInvalidateCache boolean? # Force update the cache ---@return UKismetStringLibrary function UEHelpers.GetKismetStringLibrary(ForceInvalidateCache) ---@type UKismetStringLibrary return CacheDefaultObject("/Script/Engine.Default__KismetStringLibrary", "UEHelpers_KismetStringLibrary", ForceInvalidateCache) end ---@param ForceInvalidateCache boolean? # Force update the cache ---@return UKismetTextLibrary function UEHelpers.GetKismetTextLibrary(ForceInvalidateCache) ---@type UKismetTextLibrary return CacheDefaultObject("/Script/Engine.Default__KismetTextLibrary", "UEHelpers_KismetTextLibrary", ForceInvalidateCache) end ---@param ForceInvalidateCache boolean? # Force update the cache ---@return UGameMapsSettings function UEHelpers.GetGameMapsSettings(ForceInvalidateCache) ---@type UGameMapsSettings return CacheDefaultObject("/Script/EngineSettings.Default__GameMapsSettings", "UEHelpers_GameMapsSettings", ForceInvalidateCache) end ---Returns found FName or "None" FName if the operation faled ---@param Name string ---@return FName function UEHelpers.FindFName(Name) return FName(Name, EFindName.FNAME_Find) end ---Returns added FName or "None" FName if the operation faled ---@param Name string ---@return FName function UEHelpers.AddFName(Name) return FName(Name, EFindName.FNAME_Add) end ---Tries to find existing FName, if it doesn't exist a new FName will be added to the pool ---@param Name string ---@return FName # Returns found or added FName, “None” FName if both operations fail 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