diff --git a/Automation/gen_csproj.py b/Automation/gen_csproj.py old mode 100755 new mode 100644 diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 336215e..db220dc 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -77,8 +77,11 @@ namespace GamecraftModdingAPI /// public float3 Position { - get => MovementEngine.GetPosition(Id.entityID); - set => MovementEngine.MoveBlock(Id.entityID, value); + get => Exists ? MovementEngine.GetPosition(Id.entityID) : float3.zero; + set + { + if (Exists) MovementEngine.MoveBlock(Id.entityID, value); + } } /// @@ -86,51 +89,41 @@ namespace GamecraftModdingAPI /// public float3 Rotation { - get => RotationEngine.GetRotation(Id.entityID); - set => RotationEngine.RotateBlock(Id.entityID, value); + get => Exists ? RotationEngine.GetRotation(Id.entityID) : float3.zero; + set + { + if (Exists) RotationEngine.RotateBlock(Id.entityID, value); + } } /// - /// The block's type (ID). Changing from or to a functional part may crash the game. + /// The block's type (ID). /// - public BlockIDs Type - { - get => (BlockIDs) BlockEngine.GetBlockInfo(Id).DBID; - set - { - BlockEngine.GetBlockInfo(Id).DBID = (uint) value; - uint prefabId = PrefabsID.GetPrefabId((uint) value, 0); - BlockEngine.GetBlockInfo(Id).prefabID = prefabId; - BlockEngine.GetBlockInfo(Id) = new PhysicsPrefabEntityStruct(prefabId); - } - } + public BlockIDs Type => (BlockIDs) (BlockEngine.GetBlockInfo(Id)?.DBID ?? 0); - public BlockColors Color + public BlockColor Color { - get => (BlockColors) (BlockEngine.GetBlockInfo(Id).indexInPalette % 10); + get + { + byte index = BlockEngine.GetBlockInfo(Id)?.indexInPalette ?? byte.MaxValue; + if (index == byte.MaxValue) return new BlockColor {Color = BlockColors.Default}; + return new BlockColor {Color = (BlockColors) (index % 10), Darkness = (byte) (index / 10)}; + } set { - ref var color = ref BlockEngine.GetBlockInfo(Id); - color.indexInPalette = (byte) (color.indexInPalette / 10 * 10 + value); + var def = new ColourParameterEntityStruct(); + ref var color = ref BlockEngine.GetBlockInfo(Id, ref def); + color.indexInPalette = (byte) (value.Color + value.Darkness * 10); color.needsUpdate = true; } } - public byte ColorDarkness - { - get => (byte) (BlockEngine.GetBlockInfo(Id).indexInPalette / 10); - set - { - ref var color = ref BlockEngine.GetBlockInfo(Id); - color.indexInPalette = (byte) (10 * (byte) value + color.indexInPalette % 10); - color.needsUpdate = true; - } - } + public bool Exists => BlockEngine.BlockExists(Id); /// /// Returns an array of blocks that are connected to this one. /// - public Block[] GetConnectedCubes() => BlockEngine.GetConnectedBlocks(Id.entityID); + public Block[] GetConnectedCubes() => BlockEngine.GetConnectedBlocks(Id); /// /// Removes this block. diff --git a/GamecraftModdingAPI/Blocks/BlockColors.cs b/GamecraftModdingAPI/Blocks/BlockColor.cs similarity index 50% rename from GamecraftModdingAPI/Blocks/BlockColors.cs rename to GamecraftModdingAPI/Blocks/BlockColor.cs index 146bcbf..fc87eb7 100644 --- a/GamecraftModdingAPI/Blocks/BlockColors.cs +++ b/GamecraftModdingAPI/Blocks/BlockColor.cs @@ -1,5 +1,16 @@ -namespace GamecraftModdingAPI.Blocks +namespace GamecraftModdingAPI.Blocks { + public struct BlockColor + { + public BlockColors Color; + public byte Darkness; + + public override string ToString() + { + return $"{nameof(Color)}: {Color}, {nameof(Darkness)}: {Darkness}"; + } + } + /// /// Preset block colours /// diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index a851643..f678501 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -25,20 +25,50 @@ namespace GamecraftModdingAPI.Blocks { } - public Block[] GetConnectedBlocks(uint blockID) + public Block[] GetConnectedBlocks(EGID blockID) { + if (!BlockExists(blockID)) return new Block[0]; Stack cubeStack = new Stack(); FasterList cubesToProcess = new FasterList(); - ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubesToProcess, (in GridConnectionsEntityStruct g) => { return false; }); + ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID.entityID, cubeStack, cubesToProcess, (in GridConnectionsEntityStruct g) => { return false; }); var ret = new Block[cubesToProcess.count]; for (int i = 0; i < cubesToProcess.count; i++) ret[i] = new Block(cubesToProcess[i]); return ret; } - public ref T GetBlockInfo(EGID blockID) where T : struct, IEntityComponent + /// + /// Get a struct of a block. Can be used to set properties. + /// When only querying parameters, use the other overload for convenience. + /// + /// + /// + /// + /// + public ref T GetBlockInfo(EGID blockID, ref T def) where T : struct, IEntityComponent { - return ref entitiesDB.QueryEntity(blockID); + if (entitiesDB.Exists(blockID)) + return ref entitiesDB.QueryEntity(blockID); + return ref def; + } + + /// + /// Get a struct of a block. Can only be used to retrieve information. + /// Use the overload with a default parameter to get the struct by reference to set values. + /// + /// The block's EGID + /// The struct's type to get + /// A copy of the struct or null + public T? GetBlockInfo(EGID blockID) where T : struct, IEntityComponent + { + if (entitiesDB.Exists(blockID)) + return entitiesDB.QueryEntity(blockID); + return null; + } + + public bool BlockExists(EGID id) + { + return entitiesDB.Exists(id); } } } \ No newline at end of file diff --git a/GamecraftModdingAPI/Blocks/BlockIDs.cs b/GamecraftModdingAPI/Blocks/BlockIDs.cs index 1a7a77a..bba2583 100644 --- a/GamecraftModdingAPI/Blocks/BlockIDs.cs +++ b/GamecraftModdingAPI/Blocks/BlockIDs.cs @@ -220,6 +220,11 @@ namespace GamecraftModdingAPI.Blocks CentreHUD, ObjectiveHUD, GameStatsHUD, //231 + GameOverBlock, + MovementConstrainer = 246, + RotationConstrainer, + AdvancedMovementDampener, + AdvancedRotationDampener, Mover = 250, Rotator, MovementDampener, diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs index e8ab256..3b15de8 100644 --- a/GamecraftModdingAPI/Main.cs +++ b/GamecraftModdingAPI/Main.cs @@ -72,6 +72,7 @@ namespace GamecraftModdingAPI // init object-oriented classes Player.Init(); Block.Init(); + DebugInterface.Init(); Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); } diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index 307b3f6..2e97df7 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -13,6 +13,7 @@ using GamecraftModdingAPI.Commands; using GamecraftModdingAPI.Events; using GamecraftModdingAPI.Utility; using GamecraftModdingAPI.Blocks; +using RobocraftX.FrontEnd; namespace GamecraftModdingAPI.Tests { @@ -174,9 +175,6 @@ namespace GamecraftModdingAPI.Tests CommandBuilder.Builder("getBlock") .Action(() => uREPL.Log.Output(new Player(Players.PlayerType.Local).GetBlockLookedAt()+"")).Build(); - CommandBuilder.Builder("changeToAluminium") - .Action(() => new Player(Players.PlayerType.Local).GetBlockLookedAt().Type = BlockIDs.AluminiumCube) - .Build(); CommandBuilder.Builder("Error", "Throw an error to make sure SimpleCustomCommandEngine's wrapper catches it.") .Action(() => { throw new Exception("Error Command always throws an error"); }) @@ -246,5 +244,20 @@ namespace GamecraftModdingAPI.Tests public void OnLevelWasLoaded(int level) { } public void OnUpdate() { } + + [HarmonyPatch] + public class MinimumSpecsPatch + { + public static bool Prefix(ref bool __result) + { + __result = true; + return false; + } + + public static MethodInfo TargetMethod() + { + return ((Func)MinimumSpecsCheck.CheckRequirementsMet).Method; + } + } } } diff --git a/GamecraftModdingAPI/Utility/DebugInterface.cs b/GamecraftModdingAPI/Utility/DebugInterface.cs new file mode 100644 index 0000000..1d5499e --- /dev/null +++ b/GamecraftModdingAPI/Utility/DebugInterface.cs @@ -0,0 +1,30 @@ +using System; +using GamecraftModdingAPI.Blocks; + +namespace GamecraftModdingAPI.Utility +{ + public static class DebugInterface + { + private static DebugInterfaceEngine _engine = new DebugInterfaceEngine(); + + /// + /// Saves the extra information to be displayed on the debug view. + /// The provided getter function is called each time the view updates so make sure it returns quickly. + /// + /// A global ID for the custom information + /// A function that returns the current information + public static void SetInfo(string id, Func contentGetter) => _engine.SetInfo(id, contentGetter); + + /// + /// Removes an information provided by a plugin. + /// + /// The ID of the custom information + /// + public static bool RemoveInfo(string id) => _engine.RemoveInfo(id); + + public static void Init() + { + GameEngineManager.AddGameEngine(_engine); + } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs b/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs new file mode 100644 index 0000000..2d470bb --- /dev/null +++ b/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Text.Formatting; +using GamecraftModdingAPI.Blocks; +using GamecraftModdingAPI.Engines; +using GamecraftModdingAPI.Players; +using HarmonyLib; +using RobocraftX.GUI.Debug; +using Svelto.ECS; +using Svelto.ECS.Experimental; + +namespace GamecraftModdingAPI.Utility +{ + public class DebugInterfaceEngine : IApiEngine + { + private static Dictionary> _extraInfo=new Dictionary>(); + public void Ready() + { + SetInfo("lookedAt", LookedAt); + } + + public EntitiesDB entitiesDB { get; set; } + + public void Dispose() + { + } + + public void SetInfo(string id, Func contentGetter) => _extraInfo[id] = contentGetter; + public bool RemoveInfo(string id) => _extraInfo.Remove(id); + + private Player player; + private string LookedAt() + { + if (player == null) + player = new Player(PlayerType.Local); + Block block = player.GetBlockLookedAt(); + if (block == null) return "Block: none"; + return "Block: " + block.Type + "\nColor: " + block.Color + "\n" + "At: " + block.Position; + } + + public string Name { get; } = "GamecraftModdingAPIDebugInterfaceGameEngine"; + public bool isRemovable { get; } = true; + + [HarmonyPatch] + private class Patch + { + public static IEnumerable Transpiler(IEnumerable instructions) + { + var list = new List(instructions); + try + { + //Before setting the text from the StringBuffer + int index = list.FindLastIndex(inst => inst.opcode == OpCodes.Ldfld); + var array = new CodeInstruction[] + { + new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer + new CodeInstruction(OpCodes.Call, ((Action)AddInfo).Method) + }; + list.InsertRange(index, array); + } + catch (Exception e) + { + Console.WriteLine(e); + } + + return list; + } + + public static void AddInfo(StringBuffer sb) + { + foreach (var info in _extraInfo.Values) + sb.Append(info() + "\n"); + } + + public static MethodInfo TargetMethod() + { + return AccessTools.Method("RobocraftX.GUI.Debug.DebugDisplayEngine:UpdateDisplay"); + } + } + } +} \ No newline at end of file