Browse Source

Add support for setting and placing blueprints

tags/v1.7.0
NorbiPeti 3 years ago
parent
commit
1c4e2a0db2
3 changed files with 199 additions and 3 deletions
  1. +144
    -1
      GamecraftModdingAPI/Blocks/BlueprintEngine.cs
  2. +46
    -2
      GamecraftModdingAPI/Blueprint.cs
  3. +9
    -0
      GamecraftModdingAPI/Utility/FullGameFields.cs

+ 144
- 1
GamecraftModdingAPI/Blocks/BlueprintEngine.cs 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"));
}
}
}
}

+ 46
- 2
GamecraftModdingAPI/Blueprint.cs 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);
}
}
}

+ 9
- 0
GamecraftModdingAPI/Utility/FullGameFields.cs 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)


Loading…
Cancel
Save