TechbloxModdingAPI/GamecraftModdingAPI/Blocks/BlueprintEngine.cs

319 lines
14 KiB
C#

using System;
using System.Collections.Generic;
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;
using Allocator = Svelto.Common.Allocator;
namespace GamecraftModdingAPI.Blocks
{
public class BlueprintEngine : IFactoryEngine
{
private readonly MethodInfo getBlocksFromGroup =
AccessTools.Method("RobocraftX.CR.MachineEditing.PlaceBlockUtility:GetBlocksSharingBlockgroup");
private NativeDynamicArray selectedBlocksInGroup;
private NativeHashSet<ulong> removedConnections = new NativeHashSet<ulong>();
private int addingToBlockGroup = -1;
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 readonly Type SerializeGhostBlueprintType =
AccessTools.TypeByName("RobocraftX.CR.MachineEditing.BoxSelect.SerializeGhostChildrenOnAddEngine");
private static readonly MethodInfo SerializeGhostBlueprint =
AccessTools.Method(SerializeGhostBlueprintType, "SerializeClipboardGhostEntities");
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;
private static object SerializeGhostBlueprintInstance;
private static GhostChildEntityFactory BuildGhostBlueprintFactory;
public void Ready()
{
selectedBlocksInGroup = NativeDynamicArray.Alloc<EGID>(Allocator.Persistent);
}
public EntitiesDB entitiesDB { get; set; }
public void Dispose()
{
selectedBlocksInGroup.Dispose();
}
public Block[] GetBlocksFromGroup(EGID blockID, out float3 pos, out quaternion rot)
{
var blockPos = default(float3);
var blockRot = default(quaternion);
var parameters = new object[] {blockID, selectedBlocksInGroup, entitiesDB, blockPos, blockRot};
getBlocksFromGroup.Invoke(null, parameters);
pos = (float3) parameters[3];
rot = (quaternion) parameters[4];
int count = selectedBlocksInGroup.Count<EGID>();
var ret = new Block[count];
for (uint i = 0; i < count; i++)
ret[i] = new Block(selectedBlocksInGroup.Get<EGID>(i));
selectedBlocksInGroup.FastClear();
return ret;
}
public void RemoveBlockGroup(int id)
{
BlockGroupUtility.RemoveAllBlocksInBlockGroup(id, entitiesDB, removedConnections, nativeRemove,
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 AddBlockToGroup(EGID blockID, int groupID)
{
if (globalBlockMap == null)
globalBlockMap = FullGameFields._deserialisedBlockMap;
if (groupID != addingToBlockGroup)
{
Logging.MetaDebugLog("Changing current block group from " + addingToBlockGroup + " to " + groupID);
addingToBlockGroup = groupID;
globalBlockMap.Clear();
}
globalBlockMap.Add(blockID);
}
public void SelectBlueprint(uint resourceID)
{
if (resourceID == uint.MaxValue)
BlueprintUtil.UnselectBlueprint(entitiesDB);
else
BlueprintUtil.SelectBlueprint(entitiesDB, resourceID, false, -1);
}
public uint CreateBlueprint()
{
uint index = clipboardManager.AllocateSerializationData();
return index;
}
public void ReplaceBlueprint(uint playerID, uint blueprintID, ICollection<Block> selected, float3 pos, quaternion rot)
{
var blockIDs = new EGID[selected.Count];
using (var enumerator = selected.GetEnumerator())
{
for (var i = 0; enumerator.MoveNext(); i++)
{
var block = enumerator.Current;
blockIDs[i] = block.Id;
}
}
var serializationData = clipboardManager.GetSerializationData(blueprintID);
SelectionSerializationUtility.ClearClipboard(playerID, entitiesDB, entityFunctions, serializationData.blueprintData, -1);
if (selected.Count == 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;
clipboardManager.SetGhostSerialized(blueprintID, false);
SelectionSerializationUtility.CopySelectionToClipboard(playerID, entitiesDB,
serializationData.blueprintData, entitySerialization, entityFactory, blockIDs,
(uint) blockIDs.Length, pos, rot, -1);
BuildGhostBlueprint(selected, pos, rot, playerID);
SerializeGhostBlueprint.Invoke(SerializeGhostBlueprintInstance, new object[] {playerID, blueprintID});
}
private void BuildGhostBlueprint(ICollection<Block> blocks, float3 pos, quaternion rot, uint playerID)
{
GhostChildUtility.ClearGhostChildren(playerID, entitiesDB, entityFunctions);
foreach (var block in blocks)
{
GhostChildUtility.BuildGhostChild(in playerID, block.Id, in pos, in rot, entitiesDB,
BuildGhostBlueprintFactory, false);
}
}
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,
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 GetBlueprintInfo(uint blueprintID, out float3 pos, out quaternion rot, out uint selectionSize)
{
var serializationData = clipboardManager.GetSerializationData(blueprintID);
var blueprintData = serializationData.blueprintData;
blueprintData.dataPos = 0U;
BoxSelectSerializationUtilities.ReadClipboardHeader(blueprintData, out selectionSize, out var posst,
out var rotst, out _);
blueprintData.dataPos = 0U; //Just to be sure, it gets reset when it's read anyway
pos = posst.position;
rot = rotst.rotation;
}
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; } = false;
[HarmonyPatch]
private static class RemoveEnginePatch
{
public static void Prefix(IEntityFunctions entityFunctions,
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
{
nativeRemove = entityFunctions.ToNativeRemove<BlockEntityDescriptor>("GCAPI" + nameof(BlueprintEngine));
connectionFactory = machineGraphConnectionEntityFactory;
BlueprintEngine.entityFunctions = entityFunctions;
}
public static MethodBase TargetMethod()
{
return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine"))[0];
}
}
[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.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.SelectBlockEngine"))[0];
}
}
[HarmonyPatch]
private static class SerializeGhostBlueprintPatch
{
public static void Postfix(object __instance)
{
SerializeGhostBlueprintInstance = __instance;
}
public static MethodBase TargetMethod()
{
return AccessTools.GetDeclaredConstructors(SerializeGhostBlueprintType)[0];
}
}
[HarmonyPatch]
private static class BuildGhostBlueprintPatch
{
public static void Postfix(GhostChildEntityFactory ghostChildEntityFactory)
{
BuildGhostBlueprintFactory = ghostChildEntityFactory;
}
public static MethodBase TargetMethod()
{
return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.BuildGhostChildForMultiblockPickEngine"))[0];
}
}
public IEntityFactory Factory { get; set; }
}
}