Add ability to create & move block groups & other stuff

Added a way to store block groups as blueprints
Blocks can be added/removed from block groups, although it doesn't work well atm
Added some patches to the test class in an attempt to debug an unrelated issue
Added a command to test placing a block group
Added a SelectedBlueprint property to the Player class
This commit is contained in:
Norbi Peti 2020-11-12 02:39:58 +01:00
parent 3dd61b5e4f
commit d744aaab79
8 changed files with 332 additions and 47 deletions

View file

@ -240,6 +240,8 @@ namespace GamecraftModdingAPI
set set
{ {
MovementEngine.MoveBlock(Id, InitData, value); MovementEngine.MoveBlock(Id, InitData, value);
if (blockGroup != null)
blockGroup.PosAndRotCalculated = false;
} }
} }
@ -252,6 +254,8 @@ namespace GamecraftModdingAPI
set set
{ {
RotationEngine.RotateBlock(Id, InitData, value); RotationEngine.RotateBlock(Id, InitData, value);
if (blockGroup != null)
blockGroup.PosAndRotCalculated = false;
} }
} }
@ -354,16 +358,32 @@ namespace GamecraftModdingAPI
} }
} }
private BlockGroup blockGroup;
/// <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. /// Returns null if not part of a group.<br />
/// 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.
/// </summary> /// </summary>
public BlockGroup BlockGroup public BlockGroup BlockGroup
{ {
get => BlockEngine.GetBlockInfo(this, get
{
if (blockGroup != null) return blockGroup;
return blockGroup = BlockEngine.GetBlockInfo(this,
(BlockGroupEntityComponent bgec) => (BlockGroupEntityComponent bgec) =>
bgec.currentBlockGroup == -1 ? null : new BlockGroup(bgec.currentBlockGroup, this)); bgec.currentBlockGroup == -1 ? null : new BlockGroup(bgec.currentBlockGroup, this));
} }
set
{
blockGroup?.RemoveInternal(this);
BlockEngine.SetBlockInfo(this,
(ref BlockGroupEntityComponent bgec, BlockGroup val) => bgec.currentBlockGroup = val?.Id ?? -1,
value);
value?.AddInternal(this);
blockGroup = value;
}
}
/// <summary> /// <summary>
/// Whether the block exists. The other properties will return a default value if the block doesn't exist. /// Whether the block exists. The other properties will return a default value if the block doesn't exist.

View file

