159 lines
5.8 KiB
C#
159 lines
5.8 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using HarmonyLib;
|
|
|
|
using RobocraftX.Services;
|
|
using UnityEngine;
|
|
|
|
using GamecraftModdingAPI.Utility;
|
|
using RobocraftX.Common;
|
|
|
|
namespace GamecraftModdingAPI.App
|
|
{
|
|
/// <summary>
|
|
/// The Gamecraft application that is running this code right now.
|
|
/// </summary>
|
|
public class Client
|
|
{
|
|
// extensible engine
|
|
protected static AppEngine appEngine = new AppEngine();
|
|
|
|
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>
|
|
public static event EventHandler<MenuEventArgs> EnterMenu
|
|
{
|
|
add => appEngine.EnterMenu += value;
|
|
remove => appEngine.EnterMenu -= value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// An event that fire whenever the main menu is exited.
|
|
/// </summary>
|
|
public static event EventHandler<MenuEventArgs> ExitMenu
|
|
{
|
|
add => appEngine.ExitMenu += value;
|
|
remove => appEngine.ExitMenu -= value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gamecraft build version string.
|
|
/// Usually this is in the form YYYY.mm.DD.HH.MM.SS
|
|
/// </summary>
|
|
/// <value>The version.</value>
|
|
public string Version
|
|
{
|
|
get => Application.version;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unity version string.
|
|
/// </summary>
|
|
/// <value>The unity version.</value>
|
|
public string UnityVersion
|
|
{
|
|
get => Application.unityVersion;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Game saves currently visible in the menu.
|
|
/// These take a second to completely populate after the EnterMenu event fires.
|
|
/// </summary>
|
|
/// <value>My games.</value>
|
|
public Game[] MyGames
|
|
{
|
|
get
|
|
{
|
|
if (!appEngine.IsInMenu) return new Game[0];
|
|
return appEngine.GetMyGames();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether Gamecraft is in the Main Menu
|
|
/// </summary>
|
|
/// <value><c>true</c> if in menu; <c>false</c> when loading or in a game.</value>
|
|
public bool InMenu
|
|
{
|
|
get => appEngine.IsInMenu;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open a popup which prompts the user to click a button.
|
|
/// This reuses Gamecraft's error dialog popup
|
|
/// </summary>
|
|
/// <param name="popup">The popup to display. Use an instance of SingleChoicePrompt or DualChoicePrompt.</param>
|
|
public void PromptUser(Error popup)
|
|
{
|
|
// if the stuff wasn't mostly set to internal, this would be written as:
|
|
// RobocraftX.Services.ErrorHandler.Instance.EqueueError(error);
|
|
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
EnqueueError(errorHandlerInstance, popup);
|
|
}
|
|
|
|
// TODO
|
|
/*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);
|
|
}*/
|
|
|
|
internal static void Init()
|
|
{
|
|
// this would have been so much simpler if this didn't involve a bunch of internal fields & classes
|
|
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler");
|
|
Type errorHandle = AccessTools.TypeByName("RobocraftX.Services.ErrorHandle");
|
|
ErrorHandlerInstanceGetter = (Func<object>) AccessTools.Method("GamecraftModdingAPI.App.Client:GenInstanceGetter")
|
|
.MakeGenericMethod(errorHandler)
|
|
.Invoke(null, new object[0]);
|
|
EnqueueError = (Action<object, Error>) AccessTools.Method("GamecraftModdingAPI.App.Client:GenEnqueueError")
|
|
.MakeGenericMethod(errorHandler, errorHandle)
|
|
.Invoke(null, new object[0]);
|
|
/*HandleErrorClosed = (Action<object>) AccessTools.Method("GamecraftModdingAPI.App.Client:GenHandlePopupClosed")
|
|
.MakeGenericMethod(errorHandler)
|
|
.Invoke(null, new object[0]);*/
|
|
// register engines
|
|
MenuEngineManager.AddMenuEngine(appEngine);
|
|
}
|
|
|
|
// Creating delegates once is faster than reflection every time
|
|
// Admittedly, this way is more difficult to code and less readable
|
|
private static Func<object> GenInstanceGetter<T>()
|
|
{
|
|
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler");
|
|
MethodInfo instance = AccessTools.PropertyGetter(errorHandler, "Instance");
|
|
Func<T> getterSimple = (Func<T>) Delegate.CreateDelegate(typeof(Func<T>), null, instance);
|
|
Func<object> getterCasted = () => (object) getterSimple();
|
|
return getterCasted;
|
|
}
|
|
|
|
private static Action<object, Error> GenEnqueueError<T, TRes>()
|
|
{
|
|
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler");
|
|
MethodInfo enqueueError = AccessTools.Method(errorHandler, "EnqueueError");
|
|
Func<T, Error, TRes> enqueueSimple =
|
|
(Func<T, Error, TRes>) Delegate.CreateDelegate(typeof(Func<T, Error, TRes>), enqueueError);
|
|
Action<object, Error> enqueueCasted =
|
|
(object instance, Error error) => { enqueueSimple((T) instance, error); };
|
|
return enqueueCasted;
|
|
}
|
|
|
|
private static Action<object> GenHandlePopupClosed<T>()
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|