Browse Source

Merge branch 'preview'

# Conflicts:
#	Automation/gen_csproj.py
#	TechbloxModdingAPI/TechbloxModdingAPI.csproj
tags/v2.2.0
NorbiPeti 2 years ago
parent
commit
09d3c5e81c
43 changed files with 623 additions and 317 deletions
  1. +56
    -0
      TechbloxModdingAPI/App/AntiAntiCheatPatch.cs
  2. +0
    -44
      TechbloxModdingAPI/App/AppEngine.cs
  3. +41
    -18
      TechbloxModdingAPI/App/Client.cs
  4. +14
    -6
      TechbloxModdingAPI/App/ClientAlertTest.cs
  5. +9
    -5
      TechbloxModdingAPI/App/CurrentGameMode.cs
  6. +2
    -4
      TechbloxModdingAPI/App/Game.cs
  7. +2
    -0
      TechbloxModdingAPI/App/GameBuildSimEventEngine.cs
  8. +50
    -6
      TechbloxModdingAPI/App/GameGameEngine.cs
  9. +22
    -17
      TechbloxModdingAPI/App/GameMenuEngine.cs
  10. +4
    -5
      TechbloxModdingAPI/Block.cs
  11. +1
    -1
      TechbloxModdingAPI/BlockGroup.cs
  12. +7
    -1
      TechbloxModdingAPI/Blocks/BlockIDs.cs
  13. +3
    -2
      TechbloxModdingAPI/Blocks/Engine.cs
  14. +1
    -1
      TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs
  15. +5
    -3
      TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs
  16. +3
    -3
      TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs
  17. +2
    -1
      TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs
  18. +3
    -3
      TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs
  19. +7
    -7
      TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs
  20. +17
    -17
      TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs
  21. +1
    -1
      TechbloxModdingAPI/Blueprint.cs
  22. +0
    -34
      TechbloxModdingAPI/Commands/CommandPatch.cs
  23. +1
    -0
      TechbloxModdingAPI/EcsObjectBase.cs
  24. +44
    -4
      TechbloxModdingAPI/Engines/EnginePatches.cs
  25. +34
    -36
      TechbloxModdingAPI/Input/FakeInput.cs
  26. +10
    -0
      TechbloxModdingAPI/Input/FakeInputEngine.cs
  27. +19
    -0
      TechbloxModdingAPI/Input/FakeInputPatch.cs
  28. +1
    -7
      TechbloxModdingAPI/Interface/IMGUI/IMGUIManager.cs
  29. +55
    -28
      TechbloxModdingAPI/Main.cs
  30. +6
    -6
      TechbloxModdingAPI/Persistence/SaveGameEnginePatch.cs
  31. +1
    -1
      TechbloxModdingAPI/Persistence/SimpleEntitySerializer.cs
  32. +22
    -0
      TechbloxModdingAPI/Player.Events.cs
  33. +34
    -11
      TechbloxModdingAPI/Player.cs
  34. +40
    -0
      TechbloxModdingAPI/Players/PlayerEngine.cs
  35. +15
    -4
      TechbloxModdingAPI/Players/PlayerEventsEngine.cs
  36. +16
    -1
      TechbloxModdingAPI/Players/PlayerTests.cs
  37. +16
    -0
      TechbloxModdingAPI/Tasks/OnGuiRunner.cs
  38. +2
    -2
      TechbloxModdingAPI/Tasks/Scheduler.cs
  39. +5
    -11
      TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs
  40. +23
    -3
      TechbloxModdingAPI/Tests/TestRoot.cs
  41. +22
    -20
      TechbloxModdingAPI/Utility/FullGameFields.cs
  42. +1
    -4
      TechbloxModdingAPI/Utility/GameEngineManager.cs
  43. +6
    -0
      TechbloxModdingAPI/Utility/WrappedHandler.cs

+ 56
- 0
TechbloxModdingAPI/App/AntiAntiCheatPatch.cs View File

@@ -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<TaskContract> __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<bool>) AntiAntiCheat).Method));
harmony.Patch(AccessTools.Method(type, "Shutdown"), new HarmonyMethod(((Func<bool>) 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<TaskContract> __result)
{
IEnumerator<TaskContract> Func()
{
yield return Yield.It;
}

__result = Func();
return false;
}
}
}

