diff --git a/TechbloxModdingAPI/App/AntiAntiCheatPatch.cs b/TechbloxModdingAPI/App/AntiAntiCheatPatch.cs new file mode 100644 index 0000000..ed249bf --- /dev/null +++ b/TechbloxModdingAPI/App/AntiAntiCheatPatch.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using Svelto.Tasks; + +namespace TechbloxModdingAPI.App +{ + public static class AntiAntiCheatPatch + { + private delegate bool AntiAnticheatDelegate(ref object __result); + + private delegate bool AntiAnticheatDelegateBool(ref bool __result); + + private delegate bool AntiAnticheatDelegateTask(ref IEnumerator __result); + + public static void Init(Harmony harmony) + { + var type = AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.AnticheatClientService"); + harmony.Patch(type.GetConstructors()[0], new HarmonyMethod(((Func) AntiAntiCheat).Method)); + harmony.Patch(AccessTools.Method(type, "Shutdown"), new HarmonyMethod(((Func) AntiAntiCheat).Method)); + harmony.Patch(AccessTools.Method(type, "StartProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegate) AntiAntiCheat).Method)); + harmony.Patch(AccessTools.Method(type, "StopProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegateBool) AntiAntiCheat).Method)); + harmony.Patch(AccessTools.Method("Techblox.Services.Eos.Anticheat.Client.EosGetPendingMessagesToSendServiceRequest:Execute"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method)); + harmony.Patch(AccessTools.Method("Techblox.Anticheat.Client.Engines.ShowFeedbackDialogEngine:PollAnticheatStatus"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method)); + } + + private static bool AntiAntiCheat() => false; + + private static bool AntiAntiCheat(ref object __result) + { + var targetType = + AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.StartProtectedSessionResult"); + var target = Activator.CreateInstance(targetType); + targetType.GetField("Success").SetValue(target, true); + __result = target; + return false; + } + + private static bool AntiAntiCheat(ref bool __result) + { + __result = true; + return false; + } + + private static bool AntiAntiCheatTask(ref IEnumerator __result) + { + IEnumerator Func() + { + yield return Yield.It; + } + + __result = Func(); + return false; + } + } +} \ No newline at end of file diff --git a/TechbloxModdingAPI/App/AppEngine.cs b/TechbloxModdingAPI/App/AppEngine.cs deleted file mode 100644 index e4f5dcb..0000000 --- a/TechbloxModdingAPI/App/AppEngine.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -using RobocraftX.GUI.MyGamesScreen; -using Svelto.ECS; -using TechbloxModdingAPI.Engines; -using TechbloxModdingAPI.Utility; - -namespace TechbloxModdingAPI.App -{ - public class AppEngine : IFactoryEngine - { - public WrappedHandler EnterMenu; - - public WrappedHandler ExitMenu; - - public IEntityFactory Factory { set; private get; } - - public string Name => "TechbloxModdingAPIAppEngine"; - - public bool isRemovable => false; - - public EntitiesDB entitiesDB { set; private get; } - - public void Dispose() - { - IsInMenu = false; - ExitMenu.Invoke(this, new MenuEventArgs { }); - } - - public void Ready() - { - IsInMenu = true; - EnterMenu.Invoke(this, new MenuEventArgs { }); - } - - // app functionality - - public bool IsInMenu - { - get; - private set; - } = false; - } -} diff --git a/TechbloxModdingAPI/App/Client.cs b/TechbloxModdingAPI/App/Client.cs index 6fe4b4e..89f486f 100644 --- a/TechbloxModdingAPI/App/Client.cs +++ b/TechbloxModdingAPI/App/Client.cs @@ -14,12 +14,12 @@ namespace TechbloxModdingAPI.App /// public class Client { + public static Client Instance { get; } = new Client(); + protected static Func ErrorHandlerInstanceGetter; protected static Action EnqueueError; - protected static Action HandleErrorClosed; - /// /// An event that fires whenever the main menu is loaded. /// @@ -93,14 +93,31 @@ namespace TechbloxModdingAPI.App EnqueueError(errorHandlerInstance, popup); } - // TODO - /*public void CloseCurrentPrompt() + public void CloseCurrentPrompt() + { + object errorHandlerInstance = ErrorHandlerInstanceGetter(); + var popup = GetPopupCloseMethods(errorHandlerInstance); + popup.Close(); + } + + public void SelectFirstPromptButton() + { + object errorHandlerInstance = ErrorHandlerInstanceGetter(); + var popup = GetPopupCloseMethods(errorHandlerInstance); + popup.FirstButton(); + } + + public void SelectSecondPromptButton() { - // RobocraftX.Services.ErrorHandler.Instance.HandlePopupClosed(); - // FIXME: this is a call that is also called when closing, not the actual closing action itself (so it doesn't work) object errorHandlerInstance = ErrorHandlerInstanceGetter(); - HandleErrorClosed(errorHandlerInstance); - }*/ + var popup = GetPopupCloseMethods(errorHandlerInstance); + popup.SecondButton(); + } + + internal void CloseBetaPopup() + { + Game.menuEngine.CloseBetaPopup(); + } internal static void Init() { @@ -113,9 +130,6 @@ namespace TechbloxModdingAPI.App EnqueueError = (Action) AccessTools.Method("TechbloxModdingAPI.App.Client:GenEnqueueError") .MakeGenericMethod(errorHandler, errorHandle) .Invoke(null, new object[0]); - /*HandleErrorClosed = (Action) AccessTools.Method("TechbloxModdingAPI.App.Client:GenHandlePopupClosed") - .MakeGenericMethod(errorHandler) - .Invoke(null, new object[0]);*/ } // Creating delegates once is faster than reflection every time @@ -140,14 +154,23 @@ namespace TechbloxModdingAPI.App return enqueueCasted; } - private static Action GenHandlePopupClosed() + private static (Action Close, Action FirstButton, Action SecondButton) _errorPopup; + + private static (Action Close, Action FirstButton, Action SecondButton) GetPopupCloseMethods(object handler) { - Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); - MethodInfo handlePopupClosed = AccessTools.Method(errorHandler, "HandlePopupClosed"); - Action handleSimple = - (Action) Delegate.CreateDelegate(typeof(Action), handlePopupClosed); - Action handleCasted = (object instance) => handleSimple((T) instance); - return handleCasted; + if (_errorPopup.Close != null) + return _errorPopup; + Type errorHandler = handler.GetType(); + FieldInfo field = AccessTools.Field(errorHandler, "errorPopup"); + var errorPopup = (ErrorPopup)field.GetValue(handler); + MethodInfo info = AccessTools.Method(errorPopup.GetType(), "ClosePopup"); + var close = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info); + info = AccessTools.Method(errorPopup.GetType(), "HandleFirstOption"); + var first = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info); + info = AccessTools.Method(errorPopup.GetType(), "HandleSecondOption"); + var second = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info); + _errorPopup = (close, first, second); + return _errorPopup; } } } diff --git a/TechbloxModdingAPI/App/ClientAlertTest.cs b/TechbloxModdingAPI/App/ClientAlertTest.cs index 20d8201..278a826 100644 --- a/TechbloxModdingAPI/App/ClientAlertTest.cs +++ b/TechbloxModdingAPI/App/ClientAlertTest.cs @@ -42,17 +42,25 @@ namespace TechbloxModdingAPI.App [APITestCase(TestType.Menu)] public static void TestPopUp2() { - Client c = new Client(); - c.PromptUser(popup2); - //c.CloseCurrentPrompt(); + Client.Instance.PromptUser(popup2); } [APITestCase(TestType.Menu)] public static void TestPopUp1() { - Client c = new Client(); - c.PromptUser(popup1); - //c.CloseCurrentPrompt(); + Client.Instance.PromptUser(popup1); + } + + [APITestCase(TestType.Menu)] + public static void TestPopUpClose1() + { + Client.Instance.CloseCurrentPrompt(); + } + + [APITestCase(TestType.Menu)] + public static void TestPopUpClose2() + { + Client.Instance.CloseCurrentPrompt(); } } #endif diff --git a/TechbloxModdingAPI/App/CurrentGameMode.cs b/TechbloxModdingAPI/App/CurrentGameMode.cs index 85b3e09..211b552 100644 --- a/TechbloxModdingAPI/App/CurrentGameMode.cs +++ b/TechbloxModdingAPI/App/CurrentGameMode.cs @@ -1,23 +1,27 @@ -namespace TechbloxModdingAPI.App +using System; + +namespace TechbloxModdingAPI.App { public enum CurrentGameMode { None, /// - /// Building a game + /// Building a world /// Build, /// - /// Playing a game + /// Playing on a map /// Play, /// - /// Viewing a prefab + /// Viewing a prefab (doesn't exist anymore) /// + [Obsolete] View, /// - /// Viewing a tutorial + /// Viewing a tutorial (doesn't exist anymore) /// + [Obsolete] Tutorial } } \ No newline at end of file diff --git a/TechbloxModdingAPI/App/Game.cs b/TechbloxModdingAPI/App/Game.cs index 7f52965..aac7cb5 100644 --- a/TechbloxModdingAPI/App/Game.cs +++ b/TechbloxModdingAPI/App/Game.cs @@ -2,12 +2,10 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; -using RobocraftX.Common; using RobocraftX.GUI.MyGamesScreen; -using RobocraftX.StateSync; using Svelto.ECS; +using Techblox.GameSelection; -using TechbloxModdingAPI; using TechbloxModdingAPI.Blocks; using TechbloxModdingAPI.Tasks; using TechbloxModdingAPI.Utility; @@ -318,7 +316,7 @@ namespace TechbloxModdingAPI.App get { if (menuMode || !VerifyMode()) return CurrentGameMode.None; - return (CurrentGameMode) GameMode.CurrentMode; + return gameEngine.GetGameData().gameMode == GameMode.CreateWorld ? CurrentGameMode.Build : CurrentGameMode.Play; } } diff --git a/TechbloxModdingAPI/App/GameBuildSimEventEngine.cs b/TechbloxModdingAPI/App/GameBuildSimEventEngine.cs index 67e6769..1846dd2 100644 --- a/TechbloxModdingAPI/App/GameBuildSimEventEngine.cs +++ b/TechbloxModdingAPI/App/GameBuildSimEventEngine.cs @@ -27,12 +27,14 @@ namespace TechbloxModdingAPI.App public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps) { + Console.WriteLine("Init time running mode"); SimulationMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" }); // TODO return inputDeps; } public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps) { + Console.WriteLine("Init time stopped mode"); BuildMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" }); return inputDeps; } diff --git a/TechbloxModdingAPI/App/GameGameEngine.cs b/TechbloxModdingAPI/App/GameGameEngine.cs index 2bed201..9856da8 100644 --- a/TechbloxModdingAPI/App/GameGameEngine.cs +++ b/TechbloxModdingAPI/App/GameGameEngine.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using HarmonyLib; +using RobocraftX; using RobocraftX.Common; using RobocraftX.Schedulers; using RobocraftX.SimulationModeState; @@ -8,11 +10,15 @@ using Svelto.Tasks; using Svelto.Tasks.Lean; using RobocraftX.Blocks; using RobocraftX.Common.Loading; +using RobocraftX.Multiplayer; using RobocraftX.ScreenshotTaker; using Techblox.Environment.Transition; using Techblox.GameSelection; + using TechbloxModdingAPI.Blocks; using TechbloxModdingAPI.Engines; +using TechbloxModdingAPI.Input; +using TechbloxModdingAPI.Players; using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI.App @@ -30,16 +36,34 @@ namespace TechbloxModdingAPI.App public EntitiesDB entitiesDB { set; private get; } private bool enteredGame; + private bool loadingFinished; + private bool playerJoined; public void Dispose() { + if (GameReloadedPatch.IsReload) + return; // Toggling time mode ExitGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID }); IsInGame = false; + loadingFinished = false; + playerJoined = false; + enteredGame = false; } public void Ready() { + if (GameReloadedPatch.IsReload) + return; // Toggling time mode enteredGame = true; + Player.Joined += OnPlayerJoined; + } + + private void OnPlayerJoined(object sender, PlayerEventArgs args) + { + if (args.Player.Type != PlayerType.Local) return; + playerJoined = true; + Player.Joined -= OnPlayerJoined; + CheckJoinEvent(); } // game functionality @@ -54,7 +78,7 @@ namespace TechbloxModdingAPI.App { if (async) { - ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_TimeRunningAndStopped); + ExitCurrentGameAsync().RunOn(ClientLean.EveryFrameStepRunner_TimeRunningAndStopped); } else { @@ -94,10 +118,23 @@ namespace TechbloxModdingAPI.App public void ToggleTimeMode() { - if (!entitiesDB.FoundInGroups()) - throw new AppStateException("At least one block must exist in the world to enter simulation"); - SwitchAnimationUtil.Start(entitiesDB); - } + if (TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB)) + FakeInput.ActionInput(toggleMode: true); + else + { + IEnumerator ReloadBuildModeTask() + { + SwitchAnimationUtil.Start(entitiesDB); + while (SwitchAnimationUtil.IsFadeOutActive(entitiesDB)) + yield return (TaskContract)Yield.It; + FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer; + AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame") + .Invoke(FullGameFields.Instance, new object[] { }); + } + + ReloadBuildModeTask().RunOn(ClientLean.UIScheduler); + } + } public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid) { @@ -142,9 +179,16 @@ namespace TechbloxModdingAPI.App public void Remove(ref LoadingActionEntityStruct entityComponent, EGID egid) { // Finished loading if (!enteredGame) return; + enteredGame = false; + loadingFinished = true; + CheckJoinEvent(); + } + + private void CheckJoinEvent() + { + if (!loadingFinished || !playerJoined) return; EnterGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID }); IsInGame = true; - enteredGame = false; } } } diff --git a/TechbloxModdingAPI/App/GameMenuEngine.cs b/TechbloxModdingAPI/App/GameMenuEngine.cs index ac24e3a..533b112 100644 --- a/TechbloxModdingAPI/App/GameMenuEngine.cs +++ b/TechbloxModdingAPI/App/GameMenuEngine.cs @@ -3,16 +3,15 @@ using System.Reflection; using HarmonyLib; using RobocraftX; -using RobocraftX.Common; -using RobocraftX.FrontEnd; using RobocraftX.GUI; using RobocraftX.GUI.MyGamesScreen; +using RobocraftX.Multiplayer; using Svelto.ECS; using Svelto.ECS.Experimental; using Techblox.GameSelection; + using TechbloxModdingAPI.Engines; using TechbloxModdingAPI.Utility; -using GameMode = RobocraftX.Common.GameMode; namespace TechbloxModdingAPI.App { @@ -105,20 +104,16 @@ namespace TechbloxModdingAPI.App return EnterGame(mgdes.GameName, mgdes.FileId); } - public bool EnterGame(string gameName, string fileId, bool autoEnterSim = false) + public bool EnterGame(ECSString gameName, string fileId, bool autoEnterSim = false) { - GameMode.CurrentMode = autoEnterSim ? RCXMode.Play : RCXMode.Build; - var data = new GameSelectionData - { - gameMode = Techblox.GameSelection.GameMode.PlayGame, - gameType = GameType.MachineEditor, - saveName = gameName, - saveType = SaveType.ExistingSave, - gameID = "GAMEID_Road_Track", //TODO: Expose to the API - userContentID = fileId - }; - // the private FullGameCompositionRoot.SwitchToGame() method gets passed to menu items for this reason - AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame").Invoke(FullGameFields.Instance, new object[]{data}); + FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer; + ref var selection = ref entitiesDB.QueryEntity(GameSelectionConstants.GameSelectionEGID); + selection.userContentID.Set(fileId); + selection.triggerStart = true; + selection.saveType = SaveType.ExistingSave; + selection.saveName = gameName; + selection.gameMode = GameMode.PlayGame; + selection.gameID.Set("GAMEID_Road_Track"); //TODO: Expose to the API return true; } @@ -161,6 +156,16 @@ namespace TechbloxModdingAPI.App { return ref entitiesDB.QueryEntity(id); } + + internal void CloseBetaPopup() + { + var (buffer, count) = entitiesDB.QueryEntities(ExclusiveGroup.Search("BetaPopup")); + for (int index = 0; index < count; ++index) + { + entitiesDB.QueryEntity(buffer[index].TogglePanelButtonComponent.targetPanel) + .guiRoot.enabled = false; + } + } } internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor { } @@ -178,7 +183,7 @@ namespace TechbloxModdingAPI.App public static MethodBase TargetMethod() { - return AccessTools.Method(typeof(FullGameCompositionRoot), "GoToMenu"); + return AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu"); } } diff --git a/TechbloxModdingAPI/Block.cs b/TechbloxModdingAPI/Block.cs index d752584..7cead56 100644 --- a/TechbloxModdingAPI/Block.cs +++ b/TechbloxModdingAPI/Block.cs @@ -8,9 +8,10 @@ using Svelto.ECS.EntityStructs; using RobocraftX.Common; using RobocraftX.Blocks; using Unity.Mathematics; -using Gamecraft.Blocks.GUI; using HarmonyLib; using RobocraftX.PilotSeat; +using RobocraftX.Rendering; +using Techblox.BlockLabels; using TechbloxModdingAPI.Blocks; using TechbloxModdingAPI.Blocks.Engines; @@ -339,11 +340,9 @@ namespace TechbloxModdingAPI [TestValue(null)] public string Label { - get => BlockEngine.GetBlockInfoViewComponent(this).textLabelComponent?.text; + get => BlockEngine.GetBlockInfo(this).ToString(); //TODO: Block labels set - { - var comp = BlockEngine.GetBlockInfoViewComponent(this).textLabelComponent; - if (comp != null) comp.text = value; + { //TODO } } diff --git a/TechbloxModdingAPI/BlockGroup.cs b/TechbloxModdingAPI/BlockGroup.cs index b8943b8..82f0be0 100644 --- a/TechbloxModdingAPI/BlockGroup.cs +++ b/TechbloxModdingAPI/BlockGroup.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; diff --git a/TechbloxModdingAPI/Blocks/BlockIDs.cs b/TechbloxModdingAPI/Blocks/BlockIDs.cs index e454c40..2e3618f 100644 --- a/TechbloxModdingAPI/Blocks/BlockIDs.cs +++ b/TechbloxModdingAPI/Blocks/BlockIDs.cs @@ -273,6 +273,12 @@ namespace TechbloxModdingAPI.Blocks /// /// The grid block used by the world editor, named Small Grid like the other one /// - SmallGridInWorldEditor + SmallGridInWorldEditor, + SegoeUITextblock = 376, + GravtracTextblock, + HauserTextblock, + TechnopollasTextblock, + BitBlock = 385, + Timer } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Blocks/Engine.cs b/TechbloxModdingAPI/Blocks/Engine.cs index 6140b11..9684108 100644 --- a/TechbloxModdingAPI/Blocks/Engine.cs +++ b/TechbloxModdingAPI/Blocks/Engine.cs @@ -22,7 +22,7 @@ namespace TechbloxModdingAPI.Blocks base(new EGID(id, CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP)) { } - + /* /// /// Gets or sets the Engine's On property. May not be saved. /// @@ -34,6 +34,7 @@ namespace TechbloxModdingAPI.Blocks } set { + Techblox.BlockColours.BlockColoursCompositionRoot BlockEngine.GetBlockInfo(this).engineOn = value; } } @@ -377,6 +378,6 @@ namespace TechbloxModdingAPI.Blocks { BlockEngine.GetBlockInfo(this).manualToAutoGearCoolOffTime = value; } - } + }*/ } } diff --git a/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs b/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs index 01f2d05..a8cd39e 100644 --- a/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs @@ -60,7 +60,7 @@ namespace TechbloxModdingAPI.Blocks.Engines copyToBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock}); - ExclusiveGroupStruct group = WiresExclusiveGroups.WIRES_COPY_GROUP + playerID; + ExclusiveGroupStruct group = BuildModeWiresGroups.WIRES_COPY_GROUP + playerID; copyWireToBlock.Invoke(Patch.createWireEngine, new object[] {group, pickedBlock.ID}); pickedBlock.placedBlockTweaksMustCopy = false; diff --git a/TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs b/TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs index 51b9f4c..789076e 100644 --- a/TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Reflection; using Gamecraft.Blocks.BlockGroups; @@ -173,7 +173,8 @@ namespace TechbloxModdingAPI.Blocks.Engines foreach (var block in blocks) { GhostChildUtility.BuildGhostChild(in playerID, block.Id, in pos, in rot, entitiesDB, - BuildGhostBlueprintFactory, false, bssesopt.Get().buildingDroneReference); + BuildGhostBlueprintFactory, false, bssesopt.Get().buildingDroneReference, + FullGameFields._managers.blockLabelResourceManager); } } @@ -272,7 +273,8 @@ namespace TechbloxModdingAPI.Blocks.Engines uint ghostChildBlockId = CommonExclusiveGroups.GetNewGhostChildBlockID(); var ghostEntityReference = GhostBlockUtils.GetGhostEntityReference(sourceId.entityID, entitiesDB); var entityInitializer = BuildGhostBlueprintFactory.Build( - new EGID(ghostChildBlockId, BoxSelectExclusiveGroups.GhostChildEntitiesExclusiveGroup), /*dbStruct.DBID*/ (uint)BlockIDs.Cube); + new EGID(ghostChildBlockId, BoxSelectExclusiveGroups.GhostChildEntitiesExclusiveGroup), /*dbStruct.DBID*/ (uint)BlockIDs.Cube, + FullGameFields._managers.blockLabelResourceManager); entityInitializer.Init(dbStruct); entityInitializer.Init(new GFXPrefabEntityStructGPUI( PrefabsID.GetOrCreatePrefabID((ushort)entityInitializer.Get().prefabAssetID, diff --git a/TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs b/TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs index 9351623..f9d65d8 100644 --- a/TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs @@ -1,5 +1,5 @@ using RobocraftX.Common; -using RobocraftX.UECS; +using RobocraftX.DOTS; using Svelto.ECS; using Svelto.ECS.EntityStructs; using Unity.Mathematics; @@ -40,7 +40,7 @@ namespace TechbloxModdingAPI.Blocks.Engines ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntityOrDefault(block); ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault(block); ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault(block); + ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault(block); // main (persistent) position posStruct.position = vector; // placement grid position @@ -50,7 +50,7 @@ namespace TechbloxModdingAPI.Blocks.Engines // collision position if (phyStruct.ID != default) { //It exists - FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Translation + FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.dotsEntity, new Translation { Value = posStruct.position }); diff --git a/TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs b/TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs index 9ce7d84..f4ea4c0 100644 --- a/TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs @@ -54,7 +54,8 @@ namespace TechbloxModdingAPI.Blocks.Engines //RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine DBEntityStruct dbEntity = new DBEntityStruct {DBID = block}; - EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.nextBlockEntityID, block); //The ghost block index is only used for triggers + //TODO: Test + EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers uint prefabAssetID = structInitializer.Has() ? structInitializer.Get().prefabAssetID : throw new BlockException("Prefab asset ID not found!"); //Set by the game diff --git a/TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs b/TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs index b2be508..4186bfd 100644 --- a/TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs @@ -1,5 +1,5 @@ using RobocraftX.Common; -using RobocraftX.UECS; +using RobocraftX.DOTS; using Svelto.ECS; using Svelto.ECS.EntityStructs; using Unity.Mathematics; @@ -40,7 +40,7 @@ namespace TechbloxModdingAPI.Blocks.Engines ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntityOrDefault(block); ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault(block); ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault(block); + ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault(block); // main (persistent) rotation Quaternion newRotation = rotStruct.rotation; newRotation.eulerAngles = vector; @@ -52,7 +52,7 @@ namespace TechbloxModdingAPI.Blocks.Engines // collision rotation if (phyStruct.ID != default) { //It exists - FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, + FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.dotsEntity, new Unity.Transforms.Rotation { Value = rotStruct.rotation diff --git a/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs b/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs index 9ca77f0..ef5cfe4 100644 --- a/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs @@ -2,7 +2,7 @@ using HarmonyLib; using RobocraftX.Common; -using RobocraftX.UECS; +using RobocraftX.DOTS; using Svelto.ECS; using Unity.Entities; @@ -13,7 +13,7 @@ namespace TechbloxModdingAPI.Blocks.Engines { public class ScalingEngine : IApiEngine { - private static IReactOnAddAndRemove physicsEngine; + private static IReactOnAddAndRemove physicsEngine; public void Ready() { @@ -34,16 +34,16 @@ namespace TechbloxModdingAPI.Blocks.Engines if (_entityManager == default) _entityManager = FullGameFields._physicsWorld.EntityManager; //Assuming the block exists - var entity = entitiesDB.QueryEntity(egid).uecsEntity; - var pes = new UECSPhysicsEntityCreationStruct(); - physicsEngine.Add(ref pes, egid); //Create new UECS entity + var entity = entitiesDB.QueryEntity(egid).dotsEntity; + var pes = new DOTSPhysicsEntityCreationStruct(); + physicsEngine.Add(ref pes, egid); //Create new DOTS entity _entityManager.DestroyEntity(entity); } [HarmonyPatch] class PhysicsEnginePatch { - static void Postfix(IReactOnAddAndRemove __instance) + static void Postfix(IReactOnAddAndRemove __instance) { physicsEngine = __instance; Logging.MetaDebugLog("Physics engine injected."); @@ -51,7 +51,7 @@ namespace TechbloxModdingAPI.Blocks.Engines static MethodBase TargetMethod(Harmony instance) { - return AccessTools.Method("RobocraftX.StateSync.HandleUECSPhysicEntitiesWithPrefabCreationEngine" + + return AccessTools.Method("RobocraftX.StateSync.HandleDOTSPhysicEntitiesWithPrefabCreationEngine" + ":Ready"); } } diff --git a/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs b/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs index 3c2e1cb..a612ea2 100644 --- a/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs @@ -43,7 +43,7 @@ namespace TechbloxModdingAPI.Blocks.Engines public WireEntityStruct CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort) { - EGID wireEGID = new EGID(WiresExclusiveGroups.NewWireEntityId, NamedExclusiveGroup.Group); + EGID wireEGID = new EGID(BuildModeWiresGroups.NewWireEntityId, BuildModeWiresGroups.WiresGroup.Group); EntityInitializer wireInitializer = Factory.BuildEntity(wireEGID); wireInitializer.Init(new WireEntityStruct { @@ -77,8 +77,8 @@ namespace TechbloxModdingAPI.Blocks.Engines public ref PortEntityStruct GetPortByOffset(BlockPortsStruct bps, byte portNumber, bool input) { ExclusiveGroup group = input - ? NamedExclusiveGroup.Group - : NamedExclusiveGroup.Group; + ? NamedExclusiveGroup.Group + : NamedExclusiveGroup.Group; uint id = (input ? bps.firstInputID : bps.firstOutputID) + portNumber; EGID egid = new EGID(id, group); if (!entitiesDB.Exists(egid)) @@ -193,7 +193,7 @@ namespace TechbloxModdingAPI.Blocks.Engines EGID[] inputs = new EGID[ports.inputCount]; for (uint i = 0; i < ports.inputCount; i++) { - inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup.Group); + inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup.Group); } return inputs; } @@ -204,7 +204,7 @@ namespace TechbloxModdingAPI.Blocks.Engines EGID[] outputs = new EGID[ports.outputCount]; for (uint i = 0; i < ports.outputCount; i++) { - outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup.Group); + outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup.Group); } return outputs; } @@ -219,8 +219,8 @@ namespace TechbloxModdingAPI.Blocks.Engines if (!entitiesDB.Exists(block)) return default; var group = output - ? NamedExclusiveGroup.Group - : NamedExclusiveGroup.Group; + ? NamedExclusiveGroup.Group + : NamedExclusiveGroup.Group; BlockPortsStruct ports = entitiesDB.QueryEntity(block); if (!entitiesDB.TryQueryMappedEntities(group, out var mapper)) return default; @@ -237,7 +237,7 @@ namespace TechbloxModdingAPI.Blocks.Engines public ref WireEntityStruct MatchPortToWire(PortEntityStruct port, EGID blockID, out bool exists) { - var wires = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); + var wires = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); var wiresB = wires.ToBuffer().buffer; for (uint i = 0; i < wires.count; i++) { @@ -264,7 +264,7 @@ namespace TechbloxModdingAPI.Blocks.Engines else { BlockPortsStruct ports = entitiesDB.QueryEntity(startBlock); - startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup.Group) }; + startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup.Group) }; } EGID[] endPorts; @@ -276,10 +276,10 @@ namespace TechbloxModdingAPI.Blocks.Engines else { BlockPortsStruct ports = entitiesDB.QueryEntity(endBlock); - endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup.Group) }; + endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup.Group) }; } - EntityCollection wires = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); + EntityCollection wires = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); var wiresB = wires.ToBuffer().buffer; for (int endIndex = 0; endIndex < endPorts.Length; endIndex++) { @@ -304,7 +304,7 @@ namespace TechbloxModdingAPI.Blocks.Engines public OptionalRef GetChannelDataStruct(EGID portID) { var port = GetPort(portID); - var channels = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); + var channels = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); var channelsB = channels.ToBuffer(); return port.firstChannelIndexCachedInSim < channels.count ? new OptionalRef(channelsB.buffer, port.firstChannelIndexCachedInSim) @@ -329,7 +329,7 @@ namespace TechbloxModdingAPI.Blocks.Engines public EGID[] WiredToInput(EGID block, byte port) { - WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup.Group, + WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup.Group, (WireEntityStruct wes) => wes.destinationPortUsage == port && wes.destinationBlockEGID == block); EGID[] result = new EGID[wireEntityStructs.Length]; for (uint i = 0; i < wireEntityStructs.Length; i++) @@ -342,7 +342,7 @@ namespace TechbloxModdingAPI.Blocks.Engines public EGID[] WiredToOutput(EGID block, byte port) { - WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup.Group, + WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup.Group, (WireEntityStruct wes) => wes.sourcePortUsage == port && wes.sourceBlockEGID == block); EGID[] result = new EGID[wireEntityStructs.Length]; for (uint i = 0; i < wireEntityStructs.Length; i++) @@ -371,13 +371,13 @@ namespace TechbloxModdingAPI.Blocks.Engines private EntityCollection GetSignalStruct(uint signalID, out uint index, bool input = true) { ExclusiveGroup group = input - ? NamedExclusiveGroup.Group - : NamedExclusiveGroup.Group; + ? NamedExclusiveGroup.Group + : NamedExclusiveGroup.Group; if (entitiesDB.Exists(signalID, group)) { index = entitiesDB.QueryEntity(signalID, group).anyChannelIndex; var channelData = - entitiesDB.QueryEntities(NamedExclusiveGroup.Group); + entitiesDB.QueryEntities(NamedExclusiveGroup.Group); return channelData; } diff --git a/TechbloxModdingAPI/Blueprint.cs b/TechbloxModdingAPI/Blueprint.cs index 2724e5a..c49d598 100644 --- a/TechbloxModdingAPI/Blueprint.cs +++ b/TechbloxModdingAPI/Blueprint.cs @@ -1,4 +1,4 @@ -using System; +using System; using Unity.Mathematics; using UnityEngine; diff --git a/TechbloxModdingAPI/Commands/CommandPatch.cs b/TechbloxModdingAPI/Commands/CommandPatch.cs deleted file mode 100644 index b928c1d..0000000 --- a/TechbloxModdingAPI/Commands/CommandPatch.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Reflection; - -using HarmonyLib; -using Svelto.ECS; -using RobocraftX.CR.MainGame; -using RobocraftX.Multiplayer; -using RobocraftX.StateSync; -using TechbloxModdingAPI.Utility; - -namespace TechbloxModdingAPI.Commands -{ - /// - /// Patch of RobocraftX.CR.MainGame.MainGameCompositionRoot.DeterministicCompose() - /// Initializes custom commands - /// - [HarmonyPatch] - static class CommandPatch - { - public static void Postfix(StateSyncRegistrationHelper stateSyncReg) - { - /*CommandLineCompositionRoot.Compose(contextHolder, stateSyncReg.enginesRoot, reloadGame, multiplayerParameters, - stateSyncReg); - uREPL C# compilation not supported anymore */ - var enginesRoot = stateSyncReg.enginesRoot; - CommandManager.RegisterEngines(enginesRoot); - } - - public static MethodInfo TargetMethod() - { - return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose") - .MakeGenericMethod(typeof(object)); - } - } -} \ No newline at end of file diff --git a/TechbloxModdingAPI/EcsObjectBase.cs b/TechbloxModdingAPI/EcsObjectBase.cs index 9698eaa..ba42dc8 100644 --- a/TechbloxModdingAPI/EcsObjectBase.cs +++ b/TechbloxModdingAPI/EcsObjectBase.cs @@ -62,6 +62,7 @@ namespace TechbloxModdingAPI var id = initializer(this); if (!dict.ContainsKey(id)) // Multiple instances may be created dict.Add(id, this); + Id = id; } #region ECS initializer stuff diff --git a/TechbloxModdingAPI/Engines/EnginePatches.cs b/TechbloxModdingAPI/Engines/EnginePatches.cs index 8b6e6a5..d6b61a9 100644 --- a/TechbloxModdingAPI/Engines/EnginePatches.cs +++ b/TechbloxModdingAPI/Engines/EnginePatches.cs @@ -6,27 +6,67 @@ using RobocraftX.FrontEnd; using RobocraftX.StateSync; using Svelto.ECS; using Svelto.ECS.Schedulers; +using TechbloxModdingAPI.Commands; using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI.Engines { [HarmonyPatch] - class GameLoadedEnginePatch + static class GameLoadedTimeStoppedEnginePatch { - public static EntitiesSubmissionScheduler Scheduler { get; private set; } public static void Postfix(StateSyncRegistrationHelper stateSyncReg) { // register all game engines, including deterministic GameEngineManager.RegisterEngines(stateSyncReg); - Scheduler = stateSyncReg.enginesRoot.scheduler; + // register command engines + /*CommandLineCompositionRoot.Compose(contextHolder, stateSyncReg.enginesRoot, reloadGame, multiplayerParameters, + stateSyncReg); - uREPL C# compilation not supported anymore */ + CommandManager.RegisterEngines(stateSyncReg.enginesRoot); } public static MethodBase TargetMethod() { - return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose").MakeGenericMethod(typeof(object)); + return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicTimeStoppedCompose").MakeGenericMethod(typeof(object)); } } + [HarmonyPatch] + static class GameLoadedTimeRunningEnginePatch + { + public static void Postfix(StateSyncRegistrationHelper stateSyncReg) + { + GameEngineManager.RegisterEngines(stateSyncReg); + CommandManager.RegisterEngines(stateSyncReg.enginesRoot); + } + + public static MethodBase TargetMethod() + { + return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicTimeRunningCompose").MakeGenericMethod(typeof(object)); + } + } + + [HarmonyPatch] + static class GameReloadedPatch + { + internal static bool IsReload; + public static void Prefix() => IsReload = true; + public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame"); + } + + [HarmonyPatch] + static class GameSwitchedToPatch + { + public static void Prefix() => GameReloadedPatch.IsReload = false; + public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame"); + } + + [HarmonyPatch] + static class MenuSwitchedToPatch + { + public static void Prefix() => GameReloadedPatch.IsReload = false; + public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu"); + } + [HarmonyPatch] class MenuLoadedEnginePatch { diff --git a/TechbloxModdingAPI/Input/FakeInput.cs b/TechbloxModdingAPI/Input/FakeInput.cs index a3d068a..0b0a7f9 100644 --- a/TechbloxModdingAPI/Input/FakeInput.cs +++ b/TechbloxModdingAPI/Input/FakeInput.cs @@ -1,15 +1,13 @@ -using System; +using RobocraftX.Common.Input; -using RobocraftX.Common; -using RobocraftX.Common.Input; -using Svelto.ECS; +using TechbloxModdingAPI.App; using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI.Input { public static class FakeInput { - private static readonly FakeInputEngine inputEngine = new FakeInputEngine(); + internal static readonly FakeInputEngine inputEngine = new FakeInputEngine(); /// /// Customize the local input. @@ -103,39 +101,39 @@ namespace TechbloxModdingAPI.Input } public static void ActionInput(uint playerID = uint.MaxValue, bool toggleMode = false, bool forward = false, bool backward = false, bool up = false, bool down = false, bool left = false, bool right = false, bool sprint = false, bool toggleFly = false, bool alt = false, bool primary = false, bool secondary = false, bool tertiary = false, bool primaryHeld = false, bool secondaryHeld = false, bool toggleUnitGrid = false, bool ctrl = false, bool toggleColourMode = false, bool scaleBlockUp = false, bool scaleBlockDown = false, bool rotateBlockClockwise = false, bool rotateBlockCounterclockwise = false, bool cutSelection = false, bool copySelection = false, bool deleteSelection = false) - { - if (playerID == uint.MaxValue) - { - playerID = inputEngine.GetLocalPlayerID(); - } - ref LocalPlayerInputEntityStruct currentInput = ref inputEngine.GetPlayerInputRef(playerID); + { // TODO: We can only alter our own inputs clientside + ref var currentInput = ref inputEngine._localInputCache; + //Utility.Logging.CommandLog($"Current sim frame {currentInput.frame}"); // set inputs - if (toggleMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleTimeRunningMode; - if (forward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Forward; - if (backward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Backward; - if (up) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Up; - if (down) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Down; - if (left) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Left; - if (right) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Right; - if (sprint) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Sprint; - //if (toggleFly) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SwitchFlyMode; - //if (alt) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.AltAction; - if (primary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryAction; - if (secondary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryAction; - if (tertiary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.TertiaryAction; - if (primaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryActionHeld; - if (secondaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryActionHeld; - //if (toggleUnitGrid) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid; - if (ctrl) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CtrlAction; - if (toggleColourMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleColourMode; - if (scaleBlockUp) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ScaleBlockUp; - if (scaleBlockDown) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ScaleBlockDown; - if (rotateBlockClockwise) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.RotateBlockClockwise; - if (rotateBlockCounterclockwise) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.RotateBlockAnticlockwise; - if (cutSelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CutSelection; - if (copySelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CopySelection; - if (deleteSelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.DeleteSelection; + if (toggleMode) currentInput |= RobocraftX.Common.Input.ActionInput.ToggleTimeRunningModePlay; //TODO: Test, play + if (forward) currentInput |= RobocraftX.Common.Input.ActionInput.Forward; + if (backward) currentInput |= RobocraftX.Common.Input.ActionInput.Backward; + if (up) currentInput |= RobocraftX.Common.Input.ActionInput.Up; + if (down) currentInput |= RobocraftX.Common.Input.ActionInput.Down; + if (left) currentInput |= RobocraftX.Common.Input.ActionInput.Left; + if (right) currentInput |= RobocraftX.Common.Input.ActionInput.Right; + if (sprint) currentInput |= RobocraftX.Common.Input.ActionInput.Sprint; + //if (toggleFly) currentInput |= RobocraftX.Common.Input.ActionInput.SwitchFlyMode; + //if (alt) currentInput |= RobocraftX.Common.Input.ActionInput.AltAction; + if (primary) currentInput |= RobocraftX.Common.Input.ActionInput.PrimaryActionClick; + if (secondary) currentInput |= RobocraftX.Common.Input.ActionInput.SecondaryActionClick; + if (tertiary) currentInput |= RobocraftX.Common.Input.ActionInput.TertiaryAction; + if (primaryHeld) currentInput |= RobocraftX.Common.Input.ActionInput.PrimaryActionHeld; + if (secondaryHeld) currentInput |= RobocraftX.Common.Input.ActionInput.SecondaryActionHeld; + //if (toggleUnitGrid) currentInput |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid; + if (ctrl) currentInput |= RobocraftX.Common.Input.ActionInput.CtrlAction; + if (toggleColourMode) currentInput |= RobocraftX.Common.Input.ActionInput.ToggleColourMode; + if (scaleBlockUp) currentInput |= RobocraftX.Common.Input.ActionInput.ScaleBlockUp; + if (scaleBlockDown) currentInput |= RobocraftX.Common.Input.ActionInput.ScaleBlockDown; + if (rotateBlockClockwise) currentInput |= RobocraftX.Common.Input.ActionInput.RotateBlockClockwise; + if (rotateBlockCounterclockwise) currentInput |= RobocraftX.Common.Input.ActionInput.RotateBlockAnticlockwise; + if (cutSelection) currentInput |= RobocraftX.Common.Input.ActionInput.CutSelection; + if (copySelection) currentInput |= RobocraftX.Common.Input.ActionInput.CopySelection; + if (deleteSelection) currentInput |= RobocraftX.Common.Input.ActionInput.DeleteSelection; + + if(Game.CurrentGame().IsTimeStopped) + inputEngine.HandleCustomInput(); // Only gets called when online, so calling it here as well } public static void Init() diff --git a/TechbloxModdingAPI/Input/FakeInputEngine.cs b/TechbloxModdingAPI/Input/FakeInputEngine.cs index 7b4528c..cc6a6c2 100644 --- a/TechbloxModdingAPI/Input/FakeInputEngine.cs +++ b/TechbloxModdingAPI/Input/FakeInputEngine.cs @@ -20,6 +20,8 @@ namespace TechbloxModdingAPI.Input public bool IsReady = false; + internal ActionInput _localInputCache; + public void Dispose() { IsReady = false; @@ -86,6 +88,14 @@ namespace TechbloxModdingAPI.Input return ref entitiesDB.QueryEntity(egid); } + internal void HandleCustomInput() + { + if (!LocalPlayerIDUtility.DoesLocalPlayerExist(entitiesDB)) + return; + GetPlayerInputRef(GetLocalPlayerID()).actionMask |= _localInputCache; + _localInputCache = default; + } + public uint GetLocalPlayerID() { return LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB); diff --git a/TechbloxModdingAPI/Input/FakeInputPatch.cs b/TechbloxModdingAPI/Input/FakeInputPatch.cs new file mode 100644 index 0000000..f1a3281 --- /dev/null +++ b/TechbloxModdingAPI/Input/FakeInputPatch.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using HarmonyLib; + +namespace TechbloxModdingAPI.Input +{ + [HarmonyPatch] + public static class FakeInputPatch + { + public static void Prefix() + { + FakeInput.inputEngine.HandleCustomInput(); // This gets called right before the input is sent to the server + } + + public static MethodBase TargetMethod() + { + return AccessTools.Method("RobocraftX.Multiplayer.Input.NetworkInputRecorderEngine:RecordDeterministicInput"); + } + } +} \ No newline at end of file diff --git a/TechbloxModdingAPI/Interface/IMGUI/IMGUIManager.cs b/TechbloxModdingAPI/Interface/IMGUI/IMGUIManager.cs index 8b3c865..c27c484 100644 --- a/TechbloxModdingAPI/Interface/IMGUI/IMGUIManager.cs +++ b/TechbloxModdingAPI/Interface/IMGUI/IMGUIManager.cs @@ -1,13 +1,7 @@ -using System; -using System.Collections; using System.Collections.Generic; -using TechbloxModdingAPI.App; -using TechbloxModdingAPI.Utility; -using Rewired.Internal; -using Svelto.DataStructures; using Svelto.Tasks; using Svelto.Tasks.ExtraLean; -using Svelto.Tasks.ExtraLean.Unity; +using TechbloxModdingAPI.Tasks; using UnityEngine; namespace TechbloxModdingAPI.Interface.IMGUI diff --git a/TechbloxModdingAPI/Main.cs b/TechbloxModdingAPI/Main.cs index 610aa8e..554debe 100644 --- a/TechbloxModdingAPI/Main.cs +++ b/TechbloxModdingAPI/Main.cs @@ -3,13 +3,11 @@ using System.Reflection; using HarmonyLib; using RobocraftX; -using RobocraftX.Schedulers; using RobocraftX.Services; using Svelto.Context; -using Svelto.Tasks.ExtraLean; + using TechbloxModdingAPI.App; using TechbloxModdingAPI.Blocks; -using TechbloxModdingAPI.Events; using TechbloxModdingAPI.Tasks; using TechbloxModdingAPI.Utility; @@ -51,34 +49,42 @@ namespace TechbloxModdingAPI harmony.PatchAll(currentAssembly); } catch (Exception e) - { //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet - Logging.Log(e.ToString()); - Logging.LogWarning("Failed to patch Techblox. Attempting to patch to display error..."); - harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized") - .MakeGenericMethod(typeof(UnityContext)), - new HarmonyMethod(((Action) OnPatchError).Method)); //Can't use lambdas here :( + { + HandleError(e, "Failed to patch Techblox. Attempting to patch to display error...", OnPatchError); return; } - // init utility - Logging.MetaDebugLog($"Initializing Utility"); - Utility.GameState.Init(); - // init block implementors - Logging.MetaDebugLog($"Initializing Blocks"); - // init input - Input.FakeInput.Init(); - // init object-oriented classes - Player.Init(); - Block.Init(); - BlockGroup.Init(); - Wire.Init(); - Logging.MetaDebugLog($"Initializing Client"); - Client.Init(); - Game.Init(); - // init UI - Interface.IMGUI.Constants.Init(); - Interface.IMGUI.IMGUIManager.Init(); - Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); + try + { + // init utility + Logging.MetaDebugLog($"Initializing Utility"); + Utility.GameState.Init(); + // init block implementors + Logging.MetaDebugLog($"Initializing Blocks"); + // init input + Input.FakeInput.Init(); + // init object-oriented classes + Player.Init(); + Block.Init(); + BlockGroup.Init(); + Wire.Init(); + // init client + Logging.MetaDebugLog($"Initializing Client"); + Client.Init(); + Game.Init(); + // init UI + Logging.MetaDebugLog($"Initializing UI"); + Interface.IMGUI.Constants.Init(); + Interface.IMGUI.IMGUIManager.Init(); + // init anti-anticheat + Logging.MetaDebugLog("Initializing anti-anticheat"); + AntiAntiCheatPatch.Init(harmony); + Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); + } + catch (Exception e) + { + HandleError(e, "Failed to initialize the API! Attempting to patch to display error...", OnInitError); + } } /// @@ -109,5 +115,26 @@ namespace TechbloxModdingAPI ErrorBuilder.DisplayMustQuitError("Failed to patch Techblox!\n" + "Make sure you're using the latest version of TechbloxModdingAPI or disable mods if the API isn't released yet."); } + + private static void OnInitError() + { + ErrorBuilder.DisplayMustQuitError("Failed to initialize the modding API!\n" + + "Make sure you're using the latest version. If you are, please report the error."); + } + + /// + /// Handles an init error. Logs the exception, a log message, and allows displaying an error in-game. + /// + /// The exception + /// The log message + /// The action to run when the game is ready to display error messages + private static void HandleError(Exception e, string logMsg, Action onInit) + { //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet + Logging.Log(e.ToString()); + Logging.LogWarning(logMsg); + harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized") + .MakeGenericMethod(typeof(UnityContext)), + new HarmonyMethod(onInit.Method)); //Can't use lambdas here :( + } } } diff --git a/TechbloxModdingAPI/Persistence/SaveGameEnginePatch.cs b/TechbloxModdingAPI/Persistence/SaveGameEnginePatch.cs index 4386d3a..06f4a1a 100644 --- a/TechbloxModdingAPI/Persistence/SaveGameEnginePatch.cs +++ b/TechbloxModdingAPI/Persistence/SaveGameEnginePatch.cs @@ -25,7 +25,7 @@ namespace TechbloxModdingAPI.Persistence Logging.MetaDebugLog("Skipping component serialization: no serializers registered!"); return; } - serializationData.data.ExpandBy((uint)frameStart.Length); + serializationData.data.IncreaseCapacityBy((uint)frameStart.Length); BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out int buffLen), serializationData.dataPos); uint originalPos = serializationData.dataPos; Logging.MetaDebugLog($"dataPos: {originalPos}"); @@ -35,14 +35,14 @@ namespace TechbloxModdingAPI.Persistence bbw.Write(frameStart[i]); } Logging.MetaDebugLog($"dataPos (after frame start): {bbw.Position}"); - serializationData.data.ExpandBy(4u); + serializationData.data.IncreaseCapacityBy(4u); bbw.Write((uint)SerializerManager.GetSerializersCount()); string[] serializerKeys = SerializerManager.GetSerializerNames(); for (uint c = 0; c < serializerKeys.Length; c++) { Logging.MetaDebugLog($"dataPos (loop start): {bbw.Position}"); // write component info - serializationData.data.ExpandBy(4u + (uint)serializerKeys[c].Length); + serializationData.data.IncreaseCapacityBy(4u + (uint)serializerKeys[c].Length); bbw.Write((uint)serializerKeys[c].Length); Logging.MetaDebugLog($"dataPos (now): {bbw.Position}"); byte[] nameBytes = Encoding.UTF8.GetBytes(serializerKeys[c]); @@ -51,7 +51,7 @@ namespace TechbloxModdingAPI.Persistence bbw.Write(nameBytes[i]); } Logging.MetaDebugLog($"dataPos (now): {bbw.Position}"); - serializationData.data.ExpandBy(4u); + serializationData.data.IncreaseCapacityBy(4u); serializationData.dataPos = bbw.Position + 4u; Logging.MetaDebugLog($"dataPos (now): {bbw.Position}"); Logging.MetaDebugLog($"dataPos (appears to be): {serializationData.dataPos}"); @@ -73,8 +73,8 @@ namespace TechbloxModdingAPI.Persistence } public static MethodBase TargetMethod() - { - return typeof(SaveGameEngine).GetMethod("SerializeGameToBuffer"); + { + return AccessTools.TypeByName("RobocraftX.SaveAndLoad.SaveGameEngine").GetMethod("SerializeGameToBuffer"); } } } diff --git a/TechbloxModdingAPI/Persistence/SimpleEntitySerializer.cs b/TechbloxModdingAPI/Persistence/SimpleEntitySerializer.cs index 10e7ce1..57f787a 100644 --- a/TechbloxModdingAPI/Persistence/SimpleEntitySerializer.cs +++ b/TechbloxModdingAPI/Persistence/SimpleEntitySerializer.cs @@ -46,7 +46,7 @@ namespace TechbloxModdingAPI.Persistence public bool Serialize(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer) { - serializationData.data.ExpandBy(4u); + serializationData.data.IncreaseCapacityBy(4u); BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out int count), serializationData.dataPos); EGID[] toSerialize = getEntitiesToSerialize(entitiesDB); bbw.Write((uint)toSerialize.Length); diff --git a/TechbloxModdingAPI/Player.Events.cs b/TechbloxModdingAPI/Player.Events.cs index 1a07c36..8d8cd10 100644 --- a/TechbloxModdingAPI/Player.Events.cs +++ b/TechbloxModdingAPI/Player.Events.cs @@ -20,6 +20,22 @@ namespace TechbloxModdingAPI add => seatExited += value; remove => seatExited -= value; } + + internal static WrappedHandler joined; + + public static event EventHandler Joined + { + add => joined += value; + remove => joined -= value; + } + + internal static WrappedHandler left; + + public static event EventHandler Left + { + add => left += value; + remove => left -= value; + } } public struct PlayerSeatEventArgs @@ -27,4 +43,10 @@ namespace TechbloxModdingAPI public EGID SeatId; public Seat Seat => (Seat)Block.New(SeatId); } + + public struct PlayerEventArgs + { + public EGID PlayerId; + public Player Player => Player.GetInstance(PlayerId.entityID); + } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Player.cs b/TechbloxModdingAPI/Player.cs index 2ce88f1..63d13e0 100644 --- a/TechbloxModdingAPI/Player.cs +++ b/TechbloxModdingAPI/Player.cs @@ -23,8 +23,8 @@ namespace TechbloxModdingAPI public partial class Player : EcsObjectBase, IEquatable, IEquatable { // static functionality - private static PlayerEngine playerEngine = new PlayerEngine(); - private static PlayerEventsEngine playerEventsEngine = new PlayerEventsEngine(); + private static readonly PlayerEngine playerEngine = new PlayerEngine(); + private static readonly PlayerEventsEngine playerEventsEngine = new PlayerEventsEngine(); private static Player localPlayer; /// @@ -76,6 +76,12 @@ namespace TechbloxModdingAPI } } + internal static Player GetInstance(uint id) + { + return EcsObjectBase.GetInstance(new EGID(id, CharacterExclusiveGroups.OnFootGroup), + e => new Player(e.entityID)); + } + /// /// Initializes a new instance of the class. /// @@ -119,6 +125,7 @@ namespace TechbloxModdingAPI }) { this.Type = player; + Id = base.Id.entityID; } // object fields & properties @@ -187,8 +194,6 @@ namespace TechbloxModdingAPI public float Mass => 1f / playerEngine.GetCharacterStruct(Id).Get().physicsMass.InverseMass; - private float _ping = -1f; - /// /// The player's latest network ping time. /// @@ -197,12 +202,7 @@ namespace TechbloxModdingAPI { get { - var opt = playerEngine.GetPlayerStruct(Id, Type); - if (opt) - { - _ping = opt.Get().lastPingTimeSinceLevelLoad ?? _ping; - } - return _ping; + return playerEngine.GetPing() / 1000f; } } @@ -435,15 +435,38 @@ namespace TechbloxModdingAPI playerEngine.SetLocation(Id, location, exitSeat: exitSeat); } + /// + /// Enter the given seat. + /// + /// The seat to enter. public void EnterSeat(Seat seat) { playerEngine.EnterSeat(Id, seat.Id); } + /// + /// Exit the seat the player is currently in. + /// public void ExitSeat() { playerEngine.ExitSeat(Id); } + + /// + /// Spawn the machine the player is holding in time running mode. + /// + public bool SpawnMachine() + { + return playerEngine.SpawnMachine(Id); + } + + /// + /// Despawn the player's machine in time running mode and place it in their hand. + /// + public bool DespawnMachine() + { + return playerEngine.DespawnMachine(Id); + } /// /// Returns the block the player is currently looking at in build mode. @@ -481,7 +504,7 @@ namespace TechbloxModdingAPI { var egid = playerEngine.GetThingLookedAt(Id, maxDistance); return egid != default && egid.groupID == WiresGUIExclusiveGroups.WireGroup - ? EcsObjectBase.GetInstance(new EGID(egid.entityID, NamedExclusiveGroup.Group), + ? EcsObjectBase.GetInstance(new EGID(egid.entityID, BuildModeWiresGroups.WiresGroup.Group), e => new Wire(e)) : null; } diff --git a/TechbloxModdingAPI/Players/PlayerEngine.cs b/TechbloxModdingAPI/Players/PlayerEngine.cs index 0dc2298..bf9c548 100644 --- a/TechbloxModdingAPI/Players/PlayerEngine.cs +++ b/TechbloxModdingAPI/Players/PlayerEngine.cs @@ -10,7 +10,9 @@ using RobocraftX.Physics; using RobocraftX.Blocks.Ghost; using Gamecraft.GUI.HUDFeedbackBlocks; using RobocraftX.Blocks; +using RobocraftX.Multiplayer; using RobocraftX.PilotSeat; +using RobocraftX.SimulationModeState; using Svelto.ECS; using Techblox.Camera; using Unity.Mathematics; @@ -19,6 +21,7 @@ using Svelto.ECS.EntityStructs; using Techblox.BuildingDrone; using TechbloxModdingAPI.Engines; +using TechbloxModdingAPI.Input; using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI.Players @@ -204,6 +207,8 @@ namespace TechbloxModdingAPI.Players public void EnterSeat(uint playerId, EGID seatId) { + if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) + return; PilotSeatGroupUtils.SwapTagTo(Functions, seatId); var opt = GetCharacterStruct(playerId, out var group); if (!opt) return; @@ -221,11 +226,46 @@ namespace TechbloxModdingAPI.Players public void ExitSeat(uint playerId) { + if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) + return; EGID egid = new EGID(playerId, CharacterExclusiveGroups.InPilotSeatGroup); var opt = entitiesDB.QueryEntityOptional(egid); if (!opt) return; opt.Get().instantExit = true; entitiesDB.PublishEntityChange(egid); } + + public bool SpawnMachine(uint playerId) + { + if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) + return false; + EGID egid = new EGID(playerId, CharacterExclusiveGroups.MachineSpawningGroup); + if (!entitiesDB.Exists(egid)) + return false; + //Functions.SwapEntityGroup(egid, CharacterExclusiveGroups.OnFootGroup); + FakeInput.ActionInput(playerId, primary: true); + return true; + } + + public bool DespawnMachine(uint playerId) + { + if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) + return false; + GetCharacterStruct(playerId, out var group); + if (group.isInvalid) + return false; + EGID egid = new EGID(playerId, group); + if (!entitiesDB.Exists(egid)) + return false; + Functions.SwapEntityGroup(egid, CharacterExclusiveGroups.MachineSpawningGroup); + return true; + } + + public uint GetPing() + { + return entitiesDB + .QueryUniqueEntity(MultiplayerExclusiveGroups.MultiplayerStateGroup) + .networkStats.PingMs; + } } } diff --git a/TechbloxModdingAPI/Players/PlayerEventsEngine.cs b/TechbloxModdingAPI/Players/PlayerEventsEngine.cs index 2c80f24..4461b71 100644 --- a/TechbloxModdingAPI/Players/PlayerEventsEngine.cs +++ b/TechbloxModdingAPI/Players/PlayerEventsEngine.cs @@ -1,11 +1,13 @@ using RobocraftX.Character; using RobocraftX.Character.Movement; +using RobocraftX.Common.Input; using Svelto.ECS; + using TechbloxModdingAPI.Engines; namespace TechbloxModdingAPI.Players { - public class PlayerEventsEngine : IApiEngine, IReactOnSwap + public class PlayerEventsEngine : IApiEngine, IReactOnSwap, IReactOnAddAndRemove { public void Ready() { @@ -21,13 +23,22 @@ namespace TechbloxModdingAPI.Players public void MovedTo(ref CharacterPilotSeatEntityStruct entityComponent, ExclusiveGroupStruct previousGroup, EGID egid) { - var seatId = entityComponent.pilotSeatEntity.ToEGID(entitiesDB); - var player = EcsObjectBase.GetInstance(new EGID(egid.entityID, CharacterExclusiveGroups.OnFootGroup), - e => new Player(e.entityID)); + entitiesDB.TryGetEGID(entityComponent.pilotSeatEntity, out var seatId); //TODO: Can't get EGID + var player = Player.GetInstance(egid.entityID); if (previousGroup == CharacterExclusiveGroups.InPilotSeatGroup) player.seatExited.Invoke(this, new PlayerSeatEventArgs { SeatId = seatId}); else if (egid.groupID == CharacterExclusiveGroups.InPilotSeatGroup) player.seatEntered.Invoke(this, new PlayerSeatEventArgs { SeatId = seatId }); } + + public void Add(ref PlayerIDStruct entityComponent, EGID egid) + { + Player.joined.Invoke(this, new PlayerEventArgs { PlayerId = egid }); + } + + public void Remove(ref PlayerIDStruct entityComponent, EGID egid) + { + Player.left.Invoke(this, new PlayerEventArgs { PlayerId = egid }); + } } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Players/PlayerTests.cs b/TechbloxModdingAPI/Players/PlayerTests.cs index c974518..1fc4f49 100644 --- a/TechbloxModdingAPI/Players/PlayerTests.cs +++ b/TechbloxModdingAPI/Players/PlayerTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Svelto.Tasks; using Svelto.Tasks.Enumerators; @@ -7,6 +8,7 @@ using Unity.Mathematics; using TechbloxModdingAPI.App; using TechbloxModdingAPI.Blocks; using TechbloxModdingAPI.Tests; +using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI.Players { @@ -45,7 +47,20 @@ namespace TechbloxModdingAPI.Players [APITestCase(TestType.SimulationMode)] public static IEnumerator SeatEventTestSim() { + yield return new WaitForSecondsEnumerator(1).Continue(); + Assert.Equal(Player.LocalPlayer.SpawnMachine(), true, "Failed to spawn the player's machine.", "Successfully spawned the player's machine."); + yield return new WaitForSecondsEnumerator(1).Continue(); var seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat); + int c = 0; + while (seats.Length == 0 && c < 10) + { + Logging.MetaLog("Waiting for a seat to be spawned..."); + yield return new WaitForSecondsEnumerator(1).Continue(); + Console.WriteLine("Spawn machine: " + Player.LocalPlayer.SpawnMachine()); + seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat); + c++; + } + if (seats.Length == 0) { Assert.Fail("No driver seat found!"); diff --git a/TechbloxModdingAPI/Tasks/OnGuiRunner.cs b/TechbloxModdingAPI/Tasks/OnGuiRunner.cs new file mode 100644 index 0000000..b3c4000 --- /dev/null +++ b/TechbloxModdingAPI/Tasks/OnGuiRunner.cs @@ -0,0 +1,16 @@ +using System.Collections; +using Svelto.Tasks; +using Svelto.Tasks.ExtraLean; +using Svelto.Tasks.Unity.Internal; + +namespace TechbloxModdingAPI.Tasks +{ + public class OnGuiRunner : BaseRunner> + { + public OnGuiRunner(string name, uint runningOrder = 0) + : base(name) + { + UnityCoroutineRunner.StartOnGuiCoroutine(this._processEnumerator, runningOrder); + } + } +} \ No newline at end of file diff --git a/TechbloxModdingAPI/Tasks/Scheduler.cs b/TechbloxModdingAPI/Tasks/Scheduler.cs index 764e9b7..5ad842e 100644 --- a/TechbloxModdingAPI/Tasks/Scheduler.cs +++ b/TechbloxModdingAPI/Tasks/Scheduler.cs @@ -20,7 +20,7 @@ namespace TechbloxModdingAPI.Tasks { get { - return RobocraftX.Schedulers.Lean.UIScheduler; + return RobocraftX.Schedulers.ClientLean.UIScheduler; } } @@ -28,7 +28,7 @@ namespace TechbloxModdingAPI.Tasks { get { - return RobocraftX.Schedulers.ExtraLean.UIScheduler; + return RobocraftX.Schedulers.ClientExtraLean.UIScheduler; } } diff --git a/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs b/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs index 754d588..9c80ecd 100644 --- a/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs +++ b/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs @@ -10,12 +10,10 @@ using IllusionInjector; using RobocraftX.FrontEnd; using Unity.Mathematics; using UnityEngine; -using RobocraftX.Common.Input; using Svelto.Tasks; using Svelto.Tasks.Lean; using TechbloxModdingAPI.Blocks; using TechbloxModdingAPI.Commands; -using TechbloxModdingAPI.Input; using TechbloxModdingAPI.Players; using TechbloxModdingAPI.Tasks; using TechbloxModdingAPI.Utility; @@ -345,6 +343,11 @@ namespace TechbloxModdingAPI.Tests Logging.CommandLog(asset); } }).Build(); + Client.EnterMenu += (sender, args) => Scheduler.Schedule(new Once(() => Client.Instance.CloseBetaPopup())); + + Game.Enter += (sender, args) => + Console.WriteLine( + $"Current game selection data: {FullGameFields._gameSelectionData.gameMode} - {FullGameFields._gameSelectionData.saveType}"); #if TEST TestRoot.RunTests(); #endif @@ -360,15 +363,6 @@ namespace TechbloxModdingAPI.Tests return modsString = sb.ToString(); } - public override void OnUpdate() - { - if (UnityEngine.Input.GetKeyDown(KeyCode.End)) - { - Console.WriteLine("Pressed button to toggle console"); - FakeInput.CustomInput(new LocalCosmeticInputEntityComponent {commandLineToggleInput = true}); - } - } - [HarmonyPatch] public class MinimumSpecsPatch { diff --git a/TechbloxModdingAPI/Tests/TestRoot.cs b/TechbloxModdingAPI/Tests/TestRoot.cs index 7177818..bffae51 100644 --- a/TechbloxModdingAPI/Tests/TestRoot.cs +++ b/TechbloxModdingAPI/Tests/TestRoot.cs @@ -7,7 +7,9 @@ using System.Linq; // welcome to the dark side using Svelto.Tasks; using Svelto.Tasks.Lean; using Svelto.Tasks.Enumerators; +using Svelto.Tasks.Lean.Unity; using UnityEngine; + using TechbloxModdingAPI.App; using TechbloxModdingAPI.Tasks; using TechbloxModdingAPI.Utility; @@ -64,7 +66,7 @@ namespace TechbloxModdingAPI.Tests _testsCountPassed = 0; _testsCountFailed = 0; // flow control - Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_TimeRunningAndStopped); }; + Game.Enter += (sender, args) => { GameTests().RunOn(new UpdateMonoRunner("TechbloxModdingAPITestRunner")); }; Game.Exit += (s, a) => state = "ReturningFromGame"; Client.EnterMenu += (sender, args) => { @@ -129,7 +131,7 @@ namespace TechbloxModdingAPI.Tests private static IEnumerator GoToGameTests() { - Client app = new Client(); + Client app = Client.Instance; int oldLength = 0; while (app.MyGames.Length == 0 || oldLength != app.MyGames.Length) { @@ -137,7 +139,15 @@ namespace TechbloxModdingAPI.Tests yield return new WaitForSecondsEnumerator(1).Continue(); } yield return Yield.It; - app.MyGames[0].EnterGame(); + try + { + app.MyGames[0].EnterGame(); + } + catch (Exception e) + { + Console.WriteLine("Failed to go to game tests"); + Console.WriteLine(e); + } /*Game newGame = Game.NewGame(); yield return new WaitForSecondsEnumerator(5).Continue(); // wait for sync newGame.EnterGame();*/ @@ -157,6 +167,7 @@ namespace TechbloxModdingAPI.Tests }; for (var index = 0; index < testTypesToRun.Length; index++) { + Logging.MetaLog($"Running test type {testTypesToRun[index]}"); foreach (Type t in testTypes) { foreach (MethodBase m in t.GetMethods()) @@ -198,7 +209,16 @@ namespace TechbloxModdingAPI.Tests } if (index + 1 < testTypesToRun.Length) //Don't toggle on the last test + { + bool running = currentGame.IsTimeRunning; currentGame.ToggleTimeMode(); + while (running ? !currentGame.IsTimeStopped : !currentGame.IsTimeRunning) + { + Logging.MetaLog($"Waiting for time to {(running?"stop":"start")}..."); + yield return new WaitForSecondsEnumerator(1).Continue(); + } + } + yield return new WaitForSecondsEnumerator(5).Continue(); } // exit game diff --git a/TechbloxModdingAPI/Utility/FullGameFields.cs b/TechbloxModdingAPI/Utility/FullGameFields.cs index 0a4dd1d..de9f487 100644 --- a/TechbloxModdingAPI/Utility/FullGameFields.cs +++ b/TechbloxModdingAPI/Utility/FullGameFields.cs @@ -1,20 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using DataLoader; +using DataLoader; using HarmonyLib; using RobocraftX; -using RobocraftX.Common.Utilities; +using RobocraftX.CR.MainGame; using RobocraftX.GUI; using RobocraftX.Multiplayer; -using RobocraftX.Rendering; using Svelto.Context; using Svelto.DataStructures; using Svelto.ECS; -using Svelto.ECS.Schedulers; +using Svelto.ECS.GUI; +using Techblox.GameSelection; using UnityEngine; using Unity.Entities; using Unity.Physics.Systems; @@ -104,14 +98,6 @@ namespace TechbloxModdingAPI.Utility } } - public static PhysicsUtility _physicsUtility - { - get - { - return (PhysicsUtility)fgcr?.Field("_physicsUtility").GetValue(); - } - } - /*public static UnityEntitySubmissionScheduler _frontEndSubmissionScheduler { get @@ -136,11 +122,11 @@ namespace TechbloxModdingAPI.Utility } } - public static ECSGameObjectResourceManager _eCsGameObjectResourceManager + public static ECSResourceManagers _managers { get { - return (ECSGameObjectResourceManager)fgcr?.Field("_eCsGameObjectResourceManager").GetValue(); + return (ECSResourceManagers)fgcr?.Field("_managers").GetValue(); } } @@ -160,6 +146,22 @@ namespace TechbloxModdingAPI.Utility } } + public static SveltoGUI _frontEndGUI + { + get + { + return (SveltoGUI)fgcr?.Field("_frontEndGUI").GetValue(); + } + } + + public static GameSelectionData _gameSelectionData + { + get + { + return (GameSelectionData)fgcr?.Field("_gameSelectionData").GetValue(); + } + } + private static Traverse fgcr; public static void Init(FullGameCompositionRoot instance) diff --git a/TechbloxModdingAPI/Utility/GameEngineManager.cs b/TechbloxModdingAPI/Utility/GameEngineManager.cs index 16bf4e2..04b0da7 100644 --- a/TechbloxModdingAPI/Utility/GameEngineManager.cs +++ b/TechbloxModdingAPI/Utility/GameEngineManager.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using RobocraftX.StateSync; using Svelto.ECS; diff --git a/TechbloxModdingAPI/Utility/WrappedHandler.cs b/TechbloxModdingAPI/Utility/WrappedHandler.cs index 57ff3ba..41e2fc7 100644 --- a/TechbloxModdingAPI/Utility/WrappedHandler.cs +++ b/TechbloxModdingAPI/Utility/WrappedHandler.cs @@ -34,6 +34,12 @@ namespace TechbloxModdingAPI.Utility Logging.LogWarning(wrappedException.ToString()); } }; + if (wrappers.ContainsKey(added)) + { + original.eventHandler -= wrapped; + wrappers.Remove(added); + } + wrappers.Add(added, wrapped); return new WrappedHandler { eventHandler = original.eventHandler + wrapped }; }