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();
|
||||
GameClient.Init();
|
||||
AsyncUtils.Init();
|
||||
GamecraftModdingAPI.App.Client.Init();
|
||||
GamecraftModdingAPI.App.Game.Init();
|
||||
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,15 @@ namespace GamecraftModdingAPI.Utility
|
|||
/// </summary>
|
||||
public static class FullGameFields
|
||||
{
|
||||
public static FullGameCompositionRoot Instance
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
} = null;
|
||||
|
||||
public static MultiplayerInitParameters _multiplayerParams
|
||||
{ get
|
||||
{
|
||||
get
|
||||
{
|
||||
return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue();
|
||||
}
|
||||
|
@ -157,6 +164,7 @@ namespace GamecraftModdingAPI.Utility
|
|||
public static void Init(FullGameCompositionRoot instance)
|
||||
{
|
||||
fgcr = new Traverse(instance);
|
||||
FullGameFields.Instance = instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue