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
This commit is contained in:
Norbi Peti 2020-11-13 23:59:37 +01:00
parent 64b42830a3
commit 680721256c
5 changed files with 97 additions and 13 deletions

View file

@ -244,6 +244,7 @@ namespace GamecraftModdingAPI
MovementEngine.MoveBlock(Id, InitData, value); MovementEngine.MoveBlock(Id, InitData, value);
if (blockGroup != null) if (blockGroup != null)
blockGroup.PosAndRotCalculated = false; blockGroup.PosAndRotCalculated = false;
BlockEngine.UpdateDisplayedBlock(Id);
} }
} }
@ -258,6 +259,7 @@ namespace GamecraftModdingAPI
RotationEngine.RotateBlock(Id, InitData, value); RotationEngine.RotateBlock(Id, InitData, value);
if (blockGroup != null) if (blockGroup != null)
blockGroup.PosAndRotCalculated = false; blockGroup.PosAndRotCalculated = false;
BlockEngine.UpdateDisplayedBlock(Id);
} }
} }
@ -273,6 +275,7 @@ namespace GamecraftModdingAPI
BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value); BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value);
if (!Exists) return; //UpdateCollision needs the block to exist if (!Exists) return; //UpdateCollision needs the block to exist
ScalingEngine.UpdateCollision(Id); ScalingEngine.UpdateCollision(Id);
BlockEngine.UpdateDisplayedBlock(Id);
} }
} }
@ -364,8 +367,10 @@ namespace GamecraftModdingAPI
/// <summary> /// <summary>
/// Returns the block group this block is a part of. Block groups can be placed using blueprints. /// 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.<br /> /// Returns null if not part of a group.<br />
/// Setting the group after the block has been initialized will not update everything properly. /// 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. /// so you can only set this property on blocks newly placed by your code.<br />
/// To set it for existing blocks, you can use the Copy() method and set the property on the resulting block
/// (and remove this block).
/// </summary> /// </summary>
public BlockGroup BlockGroup public BlockGroup BlockGroup
{ {
@ -378,6 +383,15 @@ namespace GamecraftModdingAPI
} }
set set
{ {
if (Exists)
{
/*var copy = Copy<Block>();
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); blockGroup?.RemoveInternal(this);
BlockEngine.SetBlockInfo(this, BlockEngine.SetBlockInfo(this,
(ref BlockGroupEntityComponent bgec, BlockGroup val) => bgec.currentBlockGroup = val?.Id ?? -1, (ref BlockGroupEntityComponent bgec, BlockGroup val) => bgec.currentBlockGroup = val?.Id ?? -1,
@ -418,7 +432,7 @@ namespace GamecraftModdingAPI
} }
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public T Copy<T>() where T : Block public T Copy<T>() where T : Block

View file

@ -12,9 +12,9 @@ using GamecraftModdingAPI.Utility;
namespace GamecraftModdingAPI namespace GamecraftModdingAPI
{ {
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
public class BlockGroup : ICollection<Block> public class BlockGroup : ICollection<Block>, IDisposable
{ {
internal static BlueprintEngine _engine = new BlueprintEngine(); internal static BlueprintEngine _engine = new BlueprintEngine();
public int Id { get; } public int Id { get; }
@ -30,8 +30,30 @@ namespace GamecraftModdingAPI
Id = id; Id = id;
sourceBlock = block; sourceBlock = block;
blocks = new List<Block>(GetBlocks()); blocks = new List<Block>(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;
}
/// <summary> /// <summary>
/// The position of the block group (center). Recalculated if blocks have been added/removed since the last query. /// The position of the block group (center). Recalculated if blocks have been added/removed since the last query.
/// </summary> /// </summary>

View file

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using Gamecraft.Wires;
using GamecraftModdingAPI.Engines; using GamecraftModdingAPI.Engines;
using HarmonyLib; using HarmonyLib;
using RobocraftX.Blocks; using RobocraftX.Blocks;
@ -15,9 +17,15 @@ namespace GamecraftModdingAPI.Blocks
{ {
private static Type copyEngineType = private static Type copyEngineType =
AccessTools.TypeByName("Gamecraft.GUI.Tweaks.Engines.CopyTweaksOnPickEngine"); 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 copyFromBlock = AccessTools.Method(copyEngineType, "CopyTweaksFromBlock");
private MethodBase copyToBlock = AccessTools.Method(copyEngineType, "ApplyTweaksToPlacedBlock"); private MethodBase copyToBlock = AccessTools.Method(copyEngineType, "ApplyTweaksToPlacedBlock");
private MethodBase copyWireFromBlock = AccessTools.Method(copyWireEngineType, "CopyWireInputsAndOutputs");
private MethodBase copyWireToBlock = AccessTools.Method(createWireEngineType, "PlaceWiresOnPlaceNewCube");
public void Ready() public void Ready()
{ {
@ -45,13 +53,23 @@ namespace GamecraftModdingAPI.Blocks
if (entitiesDB.Exists<DBEntityStruct>(pickedBlock.pickedBlockEntityID) if (entitiesDB.Exists<DBEntityStruct>(pickedBlock.pickedBlockEntityID)
&& entitiesDB.Exists<DBEntityStruct>(pickedBlock.placedBlockEntityID)) && entitiesDB.Exists<DBEntityStruct>(pickedBlock.placedBlockEntityID))
{ {
copyFromBlock.Invoke(Patch.instance, new object[] {pickedBlock.ID, pickedBlock}); copyFromBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock});
copyToBlock.Invoke(Patch.instance, 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.placedBlockTweaksMustCopy = false;
pickedBlock.placedBlockTweaksCopied = 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] [HarmonyPatch]
private static class Patch 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) 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<MethodBase> TargetMethods()
{ {
return AccessTools.GetDeclaredConstructors(copyEngineType)[0]; return new[]
{
AccessTools.GetDeclaredConstructors(copyEngineType)[0],
AccessTools.GetDeclaredConstructors(copyWireEngineType)[0],
AccessTools.GetDeclaredConstructors(createWireEngineType)[0]
};
} }
} }

View file

@ -8,6 +8,8 @@ using Gamecraft.Wires;
using RobocraftX.Blocks; using RobocraftX.Blocks;
using RobocraftX.Common; using RobocraftX.Common;
using RobocraftX.Physics; using RobocraftX.Physics;
using RobocraftX.Rendering;
using Svelto.ECS.EntityStructs;
using Svelto.DataStructures; using Svelto.DataStructures;
using Svelto.ECS; using Svelto.ECS;
@ -149,6 +151,15 @@ namespace GamecraftModdingAPI.Blocks
} }
} }
public void UpdateDisplayedBlock(EGID id)
{
if (!BlockExists(id)) return;
var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
var rot = entitiesDB.QueryEntity<RotationEntityStruct>(id);
var scale = entitiesDB.QueryEntity<ScalingEntityStruct>(id);
entitiesDB.QueryEntity<RenderingDataStruct>(id).matrix = float4x4.TRS(pos.position, rot.rotation, scale.scale);
}
public bool BlockExists(EGID blockID) public bool BlockExists(EGID blockID)
{ {
return entitiesDB.Exists<DBEntityStruct>(blockID); return entitiesDB.Exists<DBEntityStruct>(blockID);

View file

@ -101,6 +101,13 @@ namespace GamecraftModdingAPI.Blocks
loadedFromDisk = false, loadedFromDisk = false,
placedBy = playerId placedBy = playerId
}); });
/*structInitializer.Init(new CollisionFilterOverride
{
belongsTo = 32U,
collidesWith = 239532U
});*/
PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer); PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer);
EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup); EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup);
ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID); ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID);