Add Client and Game OOP features (undocumented)
This commit is contained in:
parent
0d17a1b509
commit
c912f3ba64
11 changed files with 809 additions and 1 deletions
31
GamecraftModdingAPI/App/AppCallbacksTest.cs
Normal file
31
GamecraftModdingAPI/App/AppCallbacksTest.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Tests;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
#if TEST
|
||||||
|
[APITestClass]
|
||||||
|
public static class AppCallbacksTest
|
||||||
|
{
|
||||||
|
[APITestStartUp]
|
||||||
|
public static void StartUp()
|
||||||
|
{
|
||||||
|
// this could be split into 6 separate test cases
|
||||||
|
Game.Enter += Assert.CallsBack<GameEventArgs>("GameEnter");
|
||||||
|
Game.Exit += Assert.CallsBack<GameEventArgs>("GameExit");
|
||||||
|
Game.Simulate += Assert.CallsBack<GameEventArgs>("GameSimulate");
|
||||||
|
Game.Edit += Assert.CallsBack<GameEventArgs>("GameEdit");
|
||||||
|
Client.EnterMenu += Assert.CallsBack<MenuEventArgs>("MenuEnter");
|
||||||
|
Client.ExitMenu += Assert.CallsBack<MenuEventArgs>("MenuExit");
|
||||||
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.Game)]
|
||||||
|
public static void Test()
|
||||||
|
{
|
||||||
|
// the test is actually completely implemented in StartUp()
|
||||||
|
// this is here just so it looks less weird (not required)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
63
GamecraftModdingAPI/App/AppEngine.cs
Normal file
63
GamecraftModdingAPI/App/AppEngine.cs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.GUI.MyGamesScreen;
|
||||||
|
using RobocraftX.GUI;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Engines;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
public class AppEngine : IFactoryEngine
|
||||||
|
{
|
||||||
|
public event EventHandler<MenuEventArgs> EnterMenu;
|
||||||
|
|
||||||
|
public event EventHandler<MenuEventArgs> ExitMenu;
|
||||||
|
|
||||||
|
public IEntityFactory Factory { set; private get; }
|
||||||
|
|
||||||
|
public string Name => "GamecraftModdingAPIAppEngine";
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInMenu = false;
|
||||||
|
ExceptionUtil.InvokeEvent(ExitMenu, this, new MenuEventArgs { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInMenu = true;
|
||||||
|
ExceptionUtil.InvokeEvent(EnterMenu, this, new MenuEventArgs { });
|
||||||
|
}
|
||||||
|
|
||||||
|
// app functionality
|
||||||
|
|
||||||
|
public bool IsInMenu
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
} = false;
|
||||||
|
|
||||||
|
public Game[] GetMyGames()
|
||||||
|
{
|
||||||
|
EntityCollection<MyGameDataEntityStruct> mgsevs = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||||
|
Game[] games = new Game[mgsevs.count];
|
||||||
|
for (int i = 0; i < mgsevs.count; i++)
|
||||||
|
{
|
||||||
|
Utility.Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}");
|
||||||
|
games[i] = new Game(mgsevs[i].ID);
|
||||||
|
}
|
||||||
|
return games;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct MenuEventArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
42
GamecraftModdingAPI/App/AppExceptions.cs
Normal file
42
GamecraftModdingAPI/App/AppExceptions.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
public class AppException : GamecraftModdingAPIException
|
||||||
|
{
|
||||||
|
public AppException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AppStateException : AppException
|
||||||
|
{
|
||||||
|
public AppStateException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppStateException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameNotFoundException : AppException
|
||||||
|
{
|
||||||
|
public GameNotFoundException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameNotFoundException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
GamecraftModdingAPI/App/Client.cs
Normal file
49
GamecraftModdingAPI/App/Client.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
public class Client
|
||||||
|
{
|
||||||
|
protected static AppEngine appEngine = new AppEngine();
|
||||||
|
|
||||||
|
public static event EventHandler<MenuEventArgs> EnterMenu
|
||||||
|
{
|
||||||
|
add => appEngine.EnterMenu += value;
|
||||||
|
remove => appEngine.EnterMenu -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static event EventHandler<MenuEventArgs> ExitMenu
|
||||||
|
{
|
||||||
|
add => appEngine.ExitMenu += value;
|
||||||
|
remove => appEngine.ExitMenu -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Version
|
||||||
|
{
|
||||||
|
get => Application.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UnityVersion
|
||||||
|
{
|
||||||
|
get => Application.unityVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Game[] MyGames
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!appEngine.IsInMenu) return new Game[0];
|
||||||
|
return appEngine.GetMyGames();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Init()
|
||||||
|
{
|
||||||
|
MenuEngineManager.AddMenuEngine(appEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
331
GamecraftModdingAPI/App/Game.cs
Normal file
331
GamecraftModdingAPI/App/Game.cs
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.GUI.MyGamesScreen;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Tasks;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
// TODO: exceptions
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
public class Game
|
||||||
|
{
|
||||||
|
protected static GameGameEngine gameEngine = new GameGameEngine();
|
||||||
|
protected static GameMenuEngine menuEngine = new GameMenuEngine();
|
||||||
|
protected static DebugInterfaceEngine debugOverlayEngine = new DebugInterfaceEngine();
|
||||||
|
protected static GameBuildSimEventEngine buildSimEventEngine = new GameBuildSimEventEngine();
|
||||||
|
|
||||||
|
private List<string> debugIds = new List<string>();
|
||||||
|
|
||||||
|
private bool menuMode = true;
|
||||||
|
private bool hasId = false;
|
||||||
|
|
||||||
|
public Game(uint id) : this(new EGID(id, MyGamesScreenExclusiveGroups.MyGames))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Game(EGID id)
|
||||||
|
{
|
||||||
|
this.Id = id.entityID;
|
||||||
|
this.EGID = id;
|
||||||
|
this.hasId = true;
|
||||||
|
menuMode = true;
|
||||||
|
if (!VerifyMode()) throw new AppStateException("Game cannot be created while not in a game nor in a menu (is the game in a loading screen?)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Game()
|
||||||
|
{
|
||||||
|
menuMode = false;
|
||||||
|
if (!VerifyMode()) throw new AppStateException("Game cannot be created while not in a game nor in a menu (is the game in a loading screen?)");
|
||||||
|
if (menuEngine.IsInMenu) throw new GameNotFoundException("Game not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Game CurrentGame()
|
||||||
|
{
|
||||||
|
return new Game();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Game NewGame()
|
||||||
|
{
|
||||||
|
if (!menuEngine.IsInMenu) throw new AppStateException("New Game cannot be created while not in a menu.");
|
||||||
|
uint nextId = menuEngine.HighestID() + 1;
|
||||||
|
EGID egid = new EGID(nextId, MyGamesScreenExclusiveGroups.MyGames);
|
||||||
|
menuEngine.CreateMyGame(egid);
|
||||||
|
return new Game(egid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static event EventHandler<GameEventArgs> Simulate
|
||||||
|
{
|
||||||
|
add => buildSimEventEngine.SimulationMode += value;
|
||||||
|
remove => buildSimEventEngine.SimulationMode -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static event EventHandler<GameEventArgs> Edit
|
||||||
|
{
|
||||||
|
add => buildSimEventEngine.BuildMode += value;
|
||||||
|
remove => buildSimEventEngine.BuildMode -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static event EventHandler<GameEventArgs> Enter
|
||||||
|
{
|
||||||
|
add => gameEngine.EnterGame += value;
|
||||||
|
remove => gameEngine.EnterGame -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static event EventHandler<GameEventArgs> Exit
|
||||||
|
{
|
||||||
|
add => gameEngine.ExitGame += value;
|
||||||
|
remove => gameEngine.ExitGame -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Id
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EGID EGID
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MenuItem
|
||||||
|
{
|
||||||
|
get => menuMode && hasId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return null;
|
||||||
|
if (menuMode) return menuEngine.GetGameInfo(EGID).GameName;
|
||||||
|
return GameMode.SaveGameDetails.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (menuMode)
|
||||||
|
{
|
||||||
|
menuEngine.SetGameName(EGID, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameMode.SaveGameDetails.Name = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return null;
|
||||||
|
if (menuMode) return menuEngine.GetGameInfo(EGID).GameDescription;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (menuMode)
|
||||||
|
{
|
||||||
|
menuEngine.SetGameDescription(EGID, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No description exists in-game
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Path
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return null;
|
||||||
|
if (menuMode) return menuEngine.GetGameInfo(EGID).SavedGamePath;
|
||||||
|
return GameMode.SaveGameDetails.Folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (menuMode)
|
||||||
|
{
|
||||||
|
menuEngine.GetGameInfo(EGID).SavedGamePath.Set(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// this likely breaks things
|
||||||
|
GameMode.SaveGameDetails = new SaveGameDetails(GameMode.SaveGameDetails.Name, value, GameMode.SaveGameDetails.WorkshopId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong WorkshopId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return 0uL;
|
||||||
|
if (menuMode) return 0uL; // MyGames don't have workshop IDs
|
||||||
|
return GameMode.SaveGameDetails.WorkshopId;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
VerifyMode();
|
||||||
|
if (menuMode)
|
||||||
|
{
|
||||||
|
// MyGames don't have workshop IDs
|
||||||
|
// menuEngine.GetGameInfo(EGID).GameName.Set(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// this likely breaks things
|
||||||
|
GameMode.SaveGameDetails = new SaveGameDetails(GameMode.SaveGameDetails.Name, GameMode.SaveGameDetails.Folder, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSimulating
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return false;
|
||||||
|
return !menuMode && gameEngine.IsTimeRunningMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (!menuMode && gameEngine.IsTimeRunningMode() != value)
|
||||||
|
gameEngine.ToggleTimeMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTimeRunning
|
||||||
|
{
|
||||||
|
get => IsSimulating;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
IsSimulating = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTimeStopped
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return false;
|
||||||
|
return !menuMode && gameEngine.IsTimeStoppedMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (!menuMode && gameEngine.IsTimeStoppedMode() != value)
|
||||||
|
gameEngine.ToggleTimeMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleTimeMode()
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (menuMode || !gameEngine.IsInGame)
|
||||||
|
{
|
||||||
|
throw new AppStateException("Game menu item cannot toggle it's time mode");
|
||||||
|
}
|
||||||
|
gameEngine.ToggleTimeMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnterGame()
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (!hasId)
|
||||||
|
{
|
||||||
|
throw new GameNotFoundException("Game has an invalid ID");
|
||||||
|
}
|
||||||
|
ISchedulable task = new Once(() => { menuEngine.EnterGame(EGID); this.menuMode = false; });
|
||||||
|
Scheduler.Schedule(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExitGame()
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (menuMode)
|
||||||
|
{
|
||||||
|
throw new GameNotFoundException("Cannot exit game using menu ID");
|
||||||
|
}
|
||||||
|
ISchedulable task = new Once(() => { gameEngine.ExitCurrentGame(); this.menuMode = true; });
|
||||||
|
Scheduler.Schedule(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddDebugInfo(string id, Func<string> contentGetter)
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return;
|
||||||
|
if (menuMode)
|
||||||
|
{
|
||||||
|
throw new GameNotFoundException("Game object references a menu item but AddDebugInfo only works on the currently-loaded game");
|
||||||
|
}
|
||||||
|
debugOverlayEngine.SetInfo(id, contentGetter);
|
||||||
|
debugIds.Add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RemoveDebugInfo(string id)
|
||||||
|
{
|
||||||
|
if (!VerifyMode()) return false;
|
||||||
|
if (menuMode)
|
||||||
|
{
|
||||||
|
throw new GameNotFoundException("Game object references a menu item but RemoveDebugInfo only works on the currently-loaded game");
|
||||||
|
}
|
||||||
|
if (!debugIds.Contains(id)) return false;
|
||||||
|
debugOverlayEngine.RemoveInfo(id);
|
||||||
|
return debugIds.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Game()
|
||||||
|
{
|
||||||
|
foreach (string id in debugIds)
|
||||||
|
{
|
||||||
|
debugOverlayEngine.RemoveInfo(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private bool VerifyMode()
|
||||||
|
{
|
||||||
|
if (menuMode && (!menuEngine.IsInMenu || gameEngine.IsInGame))
|
||||||
|
{
|
||||||
|
// either game loading or API is broken
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!menuMode && (menuEngine.IsInMenu || !gameEngine.IsInGame))
|
||||||
|
{
|
||||||
|
// either game loading or API is broken
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(gameEngine);
|
||||||
|
GameEngineManager.AddGameEngine(debugOverlayEngine);
|
||||||
|
MenuEngineManager.AddMenuEngine(menuEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void InitDeterministic(StateSyncRegistrationHelper stateSyncReg)
|
||||||
|
{
|
||||||
|
stateSyncReg.AddDeterministicEngine(buildSimEventEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
GamecraftModdingAPI/App/GameBuildSimEventEngine.cs
Normal file
48
GamecraftModdingAPI/App/GameBuildSimEventEngine.cs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Unity.Jobs;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Engines;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
public class GameBuildSimEventEngine : IApiEngine, IUnorderedInitializeOnTimeRunningModeEntered, IUnorderedInitializeOnTimeStoppedModeEntered
|
||||||
|
{
|
||||||
|
public event EventHandler<GameEventArgs> SimulationMode;
|
||||||
|
|
||||||
|
public event EventHandler<GameEventArgs> BuildMode;
|
||||||
|
|
||||||
|
public string Name => "GamecraftModdingAPIBuildSimEventGameEngine";
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public void Ready() { }
|
||||||
|
|
||||||
|
public JobHandle OnInitializeTimeRunningMode()
|
||||||
|
{
|
||||||
|
ExceptionUtil.InvokeEvent(SimulationMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder });
|
||||||
|
return default(JobHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobHandle OnInitializeTimeStoppedMode()
|
||||||
|
{
|
||||||
|
ExceptionUtil.InvokeEvent(BuildMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder });
|
||||||
|
return default(JobHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct GameEventArgs
|
||||||
|
{
|
||||||
|
public string GameName;
|
||||||
|
|
||||||
|
public string GamePath;
|
||||||
|
}
|
||||||
|
}
|
80
GamecraftModdingAPI/App/GameGameEngine.cs
Normal file
80
GamecraftModdingAPI/App/GameGameEngine.cs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
using RobocraftX;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Schedulers;
|
||||||
|
using RobocraftX.SimulationModeState;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.Tasks;
|
||||||
|
using Svelto.Tasks.Lean;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Engines;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
public class GameGameEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public event EventHandler<GameEventArgs> EnterGame;
|
||||||
|
|
||||||
|
public event EventHandler<GameEventArgs> ExitGame;
|
||||||
|
|
||||||
|
public string Name => "GamecraftModdingAPIGameInfoMenuEngine";
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ExceptionUtil.InvokeEvent(ExitGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder });
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
ExceptionUtil.InvokeEvent(EnterGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder });
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// game functionality
|
||||||
|
|
||||||
|
public bool IsInGame
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
} = false;
|
||||||
|
|
||||||
|
public void ExitCurrentGame()
|
||||||
|
{
|
||||||
|
ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<TaskContract> ExitCurrentGameAsync()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
while (Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING.isStopping) { yield return Yield.It; }
|
||||||
|
AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu").Invoke(FullGameFields.Instance, new object[0]);*/
|
||||||
|
yield return Yield.It;
|
||||||
|
entitiesDB.QueryEntity<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID).WantsToQuit = true;
|
||||||
|
entitiesDB.PublishEntityChange<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTimeRunningMode()
|
||||||
|
{
|
||||||
|
return TimeRunningModeUtil.IsTimeRunningMode(entitiesDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTimeStoppedMode()
|
||||||
|
{
|
||||||
|
return TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleTimeMode()
|
||||||
|
{
|
||||||
|
TimeRunningModeUtil.ToggleTimeRunningState(entitiesDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
128
GamecraftModdingAPI/App/GameMenuEngine.cs
Normal file
128
GamecraftModdingAPI/App/GameMenuEngine.cs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
using System;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
using RobocraftX;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.GUI;
|
||||||
|
using RobocraftX.GUI.MyGamesScreen;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.Experimental;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Engines;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
public class GameMenuEngine : IFactoryEngine
|
||||||
|
{
|
||||||
|
public IEntityFactory Factory { set; private get; }
|
||||||
|
|
||||||
|
public string Name => "GamecraftModdingAPIGameInfoGameEngine";
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInMenu = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInMenu = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// game functionality
|
||||||
|
|
||||||
|
public bool IsInMenu
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
} = false;
|
||||||
|
|
||||||
|
public bool CreateMyGame(EGID id, string path = "", uint thumbnailId = 0, string gameName = "", string creatorName = "", string description = "", long createdDate = 0L)
|
||||||
|
{
|
||||||
|
EntityComponentInitializer eci = Factory.BuildEntity<MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal>(id);
|
||||||
|
eci.Init(new MyGameDataEntityStruct
|
||||||
|
{
|
||||||
|
SavedGamePath = new ECSString(path),
|
||||||
|
ThumbnailId = thumbnailId,
|
||||||
|
GameName = new ECSString(gameName),
|
||||||
|
CreatorName = new ECSString(creatorName),
|
||||||
|
GameDescription = new ECSString(description),
|
||||||
|
CreatedDate = createdDate,
|
||||||
|
});
|
||||||
|
// entitiesDB.PublishEntityChange<MyGameDataEntityStruct>(id); // this will always fail
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint HighestID()
|
||||||
|
{
|
||||||
|
EntityCollection<MyGameDataEntityStruct> games = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||||
|
uint max = 0;
|
||||||
|
for (int i = 0; i < games.count; i++)
|
||||||
|
{
|
||||||
|
if (games[i].ID.entityID > max)
|
||||||
|
{
|
||||||
|
max = games[i].ID.entityID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnterGame(EGID id)
|
||||||
|
{
|
||||||
|
if (!ExistsGameInfo(id)) return false;
|
||||||
|
ref MyGameDataEntityStruct mgdes = ref GetGameInfo(id);
|
||||||
|
return EnterGame(mgdes.GameName, mgdes.SavedGamePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnterGame(string gameName, string path, ulong workshopId = 0uL, bool autoEnterSim = false)
|
||||||
|
{
|
||||||
|
GameMode.CurrentMode = autoEnterSim ? RCXMode.Play : RCXMode.Build;
|
||||||
|
GameMode.SaveGameDetails = new SaveGameDetails(gameName, path, workshopId);
|
||||||
|
// the private FullGameCompositionRoot.SwitchToGame() method gets passed to menu items for this reason
|
||||||
|
AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame").Invoke(FullGameFields.Instance, new object[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetGameName(EGID id, string name)
|
||||||
|
{
|
||||||
|
if (!ExistsGameInfo(id)) return false;
|
||||||
|
GetGameInfo(id).GameName.Set(name);
|
||||||
|
GetGameViewInfo(id).MyGamesSlotComponent.GameName = StringUtil.SanitiseString(name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetGameDescription(EGID id, string name)
|
||||||
|
{
|
||||||
|
if (!ExistsGameInfo(id)) return false;
|
||||||
|
GetGameInfo(id).GameDescription.Set(name);
|
||||||
|
GetGameViewInfo(id).MyGamesSlotComponent.GameDescription = StringUtil.SanitiseString(name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ExistsGameInfo(EGID id)
|
||||||
|
{
|
||||||
|
return entitiesDB.Exists<MyGameDataEntityStruct>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref MyGameDataEntityStruct GetGameInfo(EGID id)
|
||||||
|
{
|
||||||
|
return ref GetComponent<MyGameDataEntityStruct>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref MyGamesSlotEntityViewStruct GetGameViewInfo(EGID id)
|
||||||
|
{
|
||||||
|
return ref GetComponent<MyGamesSlotEntityViewStruct>(new EGID(id.entityID, MyGamesScreenExclusiveGroups.GameSlotGuiEntities));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T GetComponent<T>(EGID id) where T: struct, IEntityComponent
|
||||||
|
{
|
||||||
|
return ref entitiesDB.QueryEntity<T>(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { }
|
||||||
|
}
|
26
GamecraftModdingAPI/App/StateSyncRegPatch.cs
Normal file
26
GamecraftModdingAPI/App/StateSyncRegPatch.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using RobocraftX.CR.MainGame;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.App
|
||||||
|
{
|
||||||
|
[HarmonyPatch]
|
||||||
|
class StateSyncRegPatch
|
||||||
|
{
|
||||||
|
public static void Postfix(StateSyncRegistrationHelper stateSyncReg)
|
||||||
|
{
|
||||||
|
// register sim/build events engines
|
||||||
|
Game.InitDeterministic(stateSyncReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose").MakeGenericMethod(typeof(object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,6 +72,8 @@ namespace GamecraftModdingAPI
|
||||||
Block.Init();
|
Block.Init();
|
||||||
GameClient.Init();
|
GameClient.Init();
|
||||||
AsyncUtils.Init();
|
AsyncUtils.Init();
|
||||||
|
GamecraftModdingAPI.App.Client.Init();
|
||||||
|
GamecraftModdingAPI.App.Game.Init();
|
||||||
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
|
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,15 @@ namespace GamecraftModdingAPI.Utility
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class FullGameFields
|
public static class FullGameFields
|
||||||
{
|
{
|
||||||
|
public static FullGameCompositionRoot Instance
|
||||||
|
{
|
||||||
|
private set;
|
||||||
|
get;
|
||||||
|
} = null;
|
||||||
|
|
||||||
public static MultiplayerInitParameters _multiplayerParams
|
public static MultiplayerInitParameters _multiplayerParams
|
||||||
{ get
|
{
|
||||||
|
get
|
||||||
{
|
{
|
||||||
return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue();
|
return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue();
|
||||||
}
|
}
|
||||||
|
@ -157,6 +164,7 @@ namespace GamecraftModdingAPI.Utility
|
||||||
public static void Init(FullGameCompositionRoot instance)
|
public static void Init(FullGameCompositionRoot instance)
|
||||||
{
|
{
|
||||||
fgcr = new Traverse(instance);
|
fgcr = new Traverse(instance);
|
||||||
|
FullGameFields.Instance = instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue