All kinds of fixes of issues during automatic tests
- Fixed toggling time running mode - Fixed closing popups - Added support for pressing the buttons on a popup - Added error handling to Main.Init() - Automatically closing the beta message in the test plugin - Fixed Game.EnterGame() causing a crash in the game
This commit is contained in:
parent
93a0b2287a
commit
5602ef9268
11 changed files with 188 additions and 123 deletions
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
// 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.Close();
|
||||
}
|
||||
|
||||
public void SelectFirstPromptButton()
|
||||
{
|
||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
||||
popup.FirstButton();
|
||||
}
|
||||
|
||||
public void SelectSecondPromptButton()
|
||||
{
|
||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using HarmonyLib;
|
||||
using RobocraftX;
|
||||
using RobocraftX.Common;
|
||||
using RobocraftX.Schedulers;
|
||||
using RobocraftX.SimulationModeState;
|
||||
|
@ -9,11 +10,14 @@ 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;
|
||||
|
||||
|
@ -52,9 +56,7 @@ namespace TechbloxModdingAPI.App
|
|||
|
||||
private void OnPlayerJoined(object sender, PlayerEventArgs args)
|
||||
{
|
||||
Console.WriteLine("Player joined: " + args.PlayerId + " asd");
|
||||
if (args.Player.Type != PlayerType.Local) return;
|
||||
Console.WriteLine("Player joined is local asd");
|
||||
playerJoined = true;
|
||||
Player.Joined -= OnPlayerJoined;
|
||||
CheckJoinEvent();
|
||||
|
@ -112,9 +114,22 @@ 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");
|
||||
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)
|
||||
|
@ -162,13 +177,11 @@ namespace TechbloxModdingAPI.App
|
|||
if (!enteredGame) return;
|
||||
enteredGame = false;
|
||||
loadingFinished = true;
|
||||
Console.WriteLine("Loading finished - asd");
|
||||
CheckJoinEvent();
|
||||
}
|
||||
|
||||
private void CheckJoinEvent()
|
||||
{
|
||||
Console.WriteLine($"Check: {loadingFinished} {playerJoined}");
|
||||
if (!loadingFinished || !playerJoined) return;
|
||||
EnterGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID });
|
||||
IsInGame = true;
|
||||
|
|
|
@ -5,6 +5,7 @@ using HarmonyLib;
|
|||
using RobocraftX;
|
||||
using RobocraftX.GUI;
|
||||
using RobocraftX.GUI.MyGamesScreen;
|
||||
using RobocraftX.Multiplayer;
|
||||
using Svelto.ECS;
|
||||
using Svelto.ECS.Experimental;
|
||||
using Techblox.GameSelection;
|
||||
|
@ -103,19 +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)
|
||||
{
|
||||
var data = new GameSelectionData
|
||||
{
|
||||
gameMode = Techblox.GameSelection.GameMode.PlayGame,
|
||||
isOnline = false,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -158,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> { }
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace TechbloxModdingAPI.Input
|
|||
ref LocalPlayerInputEntityStruct currentInput = ref inputEngine.GetPlayerInputRef(playerID);
|
||||
//Utility.Logging.CommandLog($"Current sim frame {currentInput.frame}");
|
||||
// set inputs
|
||||
if (toggleMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleTimeRunningModeTest; //TODO: Test, play
|
||||
if (toggleMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleTimeRunningModePlay; //TODO: Test, play
|
||||
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;
|
||||
|
|
|
@ -49,15 +49,13 @@ 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;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// init utility
|
||||
Logging.MetaDebugLog($"Initializing Utility");
|
||||
Utility.GameState.Init();
|
||||
|
@ -83,6 +81,11 @@ namespace TechbloxModdingAPI
|
|||
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>
|
||||
/// Shuts down & cleans up the TechbloxModdingAPI.
|
||||
|
@ -112,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 :(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -343,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
|
||||
|
|
|
@ -129,7 +129,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 +137,15 @@ namespace TechbloxModdingAPI.Tests
|
|||
yield return new WaitForSecondsEnumerator(1).Continue();
|
||||
}
|
||||
yield return Yield.It;
|
||||
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();*/
|
||||
|
|
|
@ -7,6 +7,8 @@ using RobocraftX.Multiplayer;
|
|||
using Svelto.Context;
|
||||
using Svelto.DataStructures;
|
||||
using Svelto.ECS;
|
||||
using Svelto.ECS.GUI;
|
||||
using Techblox.GameSelection;
|
||||
using UnityEngine;
|
||||
using Unity.Entities;
|
||||
using Unity.Physics.Systems;
|
||||
|
@ -144,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)
|
||||
|
|
Loading…
Reference in a new issue