@ -1,4 +1,8 @@
using Gamecraft.Blocks.BlockGroups; using System;
using System.Collections;
using System.Collections.Generic;
using Gamecraft.Blocks.BlockGroups;
using Unity.Mathematics; using Unity.Mathematics;
using UnityEngine; using UnityEngine;
@ -10,11 +14,14 @@ 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.
/// </summary> /// </summary>
public class BlockGroup public class BlockGroup : ICollection<Block>
{ {
internal static BlueprintEngine _engine = new BlueprintEngine(); internal static BlueprintEngine _engine = new BlueprintEngine();
public int Id { get; } public int Id { get; }
private readonly Block sourceBlock; private readonly Block sourceBlock;
private readonly List<Block> blocks;
private float3 position, rotation;
internal bool PosAndRotCalculated;
internal BlockGroup(int id, Block block) internal BlockGroup(int id, Block block)
{ {
@ -22,41 +29,155 @@ namespace GamecraftModdingAPI
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!");
Id = id; Id = id;
sourceBlock = block; sourceBlock = block;
blocks = new List<Block>(GetBlocks());
} }
/// <summary> /// <summary>
/// The position of the block group. Calculated when GetBlocks() is used. /// The position of the block group (center). Recalculated if blocks have been added/removed since the last query.
/// </summary> /// </summary>
public float3 Position { get; private set; } public float3 Position
{
get
{
if (!PosAndRotCalculated)
Refresh();
return position;
}
set
{
var diff = value - position;
foreach (var block in blocks)
block.Position += diff;
if (!PosAndRotCalculated) //The condition can only be true if a block has been added/removed manually
Refresh(); //So the blocks array is up to date
else
position += diff;
}
}
/// <summary> /// <summary>
/// The rotation of the block group. Calculated when GetBlocks() is used. /// The rotation of the block group. Recalculated if blocks have been added/removed since the last query.
/// </summary> /// </summary>
public float3 Rotation { get; private set; } public float3 Rotation
{
get
{
if (!PosAndRotCalculated)
Refresh();
return rotation;
}
set
{
var diff = value - rotation;
var qdiff = Quaternion.Euler(diff);
foreach (var block in blocks)
{
block.Rotation += diff;
block.Position = qdiff * block.Position;
}
if (!PosAndRotCalculated)
Refresh();
else
rotation += diff;
}
}
/*/// <summary>
/// Removes all of the blocks in this group from the world.
/// </summary>
public void RemoveBlocks()
{
_engine.RemoveBlockGroup(Id); - TODO: Causes a hard crash
}*/
/// <summary>
/// Creates a new block group consisting of a single block.
/// You can add more blocks using the Add() method or by setting the BlockGroup property of the blocks.<br />
/// Note that only newly placed blocks should be added to groups.
/// </summary>
/// <param name="block">The block to add</param>
/// <returns>A new block group containing the given block</returns>
public static BlockGroup Create(Block block)
{
return new BlockGroup(_engine.CreateBlockGroup(default, default), block);
}
/// <summary> /// <summary>
/// Collects each block that is a part of this group. Also sets the position and rotation. /// Collects each block that is a part of this group. Also sets the position and rotation.
/// </summary> /// </summary>
/// <returns>An array of blocks</returns> /// <returns>An array of blocks</returns>
public Block[] GetBlocks() private Block[] GetBlocks()
{ {
if (!sourceBlock.Exists) return new[] {sourceBlock}; //The block must exist to get the others
var ret = _engine.GetBlocksFromGroup(sourceBlock.Id, out var pos, out var rot); var ret = _engine.GetBlocksFromGroup(sourceBlock.Id, out var pos, out var rot);
Position = pos; position = pos;
Rotation = ((Quaternion) rot).eulerAngles; rotation = ((Quaternion) rot).eulerAngles;
PosAndRotCalculated = true;
return ret; return ret;
} }
/// <summary> private void Refresh()
/// Removes all of the blocks in this group from the world.
/// </summary>
public void Remove()
{ {
_engine.RemoveBlockGroup(Id); blocks.Clear();
blocks.AddRange(GetBlocks());
} }
public static void Init() internal static void Init()
{ {
GameEngineManager.AddGameEngine(_engine); GameEngineManager.AddGameEngine(_engine);
} }
public IEnumerator<Block> GetEnumerator() => blocks.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => blocks.GetEnumerator();
/// <summary>
/// Adds a block to the group. You should only add newly placed blocks
/// so that the game initializes the group membership properly.
/// </summary>
/// <param name="item"></param>
/// <exception cref="NullReferenceException"></exception>
public void Add(Block item)
{
if (item == null) throw new NullReferenceException("Cannot add null to a block group");
item.BlockGroup = this; //Calls AddInternal
}
internal void AddInternal(Block item) => blocks.Add(item);
/// <summary>
/// Removes all blocks from this group.
/// You should not remove blocks that have been initialized, only those that you placed recently.
/// </summary>
public void Clear()
{
while (blocks.Count > 0)
Remove(blocks[blocks.Count - 1]);
}
public bool Contains(Block item) => blocks.Contains(item);
public void CopyTo(Block[] array, int arrayIndex) => blocks.CopyTo(array, arrayIndex);
/// <summary>
/// Removes a block from this group.
/// You should not remove blocks that have been initialized, only those that you placed recently.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
/// <exception cref="NullReferenceException"></exception>
public bool Remove(Block item)
{
if (item == null) throw new NullReferenceException("Cannot remove null from a block group");
bool ret = item.BlockGroup == this;
if (ret)
item.BlockGroup = null; //Calls RemoveInternal
return ret;
}
internal void RemoveInternal(Block item) => blocks.Remove(item);
public int Count => blocks.Count;
public bool IsReadOnly { get; } = false;
public Block this[int index] => blocks[index]; //Setting is not supported, since the order doesn't matter
} }
} }

View file

@ -5,10 +5,11 @@ using Svelto.ECS;
using GamecraftModdingAPI.Engines; using GamecraftModdingAPI.Engines;
using GamecraftModdingAPI.Utility; using GamecraftModdingAPI.Utility;
using RobocraftX.Blocks;
namespace GamecraftModdingAPI.Blocks namespace GamecraftModdingAPI.Blocks
{ {
public class BlockEventsEngine : IReactionaryEngine<DBEntityStruct> public class BlockEventsEngine : IReactionaryEngine<BlockTagEntityStruct>
{ {
public event EventHandler<BlockPlacedRemovedEventArgs> Placed; public event EventHandler<BlockPlacedRemovedEventArgs> Placed;
public event EventHandler<BlockPlacedRemovedEventArgs> Removed; public event EventHandler<BlockPlacedRemovedEventArgs> Removed;
@ -27,20 +28,20 @@ namespace GamecraftModdingAPI.Blocks
public bool isRemovable { get; } = false; public bool isRemovable { get; } = false;
private bool shouldAddRemove; private bool shouldAddRemove;
public void Add(ref DBEntityStruct entityComponent, EGID egid) public void Add(ref BlockTagEntityStruct entityComponent, EGID egid)
{ {
if (!(shouldAddRemove = !shouldAddRemove)) if (!(shouldAddRemove = !shouldAddRemove))
return; return;
ExceptionUtil.InvokeEvent(Placed, this, ExceptionUtil.InvokeEvent(Placed, this,
new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); new BlockPlacedRemovedEventArgs {ID = egid});
} }
public void Remove(ref DBEntityStruct entityComponent, EGID egid) public void Remove(ref BlockTagEntityStruct entityComponent, EGID egid)
{ {
if (!(shouldAddRemove = !shouldAddRemove)) if (!(shouldAddRemove = !shouldAddRemove))
return; return;
ExceptionUtil.InvokeEvent(Removed, this, ExceptionUtil.InvokeEvent(Removed, this,
new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); new BlockPlacedRemovedEventArgs {ID = egid});
} }
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using Gamecraft.Blocks.BlockGroups; using Gamecraft.Blocks.BlockGroups;
using Gamecraft.GUI.Blueprints; using Gamecraft.GUI.Blueprints;
@ -21,7 +22,7 @@ using Allocator = Svelto.Common.Allocator;
namespace GamecraftModdingAPI.Blocks namespace GamecraftModdingAPI.Blocks
{ {
public class BlueprintEngine : IApiEngine public class BlueprintEngine : IFactoryEngine
{ {
private readonly MethodInfo getBlocksFromGroup = private readonly MethodInfo getBlocksFromGroup =
AccessTools.Method("RobocraftX.CR.MachineEditing.PlaceBlockUtility:GetBlocksSharingBlockgroup"); AccessTools.Method("RobocraftX.CR.MachineEditing.PlaceBlockUtility:GetBlocksSharingBlockgroup");
@ -77,13 +78,30 @@ namespace GamecraftModdingAPI.Blocks
connectionFactory, default).Complete(); connectionFactory, default).Complete();
} }
public int CreateBlockGroup(float3 position, quaternion rotation)
{
int nextFilterId = BlockGroupUtility.NextFilterId;
Factory.BuildEntity<BlockGroupEntityDescriptor>((uint) nextFilterId,
BlockGroupExclusiveGroups.BlockGroupEntityGroup).Init(new BlockGroupTransformEntityComponent
{
blockGroupGridRotation = rotation,
blockGroupGridPosition = position
});
return nextFilterId;
}
public void SelectBlueprint(uint resourceID) public void SelectBlueprint(uint resourceID)
{ {
BlueprintUtil.SelectBlueprint(null, new BlueprintInventoryItemEntityStruct if (resourceID == uint.MaxValue)
BlueprintUtil.UnselectBlueprint(entitiesDB);
else
{
BlueprintUtil.SelectBlueprint(entitiesDB, new BlueprintInventoryItemEntityStruct
{ {
blueprintResourceId = resourceID, blueprintResourceId = resourceID,
}); });
} }
}
public uint CreateBlueprint() public uint CreateBlueprint()
{ {
@ -91,28 +109,27 @@ namespace GamecraftModdingAPI.Blocks
return index; return index;
} }
public void ReplaceBlueprint(uint playerID, uint blueprintID, Block[] selected, float3 pos, quaternion rot) public void ReplaceBlueprint(uint playerID, uint blueprintID, ICollection<Block> selected, float3 pos, quaternion rot)
{ {
var blockIDs = new EGID[selected.Length]; var blockIDs = new EGID[selected.Count];
for (var i = 0; i < selected.Length; i++) using (var enumerator = selected.GetEnumerator())
{ {
var block = selected[i]; for (var i = 0; enumerator.MoveNext(); i++)
{
var block = enumerator.Current;
blockIDs[i] = block.Id; blockIDs[i] = block.Id;
} }
}
var serializationData = clipboardManager.GetSerializationData(blueprintID); var serializationData = clipboardManager.GetSerializationData(blueprintID);
SelectionSerializationUtility.ClearClipboard(playerID, entitiesDB, entityFunctions, serializationData.blueprintData); SelectionSerializationUtility.ClearClipboard(playerID, entitiesDB, entityFunctions, serializationData.blueprintData);
if (selected.Length == 0) if (selected.Count == 0)
return; return;
//ref BlockGroupTransformEntityComponent groupTransform = ref EntityNativeDBExtensions.QueryEntity<BlockGroupTransformEntityComponent>(entitiesDb, (uint) local1.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup); //ref BlockGroupTransformEntityComponent groupTransform = ref EntityNativeDBExtensions.QueryEntity<BlockGroupTransformEntityComponent>(entitiesDb, (uint) local1.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup);
//ref ColliderAabb collider = ref EntityNativeDBExtensions.QueryEntity<ColliderAabb>(entitiesDB, (uint) groupID, BlockGroupExclusiveGroups.BlockGroupEntityGroup); //ref ColliderAabb collider = ref EntityNativeDBExtensions.QueryEntity<ColliderAabb>(entitiesDB, (uint) groupID, BlockGroupExclusiveGroups.BlockGroupEntityGroup);
//float3 bottomOffset = PlaceBlockUtility.GetBottomOffset(collider); //float3 bottomOffset = PlaceBlockUtility.GetBottomOffset(collider);
//var rootPosition = math.mul(groupTransform.blockGroupGridRotation, bottomOffset) + groupTransform.blockGroupGridPosition; //var rootPosition = math.mul(groupTransform.blockGroupGridRotation, bottomOffset) + groupTransform.blockGroupGridPosition;
//var rootRotation = groupTransform.blockGroupGridRotation; //var rootRotation = groupTransform.blockGroupGridRotation;
if (math.all(pos == default))
pos = selected[0].Position;
if (math.all(rot.value == default))
rot = Quaternion.Euler(selected[0].Rotation);
clipboardManager.SetGhostSerialized(blueprintID, false); clipboardManager.SetGhostSerialized(blueprintID, false);
SelectionSerializationUtility.CopySelectionToClipboard(playerID, entitiesDB, SelectionSerializationUtility.CopySelectionToClipboard(playerID, entitiesDB,
@ -189,7 +206,7 @@ namespace GamecraftModdingAPI.Blocks
} }
public string Name { get; } = "GamecraftModdingAPIBlueprintGameEngine"; public string Name { get; } = "GamecraftModdingAPIBlueprintGameEngine";
public bool isRemovable { get; } public bool isRemovable { get; } = false;
[HarmonyPatch] [HarmonyPatch]
private static class RemoveEnginePatch private static class RemoveEnginePatch
@ -225,5 +242,7 @@ namespace GamecraftModdingAPI.Blocks
return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.SelectBlockEngine"))[0]; return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.SelectBlockEngine"))[0];
} }
} }
public IEntityFactory Factory { get; set; }
} }
} }