+ 0
- 44
TechbloxModdingAPI/App/AppEngine.cs View File

@@ -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<MenuEventArgs> EnterMenu;

public WrappedHandler<MenuEventArgs> 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;
}
}

+ 41
- 18
TechbloxModdingAPI/App/Client.cs View File

@@ -14,12 +14,12 @@ namespace TechbloxModdingAPI.App
/// </summary>
public class Client
{
public static Client Instance { get; } = new Client();
protected static Func<object> ErrorHandlerInstanceGetter;

protected static Action<object, Error> EnqueueError;

protected static Action<object> HandleErrorClosed;

/// <summary>
/// An event that fires whenever the main menu is loaded.
/// </summary>
@@ -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<object, Error>) AccessTools.Method("TechbloxModdingAPI.App.Client:GenEnqueueError")
.MakeGenericMethod(errorHandler, errorHandle)
.Invoke(null, new object[0]);
/*HandleErrorClosed = (Action<object>) 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<object> GenHandlePopupClosed<T>()
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<T> handleSimple =
(Action<T>) Delegate.CreateDelegate(typeof(Action<T>), handlePopupClosed);
Action<object> 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;
}
}
}

+ 14
- 6
TechbloxModdingAPI/App/ClientAlertTest.cs View File

@@ -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

+ 9
- 5
TechbloxModdingAPI/App/CurrentGameMode.cs View File

@@ -1,23 +1,27 @@
namespace TechbloxModdingAPI.App
using System;

namespace TechbloxModdingAPI.App
{
public enum CurrentGameMode
{
None,
/// <summary>
/// Building a game
/// Building a world
/// </summary>
Build,
/// <summary>
/// Playing a game
/// Playing on a map
/// </summary>
Play,
/// <summary>
/// Viewing a prefab
/// Viewing a prefab (doesn't exist anymore)
/// </summary>
[Obsolete]
View,
/// <summary>
/// Viewing a tutorial
/// Viewing a tutorial (doesn't exist anymore)
/// </summary>
[Obsolete]
Tutorial
}
}

+ 2
- 4
TechbloxModdingAPI/App/Game.cs View File

@@ -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;
}
}



+ 2
- 0
TechbloxModdingAPI/App/GameBuildSimEventEngine.cs View File

@@ -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;
}


+ 50
- 6
TechbloxModdingAPI/App/GameGameEngine.cs View File

@@ -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<BlockTagEntityStruct>())
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<TaskContract> 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;
}
}
}

+ 22
- 17
TechbloxModdingAPI/App/GameMenuEngine.cs View File

@@ -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<GameSelectionComponent>(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<T>(id);
}

internal void CloseBetaPopup()
{
var (buffer, count) = entitiesDB.QueryEntities<TogglePanelButtonEntityViewStruct>(ExclusiveGroup.Search("BetaPopup"));
for (int index = 0; index < count; ++index)
{
entitiesDB.QueryEntity<GUIEntityViewStruct>(buffer[index].TogglePanelButtonComponent.targetPanel)
.guiRoot.enabled = false;
}
}
}

internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { }
@@ -178,7 +183,7 @@ namespace TechbloxModdingAPI.App

public static MethodBase TargetMethod()
{
return AccessTools.Method(typeof(FullGameCompositionRoot), "GoToMenu");
return AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu");
}
}


+ 4
- 5
TechbloxModdingAPI/Block.cs View File

@@ -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<TextLabelEntityViewStruct>(this).textLabelComponent?.text;
get => BlockEngine.GetBlockInfo<LabelResourceIDComponent>(this).ToString(); //TODO: Block labels
set
{
var comp = BlockEngine.GetBlockInfoViewComponent<TextLabelEntityViewStruct>(this).textLabelComponent;
if (comp != null) comp.text = value;
{ //TODO
}
}



+ 1
- 1
TechbloxModdingAPI/BlockGroup.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;



+ 7
- 1
TechbloxModdingAPI/Blocks/BlockIDs.cs View File

@@ -273,6 +273,12 @@ namespace TechbloxModdingAPI.Blocks
/// <summary>
/// The grid block used by the world editor, named Small Grid like the other one
/// </summary>
SmallGridInWorldEditor
SmallGridInWorldEditor,
SegoeUITextblock = 376,
GravtracTextblock,
HauserTextblock,
TechnopollasTextblock,
BitBlock = 385,
Timer
}
}

+ 3
- 2
TechbloxModdingAPI/Blocks/Engine.cs View File

@@ -22,7 +22,7 @@ namespace TechbloxModdingAPI.Blocks
base(new EGID(id, CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP))
{
}
/*
/// <summary>
/// Gets or sets the Engine's On property. May not be saved.
/// </summary>
@@ -34,6 +34,7 @@ namespace TechbloxModdingAPI.Blocks
}
set
{
Techblox.BlockColours.BlockColoursCompositionRoot
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).engineOn = value;
}
}
@@ -377,6 +378,6 @@ namespace TechbloxModdingAPI.Blocks
{
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).manualToAutoGearCoolOffTime = value;
}
}
}*/
}
}

+ 1
- 1
TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs View File

@@ -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;


+ 5
- 3
TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs View File

@@ -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<PrefabAssetIDComponent>().prefabAssetID,


+ 3
- 3
TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs View File

@@ -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<PositionEntityStruct>(block);
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<UECSPhysicsEntityStruct>(block);
ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<DOTSPhysicsEntityStruct>(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
});


+ 2
- 1
TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs View File

@@ -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<PrefabAssetIDComponent>()
? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID
: throw new BlockException("Prefab asset ID not found!"); //Set by the game


+ 3
- 3
TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs View File

@@ -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<RotationEntityStruct>(block);
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<UECSPhysicsEntityStruct>(block);
ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<DOTSPhysicsEntityStruct>(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


+ 7
- 7
TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs View File

@@ -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<UECSPhysicsEntityCreationStruct> physicsEngine;
private static IReactOnAddAndRemove<DOTSPhysicsEntityCreationStruct> 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<UECSPhysicsEntityStruct>(egid).uecsEntity;
var pes = new UECSPhysicsEntityCreationStruct();
physicsEngine.Add(ref pes, egid); //Create new UECS entity
var entity = entitiesDB.QueryEntity<DOTSPhysicsEntityStruct>(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<UECSPhysicsEntityCreationStruct> __instance)
static void Postfix(IReactOnAddAndRemove<DOTSPhysicsEntityCreationStruct> __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");
}
}


+ 17
- 17
TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs View File

@@ -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<WiresGroup>.Group);
EGID wireEGID = new EGID(BuildModeWiresGroups.NewWireEntityId, BuildModeWiresGroups.WiresGroup.Group);
EntityInitializer wireInitializer = Factory.BuildEntity<WireEntityDescriptor>(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<InputPortsGroup>.Group
: NamedExclusiveGroup<OutputPortsGroup>.Group;
? NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group
: NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group;
uint id = (input ? bps.firstInputID : bps.firstOutputID) + portNumber;
EGID egid = new EGID(id, group);
if (!entitiesDB.Exists<PortEntityStruct>(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<InputPortsGroup>.Group);
inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.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<OutputPortsGroup>.Group);
outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group);
}
return outputs;
}
@@ -219,8 +219,8 @@ namespace TechbloxModdingAPI.Blocks.Engines
if (!entitiesDB.Exists<BlockPortsStruct>(block))
return default;
var group = output
? NamedExclusiveGroup<OutputPortsGroup>.Group
: NamedExclusiveGroup<InputPortsGroup>.Group;
? NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group
: NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group;
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(block);
if (!entitiesDB.TryQueryMappedEntities<PortEntityStruct>(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<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group);
var wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.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<BlockPortsStruct>(startBlock);
startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup<OutputPortsGroup>.Group) };
startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group) };
}

EGID[] endPorts;
@@ -276,10 +276,10 @@ namespace TechbloxModdingAPI.Blocks.Engines
else
{
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(endBlock);
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<InputPortsGroup>.Group) };
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group) };
}
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group);
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group);
var wiresB = wires.ToBuffer().buffer;
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
{
@@ -304,7 +304,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
public OptionalRef<ChannelDataStruct> GetChannelDataStruct(EGID portID)
{
var port = GetPort(portID);
var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group);
var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group);
var channelsB = channels.ToBuffer();
return port.firstChannelIndexCachedInSim < channels.count
? new OptionalRef<ChannelDataStruct>(channelsB.buffer, port.firstChannelIndexCachedInSim)
@@ -329,7 +329,7 @@ namespace TechbloxModdingAPI.Blocks.Engines

