Add support for setting and placing blueprints

This commit is contained in:
Norbi Peti 2020-11-10 19:28:36 +01:00
parent 4f8feaa24b
commit 1c4e2a0db2
3 changed files with 199 additions and 3 deletions

View file

@ -1,13 +1,22 @@
using System.Reflection;
using System;
using System.Reflection;
using Gamecraft.Blocks.BlockGroups;
using Gamecraft.GUI.Blueprints;
using GamecraftModdingAPI.Engines;
using GamecraftModdingAPI.Utility;
using HarmonyLib;
using RobocraftX.Blocks;
using RobocraftX.Common;
using RobocraftX.CR.MachineEditing.BoxSelect;
using RobocraftX.CR.MachineEditing.BoxSelect.ClipboardOperations;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.DataStructures;
using Svelto.ECS.EntityStructs;
using Svelto.ECS.Serialization;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;
namespace GamecraftModdingAPI.Blocks
{
@ -18,8 +27,20 @@ namespace GamecraftModdingAPI.Blocks
private readonly NativeDynamicArray selectedBlocksInGroup = new NativeDynamicArray();
private readonly NativeHashSet<ulong> removedConnections = new NativeHashSet<ulong>();
private static readonly Type PlaceBlueprintUtilityType =
AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceBlueprintUtility");
private static readonly FieldInfo LocalBlockMap =
AccessTools.DeclaredField(PlaceBlueprintUtilityType, "_localBlockMap");
private static readonly MethodInfo BuildBlock = AccessTools.Method(PlaceBlueprintUtilityType, "BuildBlock");
private static readonly MethodInfo BuildWires = AccessTools.Method(PlaceBlueprintUtilityType, "BuildWires");
private static NativeEntityRemove nativeRemove;
private static MachineGraphConnectionEntityFactory connectionFactory;
private static IEntityFunctions entityFunctions;
private static ClipboardSerializationDataResourceManager clipboardManager;
private static IEntitySerialization entitySerialization;
private static IEntityFactory entityFactory;
private static FasterList<EGID> globalBlockMap;
public void Ready()
{
@ -55,6 +76,109 @@ namespace GamecraftModdingAPI.Blocks
});
}
public uint CreateBlueprint()
{
uint index = clipboardManager.AllocateSerializationData();
return index;
}
public void ReplaceBlueprint(uint playerID, uint blueprintID, Block[] selected, float3 pos, quaternion rot)
{
var blockIDs = new EGID[selected.Length];
for (var i = 0; i < selected.Length; i++)
{
var block = selected[i];
blockIDs[i] = block.Id;
}
var serializationData = clipboardManager.GetSerializationData(blueprintID);
SelectionSerializationUtility.ClearClipboard(playerID, entitiesDB, entityFunctions, serializationData.blueprintData);
if (selected.Length == 0)
return;
//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);
//float3 bottomOffset = PlaceBlockUtility.GetBottomOffset(collider);
//var rootPosition = math.mul(groupTransform.blockGroupGridRotation, bottomOffset) + groupTransform.blockGroupGridPosition;
//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);
SelectionSerializationUtility.CopySelectionToClipboard(playerID, entitiesDB,
serializationData.blueprintData, entitySerialization, entityFactory, blockIDs,
(uint) blockIDs.Length, pos, rot);
}
public Block[] PlaceBlueprintBlocks(uint blueprintID, uint playerID, float3 pos, float3 rot)
{ //RobocraftX.CR.MachineEditing.PlaceBlueprintUtility.PlaceBlocksFromSerialisedData
var serializationData = clipboardManager.GetSerializationData(blueprintID);
var blueprintData = serializationData.blueprintData;
blueprintData.dataPos = 0U;
uint selectionSize;
PositionEntityStruct selectionPosition;
RotationEntityStruct selectionRotation;
uint version;
BoxSelectSerializationUtilities.ReadClipboardHeader(blueprintData, out selectionSize, out selectionPosition, out selectionRotation, out version);
((FasterList<EGID>) LocalBlockMap.GetValue(null)).Clear();
if (version <= 1U)
{
uint groupsCount;
BoxSelectSerializationUtilities.ReadBlockGroupData(blueprintData, out groupsCount);
for (int index = 0; (long) index < (long) groupsCount; ++index)
{
int nextFilterId = BlockGroupUtility.NextFilterId;
entitySerialization.DeserializeNewEntity(new EGID((uint) nextFilterId, BlockGroupExclusiveGroups.BlockGroupEntityGroup), blueprintData, 1);
}
}
int nextFilterId1 = BlockGroupUtility.NextFilterId;
entityFactory.BuildEntity<BlockGroupEntityDescriptor>(new EGID((uint) nextFilterId1, BlockGroupExclusiveGroups.BlockGroupEntityGroup)).Init(new BlockGroupTransformEntityComponent
{
blockGroupGridPosition = selectionPosition.position,
blockGroupGridRotation = selectionRotation.rotation
});
var frot = Quaternion.Euler(rot);
var grid = new GridRotationStruct {position = pos, rotation = frot};
var poss = new PositionEntityStruct {position = pos};
var rots = new RotationEntityStruct {rotation = frot};
for (int index = 0; (long) index < (long) selectionSize; ++index)
BuildBlock.Invoke(null,
new object[]
{
playerID, grid, poss, rots, selectionPosition, selectionRotation, blueprintData,
entitiesDB, entitySerialization, nextFilterId1
});
/*
uint playerId, in GridRotationStruct ghostParentGrid,
in PositionEntityStruct ghostParentPosition, in RotationEntityStruct ghostParentRotation,
in PositionEntityStruct selectionPosition, in RotationEntityStruct selectionRotation,
ISerializationData serializationData, EntitiesDB entitiesDb,
IEntitySerialization entitySerialization, int blockGroupId
*/
if (globalBlockMap == null)
globalBlockMap = FullGameFields._deserialisedBlockMap;
var placedBlocks = (FasterList<EGID>) LocalBlockMap.GetValue(null);
globalBlockMap.Clear();
globalBlockMap.AddRange(placedBlocks);
BuildWires.Invoke(null,
new object[] {playerID, blueprintData, entitySerialization, entitiesDB, entityFactory});
var blocks = new Block[placedBlocks.count];
for (int i = 0; i < blocks.Length; i++)
blocks[i] = new Block(placedBlocks[i]);
return blocks;
}
public void InitBlueprint(uint blueprintID)
{
clipboardManager.IncrementRefCount(blueprintID);
}
public void DisposeBlueprint(uint blueprintID)
{
clipboardManager.DecrementRefCount(blueprintID);
}
public string Name { get; } = "GamecraftModdingAPIBlueprintGameEngine";
public bool isRemovable { get; }
@ -66,6 +190,7 @@ namespace GamecraftModdingAPI.Blocks
{
nativeRemove = entityFunctions.ToNativeRemove<BlockEntityDescriptor>("GCAPI" + nameof(BlueprintEngine));
connectionFactory = machineGraphConnectionEntityFactory;
BlueprintEngine.entityFunctions = entityFunctions;
}
public static MethodBase TargetMethod()
@ -73,5 +198,23 @@ namespace GamecraftModdingAPI.Blocks
return AccessTools.Constructor(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine"));
}
}
[HarmonyPatch]
private static class SelectEnginePatch
{
public static void Prefix(ClipboardSerializationDataResourceManager clipboardSerializationDataResourceManager,
IEntitySerialization entitySerialization,
IEntityFactory entityFactory)
{
clipboardManager = clipboardSerializationDataResourceManager;
BlueprintEngine.entitySerialization = entitySerialization;
BlueprintEngine.entityFactory = entityFactory;
}
public static MethodBase TargetMethod()
{
return AccessTools.Constructor(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.SelectBlockEngine"));
}
}
}
}