View file

@ -53,15 +53,15 @@ namespace GamecraftModdingAPI.Blocks
private EntityComponentInitializer BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) private EntityComponentInitializer BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId)
{ {
if (_blockEntityFactory == null) if (_blockEntityFactory == null)
throw new Exception("The factory is null."); throw new BlockException("The factory is null.");
if (uscale < 1) if (uscale < 1)
throw new Exception("Scale needs to be at least 1"); throw new BlockException("Scale needs to be at least 1");
if (scale.x < 4e-5) scale.x = uscale; if (scale.x < 4e-5) scale.x = uscale;
if (scale.y < 4e-5) scale.y = uscale; if (scale.y < 4e-5) scale.y = uscale;
if (scale.z < 4e-5) scale.z = uscale; if (scale.z < 4e-5) scale.z = uscale;
uint dbid = block; uint dbid = block;
if (!PrefabsID.DBIDMAP.ContainsKey(dbid)) if (!PrefabsID.HasPrefabRegistered(dbid, 0))
throw new Exception("Block with ID " + dbid + " not found!"); throw new BlockException("Block with ID " + dbid + " not found!");
//RobocraftX.CR.MachineEditing.PlaceBlockEngine //RobocraftX.CR.MachineEditing.PlaceBlockEngine
ScalingEntityStruct scaling = new ScalingEntityStruct {scale = scale}; ScalingEntityStruct scaling = new ScalingEntityStruct {scale = scale};
Quaternion rotQ = Quaternion.Euler(rot); Quaternion rotQ = Quaternion.Euler(rot);

View file

@ -1,5 +1,6 @@
using System; using System;
using Unity.Mathematics; using Unity.Mathematics;
using UnityEngine;
namespace GamecraftModdingAPI namespace GamecraftModdingAPI
{ {
@ -35,16 +36,27 @@ namespace GamecraftModdingAPI
/// <summary> /// <summary>
/// Set the blocks that the blueprint contains. /// Set the blocks that the blueprint contains.
/// Use the BlockGroup overload for automatically calculated position and rotation.
/// </summary> /// </summary>
/// <param name="blocks">The array of blocks to use</param> /// <param name="blocks">The array of blocks to use</param>
/// <param name="position">The anchor position of the blueprint</param> /// <param name="position">The anchor position of the blueprint</param>
/// <param name="rotation">The rotation of the blueprint</param> /// <param name="rotation">The base rotation of the blueprint</param>
public void SetStoredBlocks(Block[] blocks, float3 position = default, float3 rotation = default) public void StoreBlocks(Block[] blocks, float3 position, float3 rotation)
{ {
BlockGroup._engine.ReplaceBlueprint(Player.LocalPlayer.Id, Id, blocks, position, BlockGroup._engine.ReplaceBlueprint(Player.LocalPlayer.Id, Id, blocks, position,
quaternion.Euler(rotation)); quaternion.Euler(rotation));
} }
/// <summary>
/// Store the blocks from the given group in the blueprint with correct position and rotation for the blueprint.
/// </summary>
/// <param name="group">The block group to store</param>
public void StoreBlocks(BlockGroup group)
{
BlockGroup._engine.ReplaceBlueprint(Player.LocalPlayer.Id, Id, group, group.Position,
Quaternion.Euler(group.Rotation));
}
/// <summary> /// <summary>
/// Places the blocks the blueprint contains at the specified position and rotation. /// Places the blocks the blueprint contains at the specified position and rotation.
/// </summary> /// </summary>

View file

@ -1,5 +1,5 @@
using System; using System;
using Gamecraft.GUI.Blueprints;
using Unity.Mathematics; using Unity.Mathematics;
using RobocraftX.Common; using RobocraftX.Common;
using RobocraftX.Common.Players; using RobocraftX.Common.Players;
@ -343,6 +343,17 @@ namespace GamecraftModdingAPI
} }
} }
/// <summary>
/// The player's selected blueprint in their hand. Set to null to clear. Dispose after usage.
/// </summary>
public Blueprint SelectedBlueprint
{
get => playerEngine.GetPlayerStruct(Id, out BlueprintInventoryItemEntityStruct biies)
? new Blueprint(biies.blueprintResourceId)
: null;
set => BlockGroup._engine.SelectBlueprint(value?.Id ?? uint.MaxValue);
}
// object methods // object methods
/// <summary> /// <summary>