public EGID[] WiredToInput(EGID block, byte port)
{
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<WiresGroup>.Group,
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.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<WiresGroup>.Group,
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.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<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true)
{
ExclusiveGroup group = input
? NamedExclusiveGroup<InputPortsGroup>.Group
: NamedExclusiveGroup<OutputPortsGroup>.Group;
? NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group
: NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group;
if (entitiesDB.Exists<PortEntityStruct>(signalID, group))
{
index = entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).anyChannelIndex;
var channelData =
entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group);
entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group);
return channelData;
}



+ 1
- 1
TechbloxModdingAPI/Blueprint.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using Unity.Mathematics;
using UnityEngine;



+ 0
- 34
TechbloxModdingAPI/Commands/CommandPatch.cs View File

@@ -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
{
/// <summary>
/// Patch of RobocraftX.CR.MainGame.MainGameCompositionRoot.DeterministicCompose<T>()
/// Initializes custom commands
/// </summary>
[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));
}
}
}

+ 1
- 0
TechbloxModdingAPI/EcsObjectBase.cs View File

@@ -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


+ 44
- 4
TechbloxModdingAPI/Engines/EnginePatches.cs View File

@@ -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
{


+ 34
- 36
TechbloxModdingAPI/Input/FakeInput.cs View File

@@ -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();

/// <summary>
/// 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()


+ 10
- 0
TechbloxModdingAPI/Input/FakeInputEngine.cs View File

@@ -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<LocalPlayerInputEntityStruct>(egid);
}

internal void HandleCustomInput()
{
if (!LocalPlayerIDUtility.DoesLocalPlayerExist(entitiesDB))
return;
GetPlayerInputRef(GetLocalPlayerID()).actionMask |= _localInputCache;
_localInputCache = default;
}

public uint GetLocalPlayerID()
{
return LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB);


+ 19
- 0
TechbloxModdingAPI/Input/FakeInputPatch.cs View File

@@ -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");
}
}
}

+ 1
- 7
TechbloxModdingAPI/Interface/IMGUI/IMGUIManager.cs View File

@@ -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


+ 55
- 28
TechbloxModdingAPI/Main.cs View File

@@ -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<FullGameCompositionRoot>)),
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);
}
}

/// <summary>
@@ -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.");
}
/// <summary>
/// Handles an init error. Logs the exception, a log message, and allows displaying an error in-game.
/// </summary>
/// <param name="e">The exception</param>
/// <param name="logMsg">The log message</param>
/// <param name="onInit">The action to run when the game is ready to display error messages</param>
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<FullGameCompositionRoot>)),
new HarmonyMethod(onInit.Method)); //Can't use lambdas here :(
}
}
}

+ 6
- 6
TechbloxModdingAPI/Persistence/SaveGameEnginePatch.cs View File

@@ -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");
}
}
}

+ 1
- 1
TechbloxModdingAPI/Persistence/SimpleEntitySerializer.cs View File

@@ -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);


+ 22
- 0
TechbloxModdingAPI/Player.Events.cs View File

@@ -20,6 +20,22 @@ namespace TechbloxModdingAPI
add => seatExited += value;
remove => seatExited -= value;
}

internal static WrappedHandler<PlayerEventArgs> joined;
public static event EventHandler<PlayerEventArgs> Joined
{
add => joined += value;
remove => joined -= value;
}

internal static WrappedHandler<PlayerEventArgs> left;
public static event EventHandler<PlayerEventArgs> 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);
}
}

+ 34
- 11
TechbloxModdingAPI/Player.cs View File

@@ -23,8 +23,8 @@ namespace TechbloxModdingAPI
public partial class Player : EcsObjectBase, IEquatable<Player>, IEquatable<EGID>
{
// 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;

/// <summary>
@@ -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));
}

/// <summary>
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Player"/> class.
/// </summary>
@@ -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<RigidBodyEntityStruct>(Id).Get().physicsMass.InverseMass;

private float _ping = -1f;