View file

@ -1,13 +1,20 @@
using Gamecraft.GUI.Blueprints;
using System;
using Unity.Mathematics;
namespace GamecraftModdingAPI
{
/// <summary>
/// Represents a blueprint in the inventory. When placed it becomes a block group.
/// </summary>
public class Blueprint
public class Blueprint : IDisposable
{
public uint Id { get; }
internal Blueprint(uint id)
{
Id = id;
BlockGroup._engine.InitBlueprint(id);
}
/*public static void SelectBlueprint(Blueprint blueprint)
{
@ -16,5 +23,42 @@ namespace GamecraftModdingAPI
blueprintResourceId = blueprint.Id
});
}*/
/// <summary>
/// Creates a new, empty blueprint. It will be deleted on disposal unless the game holds a reference to it.
/// </summary>
/// <returns>A blueprint that doesn't have any blocks</returns>
public static Blueprint Create()
{
return new Blueprint(BlockGroup._engine.CreateBlueprint());
}
/// <summary>
/// Set the blocks that the blueprint contains.
/// </summary>
/// <param name="blocks">The array of blocks to use</param>
/// <param name="position">The anchor position of the blueprint</param>
/// <param name="rotation">The rotation of the blueprint</param>
public void SetStoredBlocks(Block[] blocks, float3 position = default, float3 rotation = default)
{
BlockGroup._engine.ReplaceBlueprint(Player.LocalPlayer.Id, Id, blocks, position,
quaternion.Euler(rotation));
}
/// <summary>
/// Places the blocks the blueprint contains at the specified position and rotation.
/// </summary>
/// <param name="position">The position of the blueprint</param>
/// <param name="rotation">The rotation of the blueprint</param>
/// <returns>An array of the placed blocks</returns>
public Block[] PlaceBlocks(float3 position, float3 rotation)
{
return BlockGroup._engine.PlaceBlueprintBlocks(Id, Player.LocalPlayer.Id, position, rotation);
}
public void Dispose()
{
BlockGroup._engine.DisposeBlueprint(Id);
}
}
}

View file

@ -12,6 +12,7 @@ using RobocraftX.GUI;
using RobocraftX.Multiplayer;
using RobocraftX.Rendering;
using Svelto.Context;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.Schedulers.Unity;
using UnityEngine;
@ -159,6 +160,14 @@ namespace GamecraftModdingAPI.Utility
}
}
public static FasterList<EGID> _deserialisedBlockMap
{
get
{
return (FasterList<EGID>) fgcr?.Field("_deserialisedBlockMap").GetValue();
}
}
private static Traverse fgcr;
public static void Init(FullGameCompositionRoot instance)