View file

@ -1,24 +1,29 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit;
using System.Text; using System.Text;
using HarmonyLib; using HarmonyLib;
using IllusionInjector; using IllusionInjector;
// test // test
using GPUInstancer;
using Svelto.ECS; using Svelto.ECS;
using RobocraftX.Blocks; using RobocraftX.Blocks;
using RobocraftX.Common; using RobocraftX.Common;
using RobocraftX.SimulationModeState; using RobocraftX.SimulationModeState;
using RobocraftX.FrontEnd; using RobocraftX.FrontEnd;
using Unity.Mathematics; using Unity.Mathematics;
using UnityEngine;
using GamecraftModdingAPI.Commands; using GamecraftModdingAPI.Commands;
using GamecraftModdingAPI.Events; using GamecraftModdingAPI.Events;
using GamecraftModdingAPI.Utility; using GamecraftModdingAPI.Utility;
using GamecraftModdingAPI.Blocks; using GamecraftModdingAPI.Blocks;
using GamecraftModdingAPI.Players; using GamecraftModdingAPI.Players;
using EventType = GamecraftModdingAPI.Events.EventType;
namespace GamecraftModdingAPI.Tests namespace GamecraftModdingAPI.Tests
{ {
@ -269,6 +274,20 @@ namespace GamecraftModdingAPI.Tests
Logging.CommandLog("Health set to: " + val); Logging.CommandLog("Health set to: " + val);
}).Build(); }).Build();
CommandBuilder.Builder("placeBlockGroup", "Places some blocks in a group")
.Action((float x, float y, float z) =>
{
var pos = new float3(x, y, z);
var group = BlockGroup.Create(Block.PlaceNew(BlockIDs.AluminiumCube, pos,
color: BlockColors.Aqua));
Block.PlaceNew(BlockIDs.AluminiumCube, pos += new float3(1, 0, 0), color: BlockColors.Blue)
.BlockGroup = group;
Block.PlaceNew(BlockIDs.AluminiumCube, pos += new float3(1, 0, 0), color: BlockColors.Green)
.BlockGroup = group;
Block.PlaceNew(BlockIDs.AluminiumCube, pos += new float3(1, 0, 0), color: BlockColors.Lime)
.BlockGroup = group;
}).Build();
GameClient.SetDebugInfo("InstalledMods", InstalledMods); GameClient.SetDebugInfo("InstalledMods", InstalledMods);
Block.Placed += (sender, args) => Block.Placed += (sender, args) =>
Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID); Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID);
@ -391,6 +410,88 @@ namespace GamecraftModdingAPI.Tests
return ((Action) MinimumSpecsCheck.CheckRequirementsMet).Method; return ((Action) MinimumSpecsCheck.CheckRequirementsMet).Method;
} }
} }
[HarmonyPatch]
public class BugHuntPatch
{
public static MethodInfo method =
SymbolExtensions.GetMethodInfo<string>(str => Console.WriteLine(str));
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
int i = 0;
foreach (var instruction in instructions)
{
i++;
yield return instruction; //Return the instruction first
//stloc, dup, callvirt
if (instruction.opcode.Name.ToLower().StartsWith("stloc")
|| instruction.opcode == OpCodes.Dup
|| instruction.opcode == OpCodes.Callvirt)
{
yield return new CodeInstruction(OpCodes.Ldstr,
"Just ran the " + i + ". instruction ending with " + instruction.opcode.Name);
yield return new CodeInstruction(OpCodes.Call, method);
}
}
}
public static MethodInfo TargetMethod()
{
return AccessTools.Method("RobocraftX.CR.MachineEditing.BoxSelect.CopySelectionEngine:GenerateThumbnail");
}
}
[HarmonyPatch]
public class BugHuntPatch2
{
public static void Prefix(int width, float fieldOfView, Vector3 cameraDirection, Vector3 lightDirection)
{
Console.WriteLine("TakeThumbnail invoked with parameters: " + width + ", " + fieldOfView + ", " +
cameraDirection + ", " + lightDirection);
GPUInstancerManager manager = GPUInstancerAPI.GetActiveManagers().Find(m => m is GPUInstancerPrefabManager);
Bounds instancesBounds = manager.ComputeInstancesBounds(2);
Console.WriteLine("Bounds: " + instancesBounds);
Console.WriteLine("Size: " + instancesBounds.size);
Console.WriteLine("Size.x < 0: " + (instancesBounds.size.x < 0));
}
public static void Postfix(Texture2D __result)
{
Console.WriteLine("TakeThumbnail returned: " + (__result == null ? null : __result.name));
}
private delegate Texture2D TakeThumbnailDel(int width, float fieldOfView, Vector3 cameraDirection,
Vector3 lightDirection);
public static MethodInfo TargetMethod()
{
return ((TakeThumbnailDel) ThumbnailUtility.TakeThumbnail).Method;
}
}
[HarmonyPatch]
public class BugHuntPatch3
{
public static void Prefix(int width, int filterLayerMask, GPUInstancerManager manager,
Vector3 cameraPosition, Quaternion cameraRotation, float cameraFov, Vector3 lightDirection,
int cullingLayer)
{
Console.WriteLine("Inner TakeThumbnail invoked with parameters: " + width + ", " + filterLayerMask +
", " + (manager != null ? manager.name : null) + ", " + cameraPosition + ", " +
cameraRotation + ", " + cameraFov + ", " + lightDirection + ", " + cullingLayer);
}
private delegate Texture2D TakeThumbnailDel(int width, int filterLayerMask, GPUInstancerManager manager,
Vector3 cameraPosition, Quaternion cameraRotation, float cameraFov, Vector3 lightDirection,
int cullingLayer);
public static MethodInfo TargetMethod()
{
return ((TakeThumbnailDel) ThumbnailUtility.TakeThumbnail).Method;
}
}
} }
#endif #endif
} }