/// <summary>
/// The player's latest network ping time.
/// </summary>
@@ -197,12 +202,7 @@ namespace TechbloxModdingAPI
{
get
{
var opt = playerEngine.GetPlayerStruct<PlayerNetworkStatsEntityStruct>(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);
}

/// <summary>
/// Enter the given seat.
/// </summary>
/// <param name="seat">The seat to enter.</param>
public void EnterSeat(Seat seat)
{
playerEngine.EnterSeat(Id, seat.Id);
}

/// <summary>
/// Exit the seat the player is currently in.
/// </summary>
public void ExitSeat()
{
playerEngine.ExitSeat(Id);
}

/// <summary>
/// Spawn the machine the player is holding in time running mode.
/// </summary>
public bool SpawnMachine()
{
return playerEngine.SpawnMachine(Id);
}

/// <summary>
/// Despawn the player's machine in time running mode and place it in their hand.
/// </summary>
public bool DespawnMachine()
{
return playerEngine.DespawnMachine(Id);
}
/// <summary>
/// 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<WiresGroup>.Group),
? EcsObjectBase.GetInstance(new EGID(egid.entityID, BuildModeWiresGroups.WiresGroup.Group),
e => new Wire(e))
: null;
}


+ 40
- 0
TechbloxModdingAPI/Players/PlayerEngine.cs View File

@@ -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<OCCUPIED_TAG>(Functions, seatId);
var opt = GetCharacterStruct<CharacterPilotSeatEntityStruct>(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<CharacterPilotSeatEntityStruct>(egid);
if (!opt) return;
opt.Get().instantExit = true;
entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid);
}

public bool SpawnMachine(uint playerId)
{
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB))
return false;
EGID egid = new EGID(playerId, CharacterExclusiveGroups.MachineSpawningGroup);
if (!entitiesDB.Exists<CharacterTagEntityStruct>(egid))
return false;
//Functions.SwapEntityGroup<CharacterEntityDescriptor>(egid, CharacterExclusiveGroups.OnFootGroup);
FakeInput.ActionInput(playerId, primary: true);
return true;
}

public bool DespawnMachine(uint playerId)
{
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB))
return false;
GetCharacterStruct<CharacterTagEntityStruct>(playerId, out var group);
if (group.isInvalid)
return false;
EGID egid = new EGID(playerId, group);
if (!entitiesDB.Exists<CharacterTagEntityStruct>(egid))
return false;
Functions.SwapEntityGroup<CharacterEntityDescriptor>(egid, CharacterExclusiveGroups.MachineSpawningGroup);
return true;
}

public uint GetPing()
{
return entitiesDB
.QueryUniqueEntity<NetworkStatsEntityStruct>(MultiplayerExclusiveGroups.MultiplayerStateGroup)
.networkStats.PingMs;
}
}
}

+ 15
- 4
TechbloxModdingAPI/Players/PlayerEventsEngine.cs View File

@@ -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<CharacterPilotSeatEntityStruct>
public class PlayerEventsEngine : IApiEngine, IReactOnSwap<CharacterPilotSeatEntityStruct>, IReactOnAddAndRemove<PlayerIDStruct>
{
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 });
}
}
}

+ 16
- 1
TechbloxModdingAPI/Players/PlayerTests.cs View File

@@ -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<TaskContract> 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!");


+ 16
- 0
TechbloxModdingAPI/Tasks/OnGuiRunner.cs View File

@@ -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<ExtraLeanSveltoTask<IEnumerator>>
{
public OnGuiRunner(string name, uint runningOrder = 0)
: base(name)
{
UnityCoroutineRunner.StartOnGuiCoroutine(this._processEnumerator, runningOrder);
}
}
}

+ 2
- 2
TechbloxModdingAPI/Tasks/Scheduler.cs View File

@@ -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;
}
}



+ 5
- 11
TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs View File

@@ -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
{


+ 23
- 3
TechbloxModdingAPI/Tests/TestRoot.cs View File

@@ -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<TaskContract> 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


+ 22
- 20
TechbloxModdingAPI/Utility/FullGameFields.cs View File

@@ -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)


+ 1
- 4
TechbloxModdingAPI/Utility/GameEngineManager.cs View File

@@ -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;


+ 6
- 0
TechbloxModdingAPI/Utility/WrappedHandler.cs View File

@@ -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<T> { eventHandler = original.eventHandler + wrapped };
}


Loading…
Cancel
Save