Added machine and environment data and new engine manager
This commit is contained in:
parent
9be1b5fdaf
commit
8a52095263
58 changed files with 516 additions and 626 deletions
|
@ -1,171 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
using RobocraftX.Services;
|
|
||||||
using UnityEngine;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The Techblox application that is running this code right now.
|
|
||||||
/// </summary>
|
|
||||||
public class Client
|
|
||||||
{
|
|
||||||
public static Client Instance { get; } = new Client();
|
|
||||||
|
|
||||||
protected static Func<object> ErrorHandlerInstanceGetter;
|
|
||||||
|
|
||||||
protected static Action<object, Error> EnqueueError;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event that fires whenever the main menu is loaded.
|
|
||||||
/// </summary>
|
|
||||||
public static event EventHandler<MenuEventArgs> EnterMenu
|
|
||||||
{
|
|
||||||
add => Game.menuEngine.EnterMenu += value;
|
|
||||||
remove => Game.menuEngine.EnterMenu -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event that fire whenever the main menu is exited.
|
|
||||||
/// </summary>
|
|
||||||
public static event EventHandler<MenuEventArgs> ExitMenu
|
|
||||||
{
|
|
||||||
add => Game.menuEngine.ExitMenu += value;
|
|
||||||
remove => Game.menuEngine.ExitMenu -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Techblox 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 (!Game.menuEngine.IsInMenu) return Array.Empty<Game>();
|
|
||||||
return Game.menuEngine.GetMyGames();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether Techblox 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 => Game.menuEngine.IsInMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Open a popup which prompts the user to click a button.
|
|
||||||
/// This reuses Techblox'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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
||||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
|
||||||
popup.SecondButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
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("TechbloxModdingAPI.App.Client:GenInstanceGetter")
|
|
||||||
.MakeGenericMethod(errorHandler)
|
|
||||||
.Invoke(null, new object[0]);
|
|
||||||
EnqueueError = (Action<object, Error>) AccessTools.Method("TechbloxModdingAPI.App.Client:GenEnqueueError")
|
|
||||||
.MakeGenericMethod(errorHandler, errorHandle)
|
|
||||||
.Invoke(null, new object[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = () => 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 Close, Action FirstButton, Action SecondButton) _errorPopup;
|
|
||||||
|
|
||||||
private static (Action Close, Action FirstButton, Action SecondButton) GetPopupCloseMethods(object handler)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,12 +20,12 @@ namespace TechbloxModdingAPI.App
|
||||||
public class Game
|
public class Game
|
||||||
{
|
{
|
||||||
// extensible engines
|
// extensible engines
|
||||||
protected static GameGameEngine gameEngine = new GameGameEngine();
|
protected static GameGameEngine gameEngine = new();
|
||||||
protected internal static GameMenuEngine menuEngine = new GameMenuEngine();
|
protected internal static GameMenuEngine menuEngine = new();
|
||||||
protected static DebugInterfaceEngine debugOverlayEngine = new DebugInterfaceEngine();
|
protected static DebugInterfaceEngine debugOverlayEngine = new();
|
||||||
protected static GameBuildSimEventEngine buildSimEventEngine = new GameBuildSimEventEngine();
|
protected static GameBuildSimEventEngine buildSimEventEngine = new();
|
||||||
|
|
||||||
private List<string> debugIds = new List<string>();
|
private List<string> debugIds = new();
|
||||||
|
|
||||||
private bool menuMode = true;
|
private bool menuMode = true;
|
||||||
private bool hasId = false;
|
private bool hasId = false;
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
using System;
|
using RobocraftX.StateSync;
|
||||||
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.StateSync;
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using Unity.Jobs;
|
using Unity.Jobs;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
namespace TechbloxModdingAPI.App
|
||||||
|
|
|
@ -16,7 +16,8 @@ using Techblox.Environment.Transition;
|
||||||
using Techblox.GameSelection;
|
using Techblox.GameSelection;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Blocks;
|
using TechbloxModdingAPI.Blocks;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Common;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
using TechbloxModdingAPI.Input;
|
using TechbloxModdingAPI.Input;
|
||||||
using TechbloxModdingAPI.Players;
|
using TechbloxModdingAPI.Players;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
|
@ -9,8 +9,7 @@ using RobocraftX.Multiplayer;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Experimental;
|
using Svelto.ECS.Experimental;
|
||||||
using Techblox.GameSelection;
|
using Techblox.GameSelection;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
namespace TechbloxModdingAPI.App
|
||||||
|
|
|
@ -25,16 +25,16 @@ namespace TechbloxModdingAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Block : EcsObjectBase, IEquatable<Block>, IEquatable<EGID>
|
public class Block : EcsObjectBase, IEquatable<Block>, IEquatable<EGID>
|
||||||
{
|
{
|
||||||
protected static readonly PlacementEngine PlacementEngine = new PlacementEngine();
|
protected static readonly PlacementEngine PlacementEngine = new();
|
||||||
protected static readonly MovementEngine MovementEngine = new MovementEngine();
|
protected static readonly MovementEngine MovementEngine = new();
|
||||||
protected static readonly RotationEngine RotationEngine = new RotationEngine();
|
protected static readonly RotationEngine RotationEngine = new();
|
||||||
protected static readonly RemovalEngine RemovalEngine = new RemovalEngine();
|
protected static readonly RemovalEngine RemovalEngine = new();
|
||||||
protected static readonly SignalEngine SignalEngine = new SignalEngine();
|
protected static readonly SignalEngine SignalEngine = new();
|
||||||
protected static readonly BlockEventsEngine BlockEventsEngine = new BlockEventsEngine();
|
protected static readonly BlockEventsEngine BlockEventsEngine = new();
|
||||||
protected static readonly ScalingEngine ScalingEngine = new ScalingEngine();
|
protected static readonly ScalingEngine ScalingEngine = new();
|
||||||
protected static readonly BlockCloneEngine BlockCloneEngine = new BlockCloneEngine();
|
protected static readonly BlockCloneEngine BlockCloneEngine = new();
|
||||||
|
|
||||||
protected internal static readonly BlockEngine BlockEngine = new BlockEngine();
|
protected internal static readonly BlockEngine BlockEngine = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position.
|
/// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position.
|
||||||
|
@ -96,7 +96,7 @@ namespace TechbloxModdingAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Dictionary<ExclusiveBuildGroup, (Func<EGID, Block> Constructor, Type Type)> GroupToConstructor =
|
private static readonly Dictionary<ExclusiveBuildGroup, (Func<EGID, Block> Constructor, Type Type)> GroupToConstructor =
|
||||||
new Dictionary<ExclusiveBuildGroup, (Func<EGID, Block>, Type)>
|
new()
|
||||||
{
|
{
|
||||||
{CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP, (id => new DampedSpring(id), typeof(DampedSpring))},
|
{CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP, (id => new DampedSpring(id), typeof(DampedSpring))},
|
||||||
{CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP, (id => new Engine(id), typeof(Engine))},
|
{CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP, (id => new Engine(id), typeof(Engine))},
|
||||||
|
@ -122,9 +122,9 @@ namespace TechbloxModdingAPI
|
||||||
internal static Block New(EGID egid, bool signaling = false)
|
internal static Block New(EGID egid, bool signaling = false)
|
||||||
{
|
{
|
||||||
if (egid == default) return null;
|
if (egid == default) return null;
|
||||||
if (GroupToConstructor.ContainsKey(egid.groupID))
|
if (GroupToConstructor.TryGetValue(egid.groupID, out var value))
|
||||||
{
|
{
|
||||||
var (constructor, type) = GroupToConstructor[egid.groupID];
|
var (constructor, type) = value;
|
||||||
return GetInstance(egid, constructor, type);
|
return GetInstance(egid, constructor, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ namespace TechbloxModdingAPI
|
||||||
: GetInstance(egid, e => new Block(e));
|
: GetInstance(egid, e => new Block(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block(EGID id) : base(id)
|
public Block(EGID id) : base(id, typeof(BlockEntityDescriptor))
|
||||||
{
|
{
|
||||||
Type expectedType;
|
Type expectedType;
|
||||||
if (GroupToConstructor.ContainsKey(id.groupID) &&
|
if (GroupToConstructor.ContainsKey(id.groupID) &&
|
||||||
|
@ -153,26 +153,6 @@ namespace TechbloxModdingAPI
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Places a new block in the world.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The block's type</param>
|
|
||||||
/// <param name="position">The block's position (a block is 0.2 wide in terms of position)</param>
|
|
||||||
/// <param name="autoWire">Whether the block should be auto-wired (if functional)</param>
|
|
||||||
/// <param name="player">The player who placed the block</param>
|
|
||||||
public Block(BlockIDs type, float3 position, bool autoWire = false, Player player = null)
|
|
||||||
: base(block =>
|
|
||||||
{
|
|
||||||
if (!PlacementEngine.IsInGame || !GameState.IsBuildMode())
|
|
||||||
throw new BlockException("Blocks can only be placed in build mode.");
|
|
||||||
var initializer = PlacementEngine.PlaceBlock(type, position, player, autoWire);
|
|
||||||
block.InitData = initializer;
|
|
||||||
Placed += ((Block)block).OnPlacedInit;
|
|
||||||
return initializer.EGID;
|
|
||||||
})
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private EGID copiedFrom;
|
private EGID copiedFrom;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -18,14 +18,14 @@ namespace TechbloxModdingAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BlockGroup : EcsObjectBase, ICollection<Block>, IDisposable
|
public class BlockGroup : EcsObjectBase, ICollection<Block>, IDisposable
|
||||||
{
|
{
|
||||||
internal static BlueprintEngine _engine = new BlueprintEngine();
|
internal static BlueprintEngine _engine = new();
|
||||||
private readonly Block sourceBlock;
|
private readonly Block sourceBlock;
|
||||||
private readonly List<Block> blocks;
|
private readonly List<Block> blocks;
|
||||||
private float3 position, rotation;
|
private float3 position, rotation;
|
||||||
internal bool PosAndRotCalculated;
|
internal bool PosAndRotCalculated;
|
||||||
|
|
||||||
internal BlockGroup(int id, Block block) : base(new EGID((uint)id,
|
internal BlockGroup(int id, Block block) : base(new EGID((uint)id,
|
||||||
BlockGroupExclusiveGroups.BlockGroupEntityGroup))
|
BlockGroupExclusiveGroups.BlockGroupEntityGroup), typeof(BlockGroupEntityDescriptor))
|
||||||
{
|
{
|
||||||
if (id == BlockGroupUtility.GROUP_UNASSIGNED)
|
if (id == BlockGroupUtility.GROUP_UNASSIGNED)
|
||||||
throw new BlockException("Cannot create a block group for blocks without a group!");
|
throw new BlockException("Cannot create a block group for blocks without a group!");
|
||||||
|
|
|
@ -8,6 +8,7 @@ using RobocraftX.Character;
|
||||||
using RobocraftX.Common;
|
using RobocraftX.Common;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks.Engines
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
|
@ -17,6 +17,7 @@ using Svelto.ECS.Experimental;
|
||||||
using Svelto.ECS.Hybrid;
|
using Svelto.ECS.Hybrid;
|
||||||
using Techblox.BuildingDrone;
|
using Techblox.BuildingDrone;
|
||||||
using Techblox.ObjectIDBlockServer;
|
using Techblox.ObjectIDBlockServer;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
|
|
|
@ -19,6 +19,7 @@ using Svelto.ECS.EntityStructs;
|
||||||
using Svelto.ECS.Native;
|
using Svelto.ECS.Native;
|
||||||
using Svelto.ECS.Serialization;
|
using Svelto.ECS.Serialization;
|
||||||
using Techblox.Blocks.Connections;
|
using Techblox.Blocks.Connections;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
@ -35,7 +36,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
AccessTools.Method("RobocraftX.CR.MachineEditing.PlaceBlockUtility:GetBlocksSharingBlockgroup");
|
AccessTools.Method("RobocraftX.CR.MachineEditing.PlaceBlockUtility:GetBlocksSharingBlockgroup");
|
||||||
|
|
||||||
private NativeDynamicArray selectedBlocksInGroup;
|
private NativeDynamicArray selectedBlocksInGroup;
|
||||||
private NativeHashSet<ulong> removedConnections = new NativeHashSet<ulong>();
|
private NativeHashSet<ulong> removedConnections = new();
|
||||||
private int addingToBlockGroup = -1;
|
private int addingToBlockGroup = -1;
|
||||||
|
|
||||||
private static readonly Type PlaceBlueprintUtilityType =
|
private static readonly Type PlaceBlueprintUtilityType =
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
using RobocraftX.DOTS;
|
using RobocraftX.DOTS;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.EntityStructs;
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using Unity.Transforms;
|
using Unity.Transforms;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,8 @@ using RobocraftX.Rendering;
|
||||||
using RobocraftX.Rendering.GPUI;
|
using RobocraftX.Rendering.GPUI;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.EntityStructs;
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ using RobocraftX.StateSync;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Native;
|
using Svelto.ECS.Native;
|
||||||
using Techblox.Blocks.Connections;
|
using Techblox.Blocks.Connections;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
using Unity.Jobs;
|
using Unity.Jobs;
|
||||||
using Allocator = Unity.Collections.Allocator;
|
using Allocator = Unity.Collections.Allocator;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using RobocraftX.DOTS;
|
using RobocraftX.DOTS;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.EntityStructs;
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ using HarmonyLib;
|
||||||
using RobocraftX.Common;
|
using RobocraftX.Common;
|
||||||
using RobocraftX.DOTS;
|
using RobocraftX.DOTS;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using Unity.Entities;
|
using Unity.Entities;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
using Gamecraft.Wires;
|
using Gamecraft.Wires;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
@ -260,7 +261,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(startBlock);
|
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(startBlock);
|
||||||
startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group) };
|
startPorts = new EGID[] {new(ports.firstOutputID + startPort, NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group) };
|
||||||
}
|
}
|
||||||
|
|
||||||
EGID[] endPorts;
|
EGID[] endPorts;
|
||||||
|
@ -272,7 +273,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(endBlock);
|
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(endBlock);
|
||||||
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group) };
|
endPorts = new EGID[] {new(ports.firstInputID + endPort, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group) };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
|
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
|
||||||
|
|
|
@ -69,45 +69,6 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Construct a wire object froam n existing connection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">Starting block ID.</param>
|
|
||||||
/// <param name="end">Ending block ID.</param>
|
|
||||||
/// <param name="startPort">Starting port number, or guess if omitted.</param>
|
|
||||||
/// <param name="endPort">Ending port number, or guess if omitted.</param>
|
|
||||||
/// <exception cref="WireInvalidException">Guessing failed or wire does not exist.</exception>
|
|
||||||
public Wire(Block start, Block end, byte startPort = Byte.MaxValue, byte endPort = Byte.MaxValue) : base(ecs =>
|
|
||||||
{
|
|
||||||
var th = (Wire)ecs;
|
|
||||||
th.startBlockEGID = start.Id;
|
|
||||||
th.endBlockEGID = end.Id;
|
|
||||||
bool flipped = false;
|
|
||||||
// find block ports
|
|
||||||
EGID wire = signalEngine.MatchBlocksToWire(start.Id, end.Id, startPort, endPort);
|
|
||||||
if (wire == default)
|
|
||||||
{
|
|
||||||
// flip I/O around and try again
|
|
||||||
wire = signalEngine.MatchBlocksToWire(end.Id, start.Id, endPort, startPort);
|
|
||||||
flipped = true;
|
|
||||||
// NB: start and end are handled exactly as they're received as params.
|
|
||||||
// This makes wire traversal easier, but makes logic in this class a bit more complex
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wire != default)
|
|
||||||
{
|
|
||||||
th.Construct(start.Id, end.Id, startPort, endPort, wire, flipped);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new WireInvalidException("Wire not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return th.wireEGID;
|
|
||||||
})
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a wire object from an existing wire connection.
|
/// Construct a wire object from an existing wire connection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -120,9 +81,9 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
public Wire(Block start, Block end, byte startPort, byte endPort, EGID wire, bool inputToOutput)
|
public Wire(Block start, Block end, byte startPort, byte endPort, EGID wire, bool inputToOutput)
|
||||||
: this(start.Id, end.Id, startPort, endPort, wire, inputToOutput)
|
: this(start.Id, end.Id, startPort, endPort, wire, inputToOutput)
|
||||||
{
|
{
|
||||||
}
|
} // TODO: Convert all constructors (including the removed one) to static methods
|
||||||
|
|
||||||
private Wire(EGID startBlock, EGID endBlock, byte startPort, byte endPort, EGID wire, bool inputToOutput) : base(wire)
|
private Wire(EGID startBlock, EGID endBlock, byte startPort, byte endPort, EGID wire, bool inputToOutput) : base(wire, typeof(WireEntityDescriptor))
|
||||||
{
|
{
|
||||||
Construct(startBlock, endBlock, startPort, endPort, wire, inputToOutput);
|
Construct(startBlock, endBlock, startPort, endPort, wire, inputToOutput);
|
||||||
}
|
}
|
||||||
|
@ -145,7 +106,7 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
/// Construct a wire object from an existing wire connection.
|
/// Construct a wire object from an existing wire connection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="wireEgid">The wire ID.</param>
|
/// <param name="wireEgid">The wire ID.</param>
|
||||||
public Wire(EGID wireEgid) : base(wireEgid)
|
public Wire(EGID wireEgid) : base(wireEgid, typeof(WireEntityDescriptor))
|
||||||
{
|
{
|
||||||
WireEntityStruct wire = signalEngine.GetWire(wireEGID);
|
WireEntityStruct wire = signalEngine.GetWire(wireEGID);
|
||||||
Construct(wire.sourceBlockEGID, wire.destinationBlockEGID, wire.sourcePortUsage, wire.destinationPortUsage,
|
Construct(wire.sourceBlockEGID, wire.destinationBlockEGID, wire.sourcePortUsage, wire.destinationPortUsage,
|
||||||
|
@ -188,22 +149,6 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
signalEngine.GetChannelDataStruct(startPortEGID).Get().valueAsEcsString.Set(value);
|
signalEngine.GetChannelDataStruct(startPortEGID).Get().valueAsEcsString.Set(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The wire's raw string signal.
|
|
||||||
/// </summary>
|
|
||||||
public ECSString ECSString
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return signalEngine.GetChannelDataStruct(startPortEGID).Get().valueAsEcsString;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
signalEngine.GetChannelDataStruct(startPortEGID).Get().valueAsEcsString = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The wire's signal id.
|
/// The wire's signal id.
|
||||||
|
@ -292,9 +237,7 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
inputToOutput = false;
|
inputToOutput = false;
|
||||||
// swap inputs and outputs
|
// swap inputs and outputs
|
||||||
(endBlockEGID, startBlockEGID) = (startBlockEGID, endBlockEGID);
|
(endBlockEGID, startBlockEGID) = (startBlockEGID, endBlockEGID);
|
||||||
var tempPort = endPortEGID;
|
(endPortEGID, startPortEGID) = (startPortEGID, endPortEGID);
|
||||||
endPortEGID = startPortEGID;
|
|
||||||
startPortEGID = tempPort;
|
|
||||||
(endPort, startPort) = (startPort, endPort);
|
(endPort, startPort) = (startPort, endPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using HarmonyLib;
|
|
||||||
using RobocraftX.Services;
|
|
||||||
using TechbloxModdingAPI.App;
|
|
||||||
using TechbloxModdingAPI.Client.Game;
|
|
||||||
using TechbloxModdingAPI.Common.Utils;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Client.App;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains information about the game client's current state.
|
|
||||||
/// </summary>
|
|
||||||
public static class Client
|
|
||||||
{ // TODO
|
|
||||||
public static GameState CurrentState { get; }
|
|
||||||
|
|
||||||
private static Func<object> ErrorHandlerInstanceGetter;
|
|
||||||
|
|
||||||
private static Action<object, Error> EnqueueError;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event that fires whenever the game's state changes
|
|
||||||
/// </summary>
|
|
||||||
public static event EventHandler<MenuEventArgs> StateChanged
|
|
||||||
{
|
|
||||||
add => Game.menuEngine.EnterMenu += value;
|
|
||||||
remove => Game.menuEngine.EnterMenu -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Techblox build version string.
|
|
||||||
/// Usually this is in the form YYYY.mm.DD.HH.MM.SS
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The version.</value>
|
|
||||||
public static string Version => Application.version;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unity version string.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The unity version.</value>
|
|
||||||
public static string UnityVersion => Application.unityVersion;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Environments (maps) currently visible in the menu.
|
|
||||||
/// These take a second to completely populate after the EnterMenu event fires.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>Available environments.</value>
|
|
||||||
public static ClientEnvironment[] Environments
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Open a popup which prompts the user to click a button.
|
|
||||||
/// This reuses Techblox's error dialog popup
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="popup">The popup to display. Use an instance of SingleChoicePrompt or DualChoicePrompt.</param>
|
|
||||||
public static 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CloseCurrentPrompt()
|
|
||||||
{
|
|
||||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
||||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
|
||||||
popup.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SelectFirstPromptButton()
|
|
||||||
{
|
|
||||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
||||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
|
||||||
popup.FirstButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SelectSecondPromptButton()
|
|
||||||
{
|
|
||||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
||||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
|
||||||
popup.SecondButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Init()
|
|
||||||
{
|
|
||||||
var errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler");
|
|
||||||
ErrorHandlerInstanceGetter = GenInstanceGetter(errorHandler);
|
|
||||||
EnqueueError = GenEnqueueError(errorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(Type handler)
|
|
||||||
{
|
|
||||||
return Reflections.CreateAccessor<Func<object>>("Instance", handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Action<object, Error> GenEnqueueError(Type handler)
|
|
||||||
{
|
|
||||||
var enqueueError = AccessTools.Method(handler, "EnqueueError");
|
|
||||||
return Reflections.CreateMethodCall<Action<object, Error>>(enqueueError, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (Action Close, Action FirstButton, Action SecondButton) _errorPopup;
|
|
||||||
|
|
||||||
private static (Action Close, Action FirstButton, Action SecondButton) GetPopupCloseMethods(object handler)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
46
TechbloxModdingAPI/Client/App/ClientEngine.cs
Normal file
46
TechbloxModdingAPI/Client/App/ClientEngine.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
using RobocraftX.GUI.MyGamesScreen;
|
||||||
|
using RobocraftX.Multiplayer;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Techblox.GameSelection;
|
||||||
|
using TechbloxModdingAPI.Client.Game;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Client.App;
|
||||||
|
|
||||||
|
internal class ClientEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientMachine[] GetMachines()
|
||||||
|
{
|
||||||
|
var (mgsevs, count) = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||||
|
var games = new ClientMachine[count];
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}");
|
||||||
|
games[i] = new ClientMachine(mgsevs[i].ID);
|
||||||
|
}
|
||||||
|
return games;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnterBuildMode(ClientEnvironment environment, ClientMachine machine)
|
||||||
|
{ // TODO: Move to using a single engine per 'type' (see AddEngine())
|
||||||
|
FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer;
|
||||||
|
ref var selection = ref entitiesDB.QueryEntity<GameSelectionComponent>(GameSelectionConstants.GameSelectionEGID);
|
||||||
|
selection.userContentID.Set(machine.ContentID);
|
||||||
|
selection.triggerStart = true;
|
||||||
|
selection.saveType = SaveType.ExistingSave;
|
||||||
|
selection.saveName.Set(machine.Name);
|
||||||
|
selection.gameMode = machine is ClientWorld ? GameMode.CreateWorld : GameMode.PlayGame;
|
||||||
|
selection.gameID.Set(environment.Id); //TODO: Expose to the API
|
||||||
|
}
|
||||||
|
}
|
79
TechbloxModdingAPI/Client/App/GameClient.cs
Normal file
79
TechbloxModdingAPI/Client/App/GameClient.cs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
using System;
|
||||||
|
using TechbloxModdingAPI.Client.Game;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Client.App;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information about the game client's current state.
|
||||||
|
/// </summary>
|
||||||
|
public static class GameClient
|
||||||
|
{
|
||||||
|
private static readonly ClientEngine _engine = new();
|
||||||
|
|
||||||
|
public static GameState CurrentState
|
||||||
|
{
|
||||||
|
get => _currentState;
|
||||||
|
internal set
|
||||||
|
{
|
||||||
|
_currentState = value;
|
||||||
|
var old = _currentState;
|
||||||
|
_stateChanged.Invoke(null, new GameStateChangedArgs { OldState = old, NewState = value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameState _currentState;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An event that fires whenever the game's state changes
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<GameStateChangedArgs> StateChanged
|
||||||
|
{
|
||||||
|
add => _stateChanged += value;
|
||||||
|
remove => _stateChanged -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WrappedHandler<GameStateChangedArgs> _stateChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Techblox build version string.
|
||||||
|
/// Usually this is in the form YYYY.mm.DD.HH.MM.SS
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The version.</value>
|
||||||
|
public static string Version => Application.version;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unity version string.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The unity version.</value>
|
||||||
|
public static string UnityVersion => Application.unityVersion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Environments (maps) currently visible in the menu.
|
||||||
|
/// These take a second to completely populate after the EnterMenu event fires.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Available environments.</value>
|
||||||
|
public static ClientEnvironment[] Environments { get; }
|
||||||
|
|
||||||
|
public static ClientMachine[] Machines { get; }
|
||||||
|
|
||||||
|
public static void EnterBuildMode(ClientEnvironment environment, ClientMachine machine)
|
||||||
|
{
|
||||||
|
var env = new ClientEnvironment("GAMEID_Road_Track"); // TODO: The options are hardcoded
|
||||||
|
_engine.EnterBuildMode(env, machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
EngineManager.AddEngine(_engine, ApiEngineType.Menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct GameStateChangedArgs
|
||||||
|
{
|
||||||
|
public GameState OldState { get; set; }
|
||||||
|
public GameState NewState { get; set; }
|
||||||
|
}
|
||||||
|
}
|
88
TechbloxModdingAPI/Client/App/Popup.cs
Normal file
88
TechbloxModdingAPI/Client/App/Popup.cs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using HarmonyLib;
|
||||||
|
using RobocraftX.Services;
|
||||||
|
using TechbloxModdingAPI.Common.Utils;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Client.App;
|
||||||
|
|
||||||
|
public static class Popup
|
||||||
|
{
|
||||||
|
private static Func<object> ErrorHandlerInstanceGetter;
|
||||||
|
|
||||||
|
private static Action<object, Error> EnqueueError;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open a popup which prompts the user to click a button.
|
||||||
|
/// This reuses Techblox's error dialog popup
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="popup">The popup to display. Use an instance of SingleChoicePrompt or DualChoicePrompt.</param>
|
||||||
|
public static void PromptUser(Error popup)
|
||||||
|
{
|
||||||
|
// if the stuff wasn't mostly set to internal, this would be written as:
|
||||||
|
// RobocraftX.Services.ErrorHandler.Instance.EnqueueError(error);
|
||||||
|
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||||
|
EnqueueError(errorHandlerInstance, popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CloseCurrentPrompt()
|
||||||
|
{
|
||||||
|
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||||
|
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
||||||
|
popup.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SelectFirstPromptButton()
|
||||||
|
{
|
||||||
|
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||||
|
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
||||||
|
popup.FirstButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SelectSecondPromptButton()
|
||||||
|
{
|
||||||
|
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||||
|
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
||||||
|
popup.SecondButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Init()
|
||||||
|
{
|
||||||
|
var errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler");
|
||||||
|
ErrorHandlerInstanceGetter = GenInstanceGetter(errorHandler);
|
||||||
|
EnqueueError = GenEnqueueError(errorHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(Type handler)
|
||||||
|
{
|
||||||
|
return Reflections.CreateAccessor<Func<object>>("Instance", handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Action<object, Error> GenEnqueueError(Type handler)
|
||||||
|
{
|
||||||
|
var enqueueError = AccessTools.Method(handler, "EnqueueError");
|
||||||
|
return Reflections.CreateMethodCall<Action<object, Error>>(enqueueError, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (Action Close, Action FirstButton, Action SecondButton) _errorPopup;
|
||||||
|
|
||||||
|
private static (Action Close, Action FirstButton, Action SecondButton) GetPopupCloseMethods(object handler)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,5 +5,10 @@ namespace TechbloxModdingAPI.Client.Game;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ClientEnvironment
|
public class ClientEnvironment
|
||||||
{
|
{
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
public ClientEnvironment(string id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
}
|
}
|
15
TechbloxModdingAPI/Client/Game/ClientMachine.cs
Normal file
15
TechbloxModdingAPI/Client/Game/ClientMachine.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using RobocraftX.GUI.MyGamesScreen;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Client.Game;
|
||||||
|
|
||||||
|
public class ClientMachine : EcsObjectBase
|
||||||
|
{
|
||||||
|
public ClientMachine(EGID id) : base(id, typeof(MyGameDataEntityDescriptor))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ContentID { get; set; } // TODO
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
10
TechbloxModdingAPI/Client/Game/ClientWorld.cs
Normal file
10
TechbloxModdingAPI/Client/Game/ClientWorld.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Client.Game;
|
||||||
|
|
||||||
|
public class ClientWorld : ClientMachine
|
||||||
|
{
|
||||||
|
public ClientWorld(EGID id) : base(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ namespace TechbloxModdingAPI.Commands
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class CommandManager
|
public static class CommandManager
|
||||||
{
|
{
|
||||||
private static Dictionary<string, ICustomCommandEngine> _customCommands = new Dictionary<string, ICustomCommandEngine>();
|
private static Dictionary<string, ICustomCommandEngine> _customCommands = new();
|
||||||
|
|
||||||
private static EnginesRoot _lastEngineRoot;
|
private static EnginesRoot _lastEngineRoot;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace TechbloxModdingAPI.Commands
|
||||||
public Delegate Action;
|
public Delegate Action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, CommandData> _commands = new Dictionary<string, CommandData>();
|
private static Dictionary<string, CommandData> _commands = new();
|
||||||
public static void Register(string name, Delegate action, string desc)
|
public static void Register(string name, Delegate action, string desc)
|
||||||
{
|
{
|
||||||
_commands.Add(name, new CommandData
|
_commands.Add(name, new CommandData
|
||||||
|
@ -51,7 +51,6 @@ namespace TechbloxModdingAPI.Commands
|
||||||
|
|
||||||
public static bool Exists(string name) => _commands.ContainsKey(name);
|
public static bool Exists(string name) => _commands.ContainsKey(name);
|
||||||
|
|
||||||
public static ReadOnlyDictionary<string, CommandData> GetAllCommandData() =>
|
public static ReadOnlyDictionary<string, CommandData> GetAllCommandData() => new(_commands);
|
||||||
new ReadOnlyDictionary<string, CommandData>(_commands);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,13 +1,4 @@
|
||||||
using System;
|
using TechbloxModdingAPI.Common;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
namespace TechbloxModdingAPI.Commands
|
||||||
{
|
{
|
||||||
|
@ -16,7 +7,7 @@ namespace TechbloxModdingAPI.Commands
|
||||||
/// If you are using implementing this yourself, you must manually register the command.
|
/// If you are using implementing this yourself, you must manually register the command.
|
||||||
/// See SimpleCustomCommandEngine's Ready() and Dispose() methods for an example of command registration.
|
/// See SimpleCustomCommandEngine's Ready() and Dispose() methods for an example of command registration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICustomCommandEngine : IApiEngine
|
public interface ICustomCommandEngine : INamedApiEngine
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The command's description, shown in command help messages
|
/// The command's description, shown in command help messages
|
||||||
|
|
21
TechbloxModdingAPI/Common/Engines/ApiEngineType.cs
Normal file
21
TechbloxModdingAPI/Common/Engines/ApiEngineType.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
namespace TechbloxModdingAPI.Common.Engines;
|
||||||
|
|
||||||
|
public enum ApiEngineType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets created and registered when loading the game and stays loaded until it's quit. Intended for menu changes.
|
||||||
|
/// </summary>
|
||||||
|
Menu,
|
||||||
|
/// <summary>
|
||||||
|
/// Gets created and registered when entering build mode.
|
||||||
|
/// </summary>
|
||||||
|
Build,
|
||||||
|
/// <summary>
|
||||||
|
/// Gets created and registered on the client's side when starting simulation (test or not).
|
||||||
|
/// </summary>
|
||||||
|
PlayClient,
|
||||||
|
/// <summary>
|
||||||
|
/// Gets created and registered on the server's side when starting simulation (test or not).
|
||||||
|
/// </summary>
|
||||||
|
PlayServer
|
||||||
|
}
|
52
TechbloxModdingAPI/Common/Engines/EngineManager.cs
Normal file
52
TechbloxModdingAPI/Common/Engines/EngineManager.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Common.Engines;
|
||||||
|
|
||||||
|
public class EngineManager
|
||||||
|
{
|
||||||
|
private static Dictionary<ApiEngineType, List<IApiEngine>> _engines = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register an engine to a given game state and type. Or multiple.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="engine">The engine</param>
|
||||||
|
/// <param name="types">The types to register to</param>
|
||||||
|
public static void AddEngine(IApiEngine engine, params ApiEngineType[] types)
|
||||||
|
{
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
if (!_engines.ContainsKey(type))
|
||||||
|
_engines.Add(type, new List<IApiEngine>());
|
||||||
|
_engines[type].Add(engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterEngines(StateSyncRegistrationHelper helper, EnginesRoot enginesRoot, ApiEngineType type)
|
||||||
|
{
|
||||||
|
IEntityFactory factory = enginesRoot.GenerateEntityFactory();
|
||||||
|
IEntityFunctions functions = enginesRoot.GenerateEntityFunctions();
|
||||||
|
foreach (var engine in _engines[type])
|
||||||
|
{
|
||||||
|
string name = engine is INamedApiEngine namedEngine ? namedEngine.Name : engine.ToString();
|
||||||
|
Logging.MetaDebugLog($"Registering {type} IApiEngine {name}");
|
||||||
|
if (engine is IDeterministicEngine detEngine)
|
||||||
|
if (helper is not null) helper.AddDeterministicEngine(detEngine);
|
||||||
|
else throw new InvalidOperationException($"Attempting to add deterministic engine to non-deterministic state {type}");
|
||||||
|
else
|
||||||
|
enginesRoot.AddEngine(engine);
|
||||||
|
switch (engine)
|
||||||
|
{
|
||||||
|
case IFactoryEngine factEngine:
|
||||||
|
factEngine.Factory = factory;
|
||||||
|
break;
|
||||||
|
case IFunEngine funEngine:
|
||||||
|
funEngine.Functions = functions;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,22 +5,21 @@ using RobocraftX.CR.MainGame;
|
||||||
using RobocraftX.FrontEnd;
|
using RobocraftX.FrontEnd;
|
||||||
using RobocraftX.StateSync;
|
using RobocraftX.StateSync;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Schedulers;
|
|
||||||
using TechbloxModdingAPI.Commands;
|
using TechbloxModdingAPI.Commands;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using GameState = TechbloxModdingAPI.Client.App.GameState;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Engines
|
namespace TechbloxModdingAPI.Common.Engines
|
||||||
{
|
{
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
static class GameLoadedTimeStoppedEnginePatch
|
static class GameLoadedTimeStoppedEnginePatch
|
||||||
{
|
{
|
||||||
public static void Postfix(StateSyncRegistrationHelper stateSyncReg)
|
public static void Postfix(StateSyncRegistrationHelper stateSyncReg)
|
||||||
{
|
{
|
||||||
|
Client.App.GameClient.CurrentState = GameState.InMachineEditor; // TODO: World editor
|
||||||
// register all game engines, including deterministic
|
// register all game engines, including deterministic
|
||||||
GameEngineManager.RegisterEngines(stateSyncReg);
|
GameEngineManager.RegisterEngines(stateSyncReg);
|
||||||
// register command engines
|
// register command engines
|
||||||
/*CommandLineCompositionRoot.Compose(contextHolder, stateSyncReg.enginesRoot, reloadGame, multiplayerParameters,
|
|
||||||
stateSyncReg); - uREPL C# compilation not supported anymore */
|
|
||||||
CommandManager.RegisterEngines(stateSyncReg.enginesRoot);
|
CommandManager.RegisterEngines(stateSyncReg.enginesRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +34,7 @@ namespace TechbloxModdingAPI.Engines
|
||||||
{
|
{
|
||||||
public static void Postfix(StateSyncRegistrationHelper stateSyncReg)
|
public static void Postfix(StateSyncRegistrationHelper stateSyncReg)
|
||||||
{
|
{
|
||||||
|
Client.App.GameClient.CurrentState = GameState.InTestMode; // TODO: Client/server
|
||||||
GameEngineManager.RegisterEngines(stateSyncReg);
|
GameEngineManager.RegisterEngines(stateSyncReg);
|
||||||
CommandManager.RegisterEngines(stateSyncReg.enginesRoot);
|
CommandManager.RegisterEngines(stateSyncReg.enginesRoot);
|
||||||
}
|
}
|
||||||
|
@ -49,21 +49,36 @@ namespace TechbloxModdingAPI.Engines
|
||||||
static class GameReloadedPatch
|
static class GameReloadedPatch
|
||||||
{
|
{
|
||||||
internal static bool IsReload;
|
internal static bool IsReload;
|
||||||
public static void Prefix() => IsReload = true;
|
public static void Prefix()
|
||||||
|
{
|
||||||
|
IsReload = true;
|
||||||
|
Client.App.GameClient.CurrentState = GameState.Loading;
|
||||||
|
}
|
||||||
|
|
||||||
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame");
|
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
static class GameSwitchedToPatch
|
static class GameSwitchedToPatch
|
||||||
{
|
{
|
||||||
public static void Prefix() => GameReloadedPatch.IsReload = false;
|
public static void Prefix()
|
||||||
|
{
|
||||||
|
GameReloadedPatch.IsReload = false;
|
||||||
|
Client.App.GameClient.CurrentState = GameState.Loading;
|
||||||
|
}
|
||||||
|
|
||||||
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame");
|
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
static class MenuSwitchedToPatch
|
static class MenuSwitchedToPatch
|
||||||
{
|
{
|
||||||
public static void Prefix() => GameReloadedPatch.IsReload = false;
|
public static void Prefix()
|
||||||
|
{
|
||||||
|
GameReloadedPatch.IsReload = false;
|
||||||
|
Client.App.GameClient.CurrentState = GameState.Loading;
|
||||||
|
}
|
||||||
|
|
||||||
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu");
|
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +87,7 @@ namespace TechbloxModdingAPI.Engines
|
||||||
{
|
{
|
||||||
public static void Postfix(EnginesRoot enginesRoot)
|
public static void Postfix(EnginesRoot enginesRoot)
|
||||||
{
|
{
|
||||||
|
Client.App.GameClient.CurrentState = GameState.InMenu; // TODO: Loaded states
|
||||||
// register menu engines
|
// register menu engines
|
||||||
MenuEngineManager.RegisterEngines(enginesRoot);
|
MenuEngineManager.RegisterEngines(enginesRoot);
|
||||||
}
|
}
|
||||||
|
@ -87,6 +103,7 @@ namespace TechbloxModdingAPI.Engines
|
||||||
{
|
{
|
||||||
public static void Postfix(FullGameCompositionRoot __instance)
|
public static void Postfix(FullGameCompositionRoot __instance)
|
||||||
{
|
{
|
||||||
|
Client.App.GameClient.CurrentState = GameState.Loading;
|
||||||
FullGameFields.Init(__instance);
|
FullGameFields.Init(__instance);
|
||||||
}
|
}
|
||||||
|
|
15
TechbloxModdingAPI/Common/Engines/IFactoryEngine.cs
Normal file
15
TechbloxModdingAPI/Common/Engines/IFactoryEngine.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Common.Engines;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Engine interface to create entities using the given Factory.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFactoryEngine : IApiEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The EntityFactory for the entitiesDB.
|
||||||
|
/// Use this to create entities in ECS.
|
||||||
|
/// </summary>
|
||||||
|
IEntityFactory Factory { set; }
|
||||||
|
}
|
11
TechbloxModdingAPI/Common/Engines/IFunEngine.cs
Normal file
11
TechbloxModdingAPI/Common/Engines/IFunEngine.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Common.Engines;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Engine interface to use entity functions to remove entities or swap their groups.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFunEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public IEntityFunctions Functions { set; }
|
||||||
|
}
|
12
TechbloxModdingAPI/Common/Engines/IReactionaryEngine.cs
Normal file
12
TechbloxModdingAPI/Common/Engines/IReactionaryEngine.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Engines
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine interface to react on an entity component being added or removed.
|
||||||
|
/// </summary>
|
||||||
|
public interface IReactionaryEngine<T> : IApiEngine, IReactOnAddAndRemove<T> where T : unmanaged, IEntityComponent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
11
TechbloxModdingAPI/Common/IApiEngine.cs
Normal file
11
TechbloxModdingAPI/Common/IApiEngine.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Common;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base engine interface used by all TechbloxModdingAPI engines
|
||||||
|
/// </summary>
|
||||||
|
public interface IApiEngine : IQueryingEntitiesEngine, IDisposable
|
||||||
|
{
|
||||||
|
}
|
9
TechbloxModdingAPI/Common/INamedApiEngine.cs
Normal file
9
TechbloxModdingAPI/Common/INamedApiEngine.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace TechbloxModdingAPI.Common;
|
||||||
|
|
||||||
|
public interface INamedApiEngine : IApiEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the engine
|
||||||
|
/// </summary>
|
||||||
|
string Name { get; }
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Engines
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Base engine interface used by all TechbloxModdingAPI engines
|
|
||||||
/// </summary>
|
|
||||||
public interface IApiEngine : IEngine, IQueryingEntitiesEngine, IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the engine
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the emitter can be removed with Manager.RemoveEventEmitter(name)
|
|
||||||
/// </summary>
|
|
||||||
bool isRemovable { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Engines
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Engine interface to create a ModEventEntityStruct in entitiesDB when Emit() is called.
|
|
||||||
/// </summary>
|
|
||||||
public interface IFactoryEngine : IApiEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The EntityFactory for the entitiesDB.
|
|
||||||
/// Use this to create a ModEventEntityStruct when Emit() is called.
|
|
||||||
/// </summary>
|
|
||||||
IEntityFactory Factory { set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Engines
|
|
||||||
{
|
|
||||||
public interface IFunEngine : IApiEngine
|
|
||||||
{
|
|
||||||
public IEntityFunctions Functions { set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.Internal;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Events;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Engines
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines.
|
|
||||||
/// </summary>
|
|
||||||
public interface IReactionaryEngine<T> : IApiEngine, IReactOnAddAndRemove<T> where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ namespace TechbloxModdingAPI.Input
|
||||||
{
|
{
|
||||||
public static class FakeInput
|
public static class FakeInput
|
||||||
{
|
{
|
||||||
internal static readonly FakeInputEngine inputEngine = new FakeInputEngine();
|
internal static readonly FakeInputEngine inputEngine = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Customize the local input.
|
/// Customize the local input.
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
using System;
|
using RobocraftX.Common;
|
||||||
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.Common.Input;
|
using RobocraftX.Common.Input;
|
||||||
using RobocraftX.Players;
|
using RobocraftX.Players;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Input
|
namespace TechbloxModdingAPI.Input
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
{
|
{
|
||||||
private bool automaticLayout;
|
private bool automaticLayout;
|
||||||
|
|
||||||
private FasterList<UIElement> elements = new FasterList<UIElement>();
|
private FasterList<UIElement> elements = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The rectangular area in the window that the UI group can use
|
/// The rectangular area in the window that the UI group can use
|
||||||
|
|
|
@ -70,7 +70,6 @@ namespace TechbloxModdingAPI
|
||||||
Wire.Init();
|
Wire.Init();
|
||||||
// init client
|
// init client
|
||||||
Logging.MetaDebugLog($"Initializing Client");
|
Logging.MetaDebugLog($"Initializing Client");
|
||||||
Client.Init();
|
|
||||||
Game.Init();
|
Game.Init();
|
||||||
// init UI
|
// init UI
|
||||||
Logging.MetaDebugLog($"Initializing UI");
|
Logging.MetaDebugLog($"Initializing UI");
|
||||||
|
|
|
@ -15,9 +15,9 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class SerializerManager
|
public static class SerializerManager
|
||||||
{
|
{
|
||||||
private static Dictionary<string, IEntitySerializer> _serializers = new Dictionary<string, IEntitySerializer>();
|
private static Dictionary<string, IEntitySerializer> _serializers = new();
|
||||||
|
|
||||||
private static Dictionary<string, Action<IEntitySerialization>> _registrations = new Dictionary<string, Action<IEntitySerialization>>();
|
private static Dictionary<string, Action<IEntitySerialization>> _registrations = new();
|
||||||
|
|
||||||
private static EnginesRoot _lastEnginesRoot;
|
private static EnginesRoot _lastEnginesRoot;
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ namespace TechbloxModdingAPI
|
||||||
public partial class Player : EcsObjectBase, IEquatable<Player>, IEquatable<EGID>
|
public partial class Player : EcsObjectBase, IEquatable<Player>, IEquatable<EGID>
|
||||||
{
|
{
|
||||||
// static functionality
|
// static functionality
|
||||||
private static readonly PlayerEngine playerEngine = new PlayerEngine();
|
private static readonly PlayerEngine playerEngine = new();
|
||||||
private static readonly PlayerEventsEngine playerEventsEngine = new PlayerEventsEngine();
|
private static readonly PlayerEventsEngine playerEventsEngine = new();
|
||||||
private static Player localPlayer;
|
private static Player localPlayer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -38,7 +38,7 @@ namespace TechbloxModdingAPI
|
||||||
switch (player)
|
switch (player)
|
||||||
{
|
{
|
||||||
case PlayerType.Remote:
|
case PlayerType.Remote:
|
||||||
return playerEngine.GetRemotePlayer() != uint.MaxValue;
|
return playerEngine.GetRemotePlayers().Length > 0;
|
||||||
case PlayerType.Local:
|
case PlayerType.Local:
|
||||||
return playerEngine.GetLocalPlayer() != uint.MaxValue;
|
return playerEngine.GetLocalPlayer() != uint.MaxValue;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ namespace TechbloxModdingAPI
|
||||||
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Player"/> class.
|
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Player"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The player's unique identifier.</param>
|
/// <param name="id">The player's unique identifier.</param>
|
||||||
public Player(uint id) : base(new EGID(id, CharacterExclusiveGroups.OnFootGroup))
|
public Player(uint id) : base(new EGID(id, CharacterExclusiveGroups.OnFootGroup), typeof(CharacterEntityDescriptor))
|
||||||
{
|
{
|
||||||
this.Id = id;
|
this.Id = id;
|
||||||
if (!Exists(id))
|
if (!Exists(id))
|
||||||
|
@ -100,38 +100,6 @@ namespace TechbloxModdingAPI
|
||||||
this.Type = playerEngine.GetLocalPlayer() == id ? PlayerType.Local : PlayerType.Remote;
|
this.Type = playerEngine.GetLocalPlayer() == id ? PlayerType.Local : PlayerType.Remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Player"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="player">The player type. Chooses the first available player matching the criteria.</param>
|
|
||||||
public Player(PlayerType player) : base(ecs =>
|
|
||||||
{
|
|
||||||
uint id;
|
|
||||||
switch (player)
|
|
||||||
{
|
|
||||||
case PlayerType.Local:
|
|
||||||
id = playerEngine.GetLocalPlayer();
|
|
||||||
break;
|
|
||||||
case PlayerType.Remote:
|
|
||||||
id = playerEngine.GetRemotePlayer();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
id = uint.MaxValue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id == uint.MaxValue)
|
|
||||||
{
|
|
||||||
throw new PlayerNotFoundException($"No player of {player} type exists");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new EGID(id, CharacterExclusiveGroups.OnFootGroup);
|
|
||||||
})
|
|
||||||
{
|
|
||||||
this.Type = player;
|
|
||||||
Id = base.Id.entityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// object fields & properties
|
// object fields & properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -14,11 +14,9 @@ using RobocraftX.SimulationModeState;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Techblox.Camera;
|
using Techblox.Camera;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using Svelto.ECS.DataStructures;
|
|
||||||
using Techblox.BuildingDrone;
|
using Techblox.BuildingDrone;
|
||||||
using Techblox.Character;
|
using Techblox.Character;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Input;
|
using TechbloxModdingAPI.Input;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
@ -58,15 +56,17 @@ namespace TechbloxModdingAPI.Players
|
||||||
return uint.MaxValue;
|
return uint.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetRemotePlayer()
|
public uint[] GetRemotePlayers()
|
||||||
{
|
{
|
||||||
if (!isReady) return uint.MaxValue;
|
if (!isReady) return Array.Empty<uint>();
|
||||||
var (localPlayers, count) = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers);
|
var (localPlayers, count) = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers);
|
||||||
if (count > 0)
|
var players = new uint[count];
|
||||||
{
|
for (int i = 0; i < count; i++)
|
||||||
return localPlayers[0].ID.entityID;
|
{
|
||||||
}
|
players[i] = localPlayers[i].ID.entityID;
|
||||||
return uint.MaxValue;
|
}
|
||||||
|
|
||||||
|
return players;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetAllPlayerCount()
|
public long GetAllPlayerCount()
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
using System;
|
|
||||||
using RobocraftX.Character;
|
using RobocraftX.Character;
|
||||||
using RobocraftX.Character.Movement;
|
using RobocraftX.Character.Movement;
|
||||||
using RobocraftX.Common.Input;
|
using RobocraftX.Common.Input;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Players
|
namespace TechbloxModdingAPI.Players
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,7 @@ using Unity.Mathematics;
|
||||||
|
|
||||||
using TechbloxModdingAPI.App;
|
using TechbloxModdingAPI.App;
|
||||||
using TechbloxModdingAPI.Blocks;
|
using TechbloxModdingAPI.Blocks;
|
||||||
|
using TechbloxModdingAPI.Client.App;
|
||||||
using TechbloxModdingAPI.Tests;
|
using TechbloxModdingAPI.Tests;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ namespace TechbloxModdingAPI.Players
|
||||||
while (Player.LocalPlayer.State != PlayerState.InSeat)
|
while (Player.LocalPlayer.State != PlayerState.InSeat)
|
||||||
{
|
{
|
||||||
bool cont = false;
|
bool cont = false;
|
||||||
Client.Instance.PromptUser(new SingleChoicePrompt("Testing", $"Enter the seat at {seat.Position} pls", "OK", () => cont = true));
|
Popup.PromptUser(new SingleChoicePrompt("Testing", $"Enter the seat at {seat.Position} pls", "OK", () => cont = true));
|
||||||
while (!cont)
|
while (!cont)
|
||||||
yield return Yield.It;
|
yield return Yield.It;
|
||||||
yield return new WaitForSecondsEnumerator(5f).Continue();
|
yield return new WaitForSecondsEnumerator(5f).Continue();
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace TechbloxModdingAPI
|
||||||
private Cluster cluster;
|
private Cluster cluster;
|
||||||
private readonly uint clusterId = uint.MaxValue;
|
private readonly uint clusterId = uint.MaxValue;
|
||||||
|
|
||||||
public SimBody(EGID id) : base(id)
|
public SimBody(EGID id) : base(id, typeof(ClusterEntityDescriptor))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,9 @@ namespace TechbloxModdingAPI.Tasks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly Svelto.Tasks.ExtraLean.Unity.UpdateMonoRunner extraLeanRunner = new Svelto.Tasks.ExtraLean.Unity.UpdateMonoRunner("TechbloxModdingAPIExtraLean");
|
public static readonly Svelto.Tasks.ExtraLean.Unity.UpdateMonoRunner extraLeanRunner = new("TechbloxModdingAPIExtraLean");
|
||||||
|
|
||||||
public static readonly Svelto.Tasks.Lean.Unity.UpdateMonoRunner leanRunner = new Svelto.Tasks.Lean.Unity.UpdateMonoRunner("TechbloxModdingAPILean");
|
public static readonly Svelto.Tasks.Lean.Unity.UpdateMonoRunner leanRunner = new("TechbloxModdingAPILean");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Schedule a task to run asynchronously.
|
/// Schedule a task to run asynchronously.
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace TechbloxModdingAPI.Tests
|
||||||
{
|
{
|
||||||
private static StreamWriter logFile = null;
|
private static StreamWriter logFile = null;
|
||||||
|
|
||||||
private static ConcurrentDictionary<string, string> callbacks = new ConcurrentDictionary<string, string>();
|
private static ConcurrentDictionary<string, string> callbacks = new();
|
||||||
|
|
||||||
private const string PASS = "SUCCESS: ";
|
private const string PASS = "SUCCESS: ";
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,12 @@ using Svelto.Tasks;
|
||||||
using Svelto.Tasks.Lean;
|
using Svelto.Tasks.Lean;
|
||||||
using Svelto.Tasks.Enumerators;
|
using Svelto.Tasks.Enumerators;
|
||||||
using Svelto.Tasks.Lean.Unity;
|
using Svelto.Tasks.Lean.Unity;
|
||||||
|
using TechbloxModdingAPI.Client.App;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
using TechbloxModdingAPI.App;
|
|
||||||
using TechbloxModdingAPI.Tasks;
|
using TechbloxModdingAPI.Tasks;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using GameState = TechbloxModdingAPI.Client.App.GameState;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Tests
|
namespace TechbloxModdingAPI.Tests
|
||||||
{
|
{
|
||||||
|
@ -66,19 +67,33 @@ namespace TechbloxModdingAPI.Tests
|
||||||
_testsCountPassed = 0;
|
_testsCountPassed = 0;
|
||||||
_testsCountFailed = 0;
|
_testsCountFailed = 0;
|
||||||
// flow control
|
// flow control
|
||||||
Game.Enter += (sender, args) => { GameTests().RunOn(new UpdateMonoRunner("TechbloxModdingAPITestRunner")); };
|
Client.App.GameClient.StateChanged += (sender, args) =>
|
||||||
Game.Exit += (s, a) => state = "ReturningFromGame";
|
|
||||||
Client.EnterMenu += (sender, args) =>
|
|
||||||
{
|
{
|
||||||
if (state == "EnteringMenu")
|
switch (args.NewState)
|
||||||
{
|
{
|
||||||
MenuTests().RunOn(Scheduler.leanRunner);
|
case GameState.InMenu:
|
||||||
state = "EnteringGame";
|
{
|
||||||
}
|
if (state == "EnteringMenu")
|
||||||
if (state == "ReturningFromGame")
|
{
|
||||||
{
|
MenuTests().RunOn(Scheduler.leanRunner);
|
||||||
TearDown().RunOn(Scheduler.leanRunner);
|
state = "EnteringGame";
|
||||||
state = "ShuttingDown";
|
}
|
||||||
|
|
||||||
|
if (state == "ReturningFromGame")
|
||||||
|
{
|
||||||
|
TearDown().RunOn(Scheduler.leanRunner);
|
||||||
|
state = "ShuttingDown";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GameState.InMachineEditor:
|
||||||
|
GameTests().RunOn(new UpdateMonoRunner("TechbloxModdingAPITestRunner"));
|
||||||
|
break;
|
||||||
|
case GameState.Loading:
|
||||||
|
if (args.OldState == GameState.InTestMode)
|
||||||
|
state = "ReturningFromGame";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// init tests here
|
// init tests here
|
||||||
|
@ -131,17 +146,16 @@ namespace TechbloxModdingAPI.Tests
|
||||||
|
|
||||||
private static IEnumerator<TaskContract> GoToGameTests()
|
private static IEnumerator<TaskContract> GoToGameTests()
|
||||||
{
|
{
|
||||||
Client app = Client.Instance;
|
|
||||||
int oldLength = 0;
|
int oldLength = 0;
|
||||||
while (app.MyGames.Length == 0 || oldLength != app.MyGames.Length)
|
while (GameClient.Machines.Length == 0 || oldLength != GameClient.Machines.Length)
|
||||||
{
|
{
|
||||||
oldLength = app.MyGames.Length;
|
oldLength = GameClient.Machines.Length;
|
||||||
yield return new WaitForSecondsEnumerator(1).Continue();
|
yield return new WaitForSecondsEnumerator(1).Continue();
|
||||||
}
|
}
|
||||||
yield return Yield.It;
|
yield return Yield.It;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
app.MyGames[0].EnterGame();
|
GameClient.Machines[0].EnterGame();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,23 +1,17 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Formatting;
|
|
||||||
using TechbloxModdingAPI.Blocks;
|
|
||||||
using TechbloxModdingAPI.Players;
|
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using RobocraftX.GUI.Debug;
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Experimental;
|
using TechbloxModdingAPI.Common;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
public class DebugInterfaceEngine : IApiEngine
|
public class DebugInterfaceEngine : IApiEngine
|
||||||
{
|
{
|
||||||
private static Dictionary<string, Func<string>> _extraInfo=new Dictionary<string, Func<string>>();
|
private static Dictionary<string, Func<string>> _extraInfo=new();
|
||||||
public void Ready()
|
public void Ready()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -46,8 +40,8 @@ namespace TechbloxModdingAPI.Utility
|
||||||
int index = list.FindLastIndex(inst => inst.opcode == OpCodes.Ldfld);
|
int index = list.FindLastIndex(inst => inst.opcode == OpCodes.Ldfld);
|
||||||
var array = new CodeInstruction[]
|
var array = new CodeInstruction[]
|
||||||
{
|
{
|
||||||
new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer
|
new(OpCodes.Ldloc_0), //StringBuffer
|
||||||
new CodeInstruction(OpCodes.Call, ((Action<StringBuilder>)AddInfo).Method)
|
new(OpCodes.Call, ((Action<StringBuilder>)AddInfo).Method)
|
||||||
};
|
};
|
||||||
list.InsertRange(index - 1, array); //-1: ldloc.1 ("local") before ldfld
|
list.InsertRange(index - 1, array); //-1: ldloc.1 ("local") before ldfld
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ using System.Linq;
|
||||||
|
|
||||||
using RobocraftX.StateSync;
|
using RobocraftX.StateSync;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Common;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
|
@ -12,7 +13,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class GameEngineManager
|
public static class GameEngineManager
|
||||||
{
|
{
|
||||||
private static Dictionary<string, IApiEngine> _gameEngines = new Dictionary<string, IApiEngine>();
|
private static Dictionary<string, IApiEngine> _gameEngines = new();
|
||||||
|
|
||||||
private static EnginesRoot _lastEngineRoot;
|
private static EnginesRoot _lastEngineRoot;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class GameState
|
public static class GameState
|
||||||
{
|
{
|
||||||
private static GameStateEngine gameEngine = new GameStateEngine();
|
private static GameStateEngine gameEngine = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the game in edit mode?
|
/// Is the game in edit mode?
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using RobocraftX.SimulationModeState;
|
using RobocraftX.SimulationModeState;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Common;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Common;
|
||||||
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
|
@ -14,7 +11,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class MenuEngineManager
|
public static class MenuEngineManager
|
||||||
{
|
{
|
||||||
private static Dictionary<string, IApiEngine> _menuEngines = new Dictionary<string, IApiEngine>();
|
private static Dictionary<string, IApiEngine> _menuEngines = new();
|
||||||
|
|
||||||
private static EnginesRoot _lastEngineRoot;
|
private static EnginesRoot _lastEngineRoot;
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Store wrappers so we can unregister them properly
|
/// Store wrappers so we can unregister them properly
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Dictionary<EventHandler<T>, EventHandler<T>> wrappers =
|
private static Dictionary<EventHandler<T>, EventHandler<T>> wrappers = new();
|
||||||
new Dictionary<EventHandler<T>, EventHandler<T>>();
|
|
||||||
|
|
||||||
public static WrappedHandler<T> operator +(WrappedHandler<T> original, EventHandler<T> added)
|
public static WrappedHandler<T> operator +(WrappedHandler<T> original, EventHandler<T> added)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue