From 680721256c101fc2ddeab01323ab89850e41fb72 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 13 Nov 2020 23:59:37 +0100 Subject: [PATCH] Add support for copying wires, some fixes and additions Removing blocks from groups when they are removed from the game Attempted to update graphics when changing blocks Disallowing changing the block group after creation, now that we can copy blocks --- GamecraftModdingAPI/Block.cs | 20 +++++++-- GamecraftModdingAPI/BlockGroup.cs | 28 ++++++++++-- .../Blocks/BlockCloneEngine.cs | 44 ++++++++++++++++--- GamecraftModdingAPI/Blocks/BlockEngine.cs | 11 +++++ GamecraftModdingAPI/Blocks/PlacementEngine.cs | 7 +++ 5 files changed, 97 insertions(+), 13 deletions(-) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 59914fd..0fecf40 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -244,6 +244,7 @@ namespace GamecraftModdingAPI MovementEngine.MoveBlock(Id, InitData, value); if (blockGroup != null) blockGroup.PosAndRotCalculated = false; + BlockEngine.UpdateDisplayedBlock(Id); } } @@ -258,6 +259,7 @@ namespace GamecraftModdingAPI RotationEngine.RotateBlock(Id, InitData, value); if (blockGroup != null) blockGroup.PosAndRotCalculated = false; + BlockEngine.UpdateDisplayedBlock(Id); } } @@ -273,6 +275,7 @@ namespace GamecraftModdingAPI BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value); if (!Exists) return; //UpdateCollision needs the block to exist ScalingEngine.UpdateCollision(Id); + BlockEngine.UpdateDisplayedBlock(Id); } } @@ -364,8 +367,10 @@ namespace GamecraftModdingAPI /// /// Returns the block group this block is a part of. Block groups can be placed using blueprints. /// Returns null if not part of a group.
- /// Setting the group after the block has been initialized will not update everything properly. - /// You should only set this property on blocks newly placed by your code. + /// Setting the group after the block has been initialized will not update everything properly, + /// so you can only set this property on blocks newly placed by your code.
+ /// To set it for existing blocks, you can use the Copy() method and set the property on the resulting block + /// (and remove this block). ///
public BlockGroup BlockGroup { @@ -378,6 +383,15 @@ namespace GamecraftModdingAPI } set { + if (Exists) + { + /*var copy = Copy(); + copy.BlockGroup = value; //It won't run this on the new instance as it won't 'exist' yet + Remove();*/ + Logging.LogWarning("Attempted to set group of existing block. This is not supported." + + " Copy the block and set the group of the resulting block."); + return; + } blockGroup?.RemoveInternal(this); BlockEngine.SetBlockInfo(this, (ref BlockGroupEntityComponent bgec, BlockGroup val) => bgec.currentBlockGroup = val?.Id ?? -1, @@ -418,7 +432,7 @@ namespace GamecraftModdingAPI } /// - /// Creates a copy of the block in the game with the same basic properties and tweakable stats. + /// Creates a copy of the block in the game with the same properties, stats and wires. /// /// public T Copy() where T : Block diff --git a/GamecraftModdingAPI/BlockGroup.cs b/GamecraftModdingAPI/BlockGroup.cs index a82e776..4a0d994 100644 --- a/GamecraftModdingAPI/BlockGroup.cs +++ b/GamecraftModdingAPI/BlockGroup.cs @@ -12,9 +12,9 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI { /// - /// A group of blocks that can be selected together. The placed version of blueprints. + /// A group of blocks that can be selected together. The placed version of blueprints. Dispose after usage. /// - public class BlockGroup : ICollection + public class BlockGroup : ICollection, IDisposable { internal static BlueprintEngine _engine = new BlueprintEngine(); public int Id { get; } @@ -30,8 +30,30 @@ namespace GamecraftModdingAPI Id = id; sourceBlock = block; blocks = new List(GetBlocks()); + Block.Removed += OnBlockRemoved; } - + + private void OnBlockRemoved(object sender, BlockPlacedRemovedEventArgs e) + { + //blocks.RemoveAll(block => block.Id == e.ID); - Allocation heavy + int index = -1; + for (int i = 0; i < blocks.Count; i++) + { + if (blocks[i].Id == e.ID) + { + index = i; + break; + } + } + + if (index != -1) blocks.RemoveAt(index); + } + + public void Dispose() + { + Block.Removed -= OnBlockRemoved; + } + /// /// The position of the block group (center). Recalculated if blocks have been added/removed since the last query. /// diff --git a/GamecraftModdingAPI/Blocks/BlockCloneEngine.cs b/GamecraftModdingAPI/Blocks/BlockCloneEngine.cs index d4d16f1..0acf44d 100644 --- a/GamecraftModdingAPI/Blocks/BlockCloneEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockCloneEngine.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Reflection; +using Gamecraft.Wires; using GamecraftModdingAPI.Engines; using HarmonyLib; using RobocraftX.Blocks; @@ -15,9 +17,15 @@ namespace GamecraftModdingAPI.Blocks { private static Type copyEngineType = AccessTools.TypeByName("Gamecraft.GUI.Tweaks.Engines.CopyTweaksOnPickEngine"); + private static Type copyWireEngineType = + AccessTools.TypeByName("Gamecraft.Wires.WireConnectionCopyOnPickEngine"); + private static Type createWireEngineType = + AccessTools.TypeByName("RobocraftX.GUI.Wires.WireConnectionCreateOnPlaceEngine"); private MethodBase copyFromBlock = AccessTools.Method(copyEngineType, "CopyTweaksFromBlock"); private MethodBase copyToBlock = AccessTools.Method(copyEngineType, "ApplyTweaksToPlacedBlock"); + private MethodBase copyWireFromBlock = AccessTools.Method(copyWireEngineType, "CopyWireInputsAndOutputs"); + private MethodBase copyWireToBlock = AccessTools.Method(createWireEngineType, "PlaceWiresOnPlaceNewCube"); public void Ready() { @@ -45,13 +53,23 @@ namespace GamecraftModdingAPI.Blocks if (entitiesDB.Exists(pickedBlock.pickedBlockEntityID) && entitiesDB.Exists(pickedBlock.placedBlockEntityID)) { - copyFromBlock.Invoke(Patch.instance, new object[] {pickedBlock.ID, pickedBlock}); - copyToBlock.Invoke(Patch.instance, new object[] {pickedBlock.ID, pickedBlock}); + copyFromBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock}); + + uint playerID = Player.LocalPlayer.Id; + var parameters = new object[] {playerID, pickedBlock}; + copyWireFromBlock.Invoke(Patch.copyWireEngine, parameters); + pickedBlock = (PickedBlockExtraDataStruct) parameters[1]; //ref arg + + copyToBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock}); + + ExclusiveGroupStruct group = WiresExclusiveGroups.WIRES_COPY_GROUP + playerID; + copyWireToBlock.Invoke(Patch.createWireEngine, new object[] {group, pickedBlock.ID}); + pickedBlock.placedBlockTweaksMustCopy = false; pickedBlock.placedBlockTweaksCopied = false; } - pickedBlock = oldStruct; //Make sure to not interfere with the game + pickedBlock = oldStruct; //Make sure to not interfere with the game - Although that might not be the case with the wire copying } } } @@ -59,16 +77,28 @@ namespace GamecraftModdingAPI.Blocks [HarmonyPatch] private static class Patch { - public static object instance; + public static object copyEngine; + public static object copyWireEngine; + public static object createWireEngine; public static void Postfix(object __instance) { - instance = __instance; + if (__instance.GetType() == copyEngineType) + copyEngine = __instance; + else if (__instance.GetType() == copyWireEngineType) + copyWireEngine = __instance; + else if (__instance.GetType() == createWireEngineType) + createWireEngine = __instance; } - public static MethodBase TargetMethod() + public static IEnumerable TargetMethods() { - return AccessTools.GetDeclaredConstructors(copyEngineType)[0]; + return new[] + { + AccessTools.GetDeclaredConstructors(copyEngineType)[0], + AccessTools.GetDeclaredConstructors(copyWireEngineType)[0], + AccessTools.GetDeclaredConstructors(createWireEngineType)[0] + }; } } diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 351d686..2da04a3 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -8,6 +8,8 @@ using Gamecraft.Wires; using RobocraftX.Blocks; using RobocraftX.Common; using RobocraftX.Physics; +using RobocraftX.Rendering; +using Svelto.ECS.EntityStructs; using Svelto.DataStructures; using Svelto.ECS; @@ -149,6 +151,15 @@ namespace GamecraftModdingAPI.Blocks } } + public void UpdateDisplayedBlock(EGID id) + { + if (!BlockExists(id)) return; + var pos = entitiesDB.QueryEntity(id); + var rot = entitiesDB.QueryEntity(id); + var scale = entitiesDB.QueryEntity(id); + entitiesDB.QueryEntity(id).matrix = float4x4.TRS(pos.position, rot.rotation, scale.scale); + } + public bool BlockExists(EGID blockID) { return entitiesDB.Exists(blockID); diff --git a/GamecraftModdingAPI/Blocks/PlacementEngine.cs b/GamecraftModdingAPI/Blocks/PlacementEngine.cs index 5357e7f..fab9c62 100644 --- a/GamecraftModdingAPI/Blocks/PlacementEngine.cs +++ b/GamecraftModdingAPI/Blocks/PlacementEngine.cs @@ -101,6 +101,13 @@ namespace GamecraftModdingAPI.Blocks loadedFromDisk = false, placedBy = playerId }); + + /*structInitializer.Init(new CollisionFilterOverride + { + belongsTo = 32U, + collidesWith = 239532U + });*/ + PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer); EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup); ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity(playerEGID);