Browse Source

Merge branch 'master' into customblocks

# Conflicts:
#	GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
tags/v1.8.0
NorbiPeti 3 years ago
parent
commit
56a64daa18
49 changed files with 1782 additions and 287 deletions
  1. +0
    -0
      Automation/gen_csproj.py
  2. +3
    -2
      GamecraftModdingAPI/App/AppEngine.cs
  3. +23
    -0
      GamecraftModdingAPI/App/CurrentGameMode.cs
  4. +12
    -0
      GamecraftModdingAPI/App/Game.cs
  5. +17
    -6
      GamecraftModdingAPI/App/GameGameEngine.cs
  6. +6
    -4
      GamecraftModdingAPI/App/GameMenuEngine.cs
  7. +113
    -35
      GamecraftModdingAPI/Block.cs
  8. +216
    -0
      GamecraftModdingAPI/BlockGroup.cs
  9. +108
    -0
      GamecraftModdingAPI/Blocks/BlockCloneEngine.cs
  10. +14
    -1
      GamecraftModdingAPI/Blocks/BlockColor.cs
  11. +91
    -39
      GamecraftModdingAPI/Blocks/BlockEngine.cs
  12. +2
    -2
      GamecraftModdingAPI/Blocks/BlockEngineInit.cs
  13. +6
    -5
      GamecraftModdingAPI/Blocks/BlockEventsEngine.cs
  14. +88
    -3
      GamecraftModdingAPI/Blocks/BlockIDs.cs
  15. +319
    -0
      GamecraftModdingAPI/Blocks/BlueprintEngine.cs
  16. +1
    -1
      GamecraftModdingAPI/Blocks/ConsoleBlock.cs
  17. +48
    -0
      GamecraftModdingAPI/Blocks/DampedSpring.cs
  18. +1
    -1
      GamecraftModdingAPI/Blocks/LogicGate.cs
  19. +1
    -1
      GamecraftModdingAPI/Blocks/Motor.cs
  20. +3
    -3
      GamecraftModdingAPI/Blocks/MovementEngine.cs
  21. +2
    -2
      GamecraftModdingAPI/Blocks/MusicBlock.cs
  22. +1
    -1
      GamecraftModdingAPI/Blocks/ObjectIdentifier.cs
  23. +1
    -1
      GamecraftModdingAPI/Blocks/Piston.cs
  24. +14
    -8
      GamecraftModdingAPI/Blocks/PlacementEngine.cs
  25. +4
    -1
      GamecraftModdingAPI/Blocks/RemovalEngine.cs
  26. +3
    -3
      GamecraftModdingAPI/Blocks/RotationEngine.cs
  27. +3
    -6
      GamecraftModdingAPI/Blocks/ScalingEngine.cs
  28. +1
    -1
      GamecraftModdingAPI/Blocks/Servo.cs
  29. +209
    -0
      GamecraftModdingAPI/Blocks/SfxBlock.cs
  30. +29
    -15
      GamecraftModdingAPI/Blocks/SignalEngine.cs
  31. +1
    -1
      GamecraftModdingAPI/Blocks/SpawnPoint.cs
  32. +3
    -1
      GamecraftModdingAPI/Blocks/TextBlock.cs
  33. +1
    -1
      GamecraftModdingAPI/Blocks/Timer.cs
  34. +102
    -0
      GamecraftModdingAPI/Blueprint.cs
  35. +33
    -0
      GamecraftModdingAPI/Cluster.cs
  36. +0
    -2
      GamecraftModdingAPI/Events/GameActivatedComposePatch.cs
  37. +182
    -109
      GamecraftModdingAPI/GamecraftModdingAPI.csproj
  38. +2
    -2
      GamecraftModdingAPI/Input/FakeInput.cs
  39. +4
    -4
      GamecraftModdingAPI/Inventory/HotbarEngine.cs
  40. +1
    -3
      GamecraftModdingAPI/Inventory/HotbarSlotSelectionHandlerEnginePatch.cs
  41. +25
    -7
      GamecraftModdingAPI/Main.cs
  42. +32
    -2
      GamecraftModdingAPI/Player.cs
  43. +10
    -0
      GamecraftModdingAPI/Players/PlayerBuildingMode.cs
  44. +4
    -4
      GamecraftModdingAPI/Players/PlayerEngine.cs
  45. +12
    -2
      GamecraftModdingAPI/SimBody.cs
  46. +19
    -5
      GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
  47. +1
    -1
      GamecraftModdingAPI/Tests/TestRoot.cs
  48. +10
    -1
      GamecraftModdingAPI/Utility/FullGameFields.cs
  49. +1
    -1
      doxygen.conf

+ 0
- 0
Automation/gen_csproj.py View File


+ 3
- 2
GamecraftModdingAPI/App/AppEngine.cs View File

@@ -46,11 +46,12 @@ namespace GamecraftModdingAPI.App
public Game[] GetMyGames()
{
EntityCollection<MyGameDataEntityStruct> mgsevs = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
var mgsevsB = mgsevs.ToBuffer().buffer;
Game[] games = new Game[mgsevs.count];
for (int i = 0; i < mgsevs.count; i++)
{
Utility.Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}");
games[i] = new Game(mgsevs[i].ID);
Utility.Logging.MetaDebugLog($"Found game named {mgsevsB[i].GameName}");
games[i] = new Game(mgsevsB[i].ID);
}
return games;
}


+ 23
- 0
GamecraftModdingAPI/App/CurrentGameMode.cs View File

@@ -0,0 +1,23 @@
namespace GamecraftModdingAPI.App
{
public enum CurrentGameMode
{
None,
/// <summary>
/// Building a game
/// </summary>
Build,
/// <summary>
/// Playing a game
/// </summary>
Play,
/// <summary>
/// Viewing a prefab
/// </summary>
View,
/// <summary>
/// Viewing a tutorial
/// </summary>
Tutorial
}
}

+ 12
- 0
GamecraftModdingAPI/App/Game.cs View File

@@ -335,6 +335,18 @@ namespace GamecraftModdingAPI.App
gameEngine.ToggleTimeMode();
}

/// <summary>
/// The mode of the game.
/// </summary>
public CurrentGameMode Mode
{
get
{
if (menuMode || !VerifyMode()) return CurrentGameMode.None;
return (CurrentGameMode) GameMode.CurrentMode;
}
}

/// <summary>
/// Load the game save.
/// This happens asynchronously, so when this method returns the game not loaded yet.


+ 17
- 6
GamecraftModdingAPI/App/GameGameEngine.cs View File

@@ -52,7 +52,7 @@ namespace GamecraftModdingAPI.App
{
if (async)
{
ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING);
ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_TimeRunningAndStopped);
}
else
{
@@ -102,16 +102,27 @@ namespace GamecraftModdingAPI.App
if (filter == BlockIDs.Invalid)
{
foreach (var (blocks, _) in allBlocks)
foreach (var block in blocks)
blockEGIDs.Add(block.ID);
{
var buffer = blocks.ToBuffer().buffer;
for (int i = 0; i < buffer.capacity; i++)
blockEGIDs.Add(buffer[i].ID);
}

return blockEGIDs.ToArray();
}
else
{
foreach (var (blocks, _) in allBlocks)
foreach (var block in blocks)
if (block.DBID == (ulong) filter)
blockEGIDs.Add(block.ID);
{
var array = blocks.ToBuffer().buffer;
for (var index = 0; index < array.capacity; index++)
{
var block = array[index];
if (block.DBID == (ulong) filter)
blockEGIDs.Add(block.ID);
}
}

return blockEGIDs.ToArray();
}
}


+ 6
- 4
GamecraftModdingAPI/App/GameMenuEngine.cs View File

@@ -61,12 +61,13 @@ namespace GamecraftModdingAPI.App
public uint HighestID()
{
EntityCollection<MyGameDataEntityStruct> games = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
var gamesB = games.ToBuffer().buffer;
uint max = 0;
for (int i = 0; i < games.count; i++)
{
if (games[i].ID.entityID > max)
if (gamesB[i].ID.entityID > max)
{
max = games[i].ID.entityID;
max = gamesB[i].ID.entityID;
}
}
return max;
@@ -118,11 +119,12 @@ namespace GamecraftModdingAPI.App
{
EntityCollection<MyGamesSlotEntityViewStruct> entities =
entitiesDB.QueryEntities<MyGamesSlotEntityViewStruct>(MyGamesScreenExclusiveGroups.GameSlotGuiEntities);
var entitiesB = entities.ToBuffer().buffer;
for (int i = 0; i < entities.count; i++)
{
if (entities[i].ID.entityID == id.entityID)
if (entitiesB[i].ID.entityID == id.entityID)
{
return ref entities[i];
return ref entitiesB[i];
}
}
MyGamesSlotEntityViewStruct[] defRef = new MyGamesSlotEntityViewStruct[1];


+ 113
- 35
GamecraftModdingAPI/Block.cs View File

@@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;

using Gamecraft.Blocks.BlockGroups;
using Svelto.ECS;
using Svelto.ECS.EntityStructs;
using RobocraftX.Common;
using RobocraftX.Blocks;
using Unity.Mathematics;
using Unity.Entities;
using Gamecraft.Blocks.GUI;

using GamecraftModdingAPI.Blocks;
@@ -29,6 +29,7 @@ namespace GamecraftModdingAPI
protected static readonly SignalEngine SignalEngine = new SignalEngine();
protected static readonly BlockEventsEngine BlockEventsEngine = new BlockEventsEngine();
protected static readonly ScalingEngine ScalingEngine = new ScalingEngine();
protected static readonly BlockCloneEngine BlockCloneEngine = new BlockCloneEngine();

protected internal static readonly BlockEngine BlockEngine = new BlockEngine();

@@ -36,16 +37,11 @@ namespace GamecraftModdingAPI
/// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position.
/// Place blocks next to each other to connect them.
/// The placed block will be a complete block with a placement grid and collision which will be saved along with the game.
/// <para></para>
/// <para>When placing multiple blocks, do not access properties immediately after creation as this
/// triggers a sync each time which can affect performance and may cause issues with the game.
/// You may either use AsyncUtils.WaitForSubmission() after placing all of the blocks
/// or simply access the block properties which will trigger the synchronization the first time a property is used.</para>
/// </summary>
/// <param name="block">The block's type</param>
/// <param name="color">The block's color</param>
/// <param name="darkness">The block color's darkness (0-9) - 0 is default color</param>
/// <param name="position">The block's position in the grid - default block size is 0.2</param>
/// <param name="position">The block's position - default block size is 0.2</param>
/// <param name="rotation">The block's rotation in degrees</param>
/// <param name="uscale">The block's uniform scale - default scale is 1 (with 0.2 width)</param>
/// <param name="scale">The block's non-uniform scale - 0 means <paramref name="uscale"/> is used</param>
@@ -66,7 +62,7 @@ namespace GamecraftModdingAPI
/// <param name="block">The block's type</param>
/// <param name="color">The block's color</param>
/// <param name="darkness">The block color's darkness (0-9) - 0 is default color</param>
/// <param name="position">The block's position in the grid - default block size is 0.2</param>
/// <param name="position">The block's position - default block size is 0.2</param>
/// <param name="rotation">The block's rotation in degrees</param>
/// <param name="uscale">The block's uniform scale - default scale is 1 (with 0.2 width)</param>
/// <param name="scale">The block's non-uniform scale - 0 means <paramref name="uscale"/> is used</param>
@@ -118,25 +114,35 @@ namespace GamecraftModdingAPI

private static Dictionary<Type, Func<EGID, Block>> initializers = new Dictionary<Type, Func<EGID, Block>>();

private static Dictionary<Type, ExclusiveGroupStruct[]> typeToGroup =
new Dictionary<Type, ExclusiveGroupStruct[]>
private static Dictionary<Type, ExclusiveBuildGroup[]> typeToGroup =
new Dictionary<Type, ExclusiveBuildGroup[]>
{
{typeof(ConsoleBlock), new[] {CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP}},
{typeof(LogicGate), new [] {CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP}},
{typeof(Motor), new[] {CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP}},
{typeof(MusicBlock), new[] {CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP}},
{typeof(Piston), new[] {CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP}},
{typeof(Servo), new[] {CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP}},
{typeof(ConsoleBlock), new[] {CommonExclusiveGroups.CONSOLE_BLOCK_GROUP}},
{typeof(LogicGate), new [] {CommonExclusiveGroups.LOGIC_BLOCK_GROUP}},
{typeof(Motor), new[] {CommonExclusiveGroups.MOTOR_BLOCK_GROUP}},
{typeof(MusicBlock), new[] {CommonExclusiveGroups.MUSIC_BLOCK_GROUP}},
{typeof(ObjectIdentifier), new[]{CommonExclusiveGroups.OBJID_BLOCK_GROUP}},
{typeof(Piston), new[] {CommonExclusiveGroups.PISTON_BLOCK_GROUP}},
{typeof(Servo), new[] {CommonExclusiveGroups.SERVO_BLOCK_GROUP}},
{
typeof(SpawnPoint),
new[]
{
CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP,
CommonExclusiveGroups.BUILD_BUILDINGSPAWN_BLOCK_GROUP
CommonExclusiveGroups.SPAWNPOINT_BLOCK_GROUP,
CommonExclusiveGroups.BUILDINGSPAWN_BLOCK_GROUP
}
},
{typeof(TextBlock), new[] {CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP}},
{typeof(Timer), new[] {CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP}}
{
typeof(SfxBlock),
new[]
{
CommonExclusiveGroups.SIMPLESFX_BLOCK_GROUP,
CommonExclusiveGroups.LOOPEDSFX_BLOCK_GROUP
}
},
{typeof(DampedSpring), new [] {CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP}},
{typeof(TextBlock), new[] {CommonExclusiveGroups.TEXT_BLOCK_GROUP}},
{typeof(Timer), new[] {CommonExclusiveGroups.TIMER_BLOCK_GROUP}}
};

/// <summary>
@@ -184,7 +190,7 @@ namespace GamecraftModdingAPI
type);
ILGenerator il = dynamic.GetILGenerator();

il.DeclareLocal(type);
//il.DeclareLocal(type);
il.Emit(OpCodes.Ldarg_0); //Load EGID and pass to constructor
il.Emit(OpCodes.Newobj, ctor); //Call constructor
//il.Emit(OpCodes.Stloc_0); - doesn't seem like we need these
@@ -224,6 +230,7 @@ namespace GamecraftModdingAPI
public EGID Id { get; }

internal BlockEngine.BlockInitData InitData;
private EGID copiedFrom;

/// <summary>
/// The block's current position or zero if the block no longer exists.
@@ -235,6 +242,9 @@ namespace GamecraftModdingAPI
set
{
MovementEngine.MoveBlock(Id, InitData, value);
if (blockGroup != null)
blockGroup.PosAndRotCalculated = false;
BlockEngine.UpdateDisplayedBlock(Id);
}
}

@@ -247,6 +257,9 @@ namespace GamecraftModdingAPI
set
{
RotationEngine.RotateBlock(Id, InitData, value);
if (blockGroup != null)
blockGroup.PosAndRotCalculated = false;
BlockEngine.UpdateDisplayedBlock(Id);
}
}

@@ -262,6 +275,7 @@ namespace GamecraftModdingAPI
BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value);
if (!Exists) return; //UpdateCollision needs the block to exist
ScalingEngine.UpdateCollision(Id);
BlockEngine.UpdateDisplayedBlock(Id);
}
}

@@ -307,9 +321,10 @@ namespace GamecraftModdingAPI
BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, BlockColor val) =>
{
color.indexInPalette = (byte) (val.Color + val.Darkness * 10);
color.overridePaletteColour = false;
color.needsUpdate = true;
BlockEngine.SetBlockColorFromPalette(ref color);
//color.overridePaletteColour = false;
//color.needsUpdate = true;
color.hasNetworkChange = true;
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette);
}, value);
}
}
@@ -319,14 +334,15 @@ namespace GamecraftModdingAPI
/// </summary>
public float4 CustomColor
{
get => BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.overriddenColour);
get => BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.paletteColour);
set
{
BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, float4 val) =>
{
color.overriddenColour = val;
color.overridePaletteColour = true;
color.needsUpdate = true;
color.paletteColour = val;
//color.overridePaletteColour = true;
//color.needsUpdate = true;
color.hasNetworkChange = true;
}, value);
}
}
@@ -347,6 +363,41 @@ namespace GamecraftModdingAPI
}
}

private BlockGroup blockGroup;
/// <summary>
/// Returns the block group this block is a part of. Block groups can also be placed using blueprints.
/// Returns null if not part of a group.<br />
/// Setting the group after the block has been initialized will not update everything properly,
/// 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>
public BlockGroup BlockGroup
{
get
{
if (blockGroup != null) return blockGroup;
return blockGroup = BlockEngine.GetBlockInfo(this,
(BlockGroupEntityComponent bgec) =>
bgec.currentBlockGroup == -1 ? null : new BlockGroup(bgec.currentBlockGroup, this));
}
set
{
if (Exists)
{
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);
BlockEngine.SetBlockInfo(this,
(ref BlockGroupEntityComponent bgec, BlockGroup val) => bgec.currentBlockGroup = val?.Id ?? -1,
value);
value?.AddInternal(this);
blockGroup = value;
}
}

/// <summary>
/// Whether the block exists. The other properties will return a default value if the block doesn't exist.
/// If the block was just placed, then this will also return false but the properties will work correctly.
@@ -368,11 +419,34 @@ namespace GamecraftModdingAPI
/// Returns the rigid body of the chunk of blocks this one belongs to during simulation.
/// Can be used to apply forces or move the block around while the simulation is running.
/// </summary>
/// <returns>The SimBody of the chunk or null if the block doesn't exist.</returns>
/// <returns>The SimBody of the chunk or null if the block doesn't exist or not in simulation mode.</returns>
public SimBody GetSimBody()
{
return BlockEngine.GetBlockInfo(this,
(GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId, st.clusterId));
(GridConnectionsEntityStruct st) => st.machineRigidBodyId != uint.MaxValue
? new SimBody(st.machineRigidBodyId, st.clusterId)
: null);
}

/// <summary>
/// Creates a copy of the block in the game with the same properties, stats and wires.
/// </summary>
/// <returns></returns>
public T Copy<T>() where T : Block
{
var block = PlaceNew<T>(Type, Position, Rotation, Color.Color, Color.Darkness, UniformScale, Scale);
block.copiedFrom = Id;
if (Type == BlockIDs.ConsoleBlock
&& (this is ConsoleBlock srcCB || (srcCB = Specialise<ConsoleBlock>()) != null)
&& (block is ConsoleBlock dstCB || (dstCB = block.Specialise<ConsoleBlock>()) != null))
{
//Console block properties are set by a separate engine in the game
dstCB.Arg1 = srcCB.Arg1;
dstCB.Arg2 = srcCB.Arg2;
dstCB.Arg3 = srcCB.Arg3;
dstCB.Command = srcCB.Command;
}
return block;
}

private void OnPlacedInit(object sender, BlockPlacedRemovedEventArgs e)
@@ -380,6 +454,8 @@ namespace GamecraftModdingAPI
if (e.ID != Id) return;
Placed -= OnPlacedInit; //And we can reference it
InitData = default; //Remove initializer as it's no longer valid - if the block gets removed it shouldn't be used again
if (copiedFrom != EGID.Empty)
BlockCloneEngine.CopyBlockStats(copiedFrom, Id);
}

public override string ToString()
@@ -422,6 +498,7 @@ namespace GamecraftModdingAPI
GameEngineManager.AddGameEngine(BlockEventsEngine);
GameEngineManager.AddGameEngine(ScalingEngine);
GameEngineManager.AddGameEngine(SignalEngine);
GameEngineManager.AddGameEngine(BlockCloneEngine);
Wire.signalEngine = SignalEngine; // requires same functionality, no need to duplicate the engine
}

@@ -439,7 +516,12 @@ namespace GamecraftModdingAPI
//Lets improve that using delegates
var block = New<T>(Id.entityID, Id.groupID);
block.InitData = this.InitData;
if (this.InitData.Group != null)
{
block.InitData = this.InitData;
Placed += block.OnPlacedInit; //Reset InitData of new object
}

return block;
}

@@ -452,9 +534,5 @@ namespace GamecraftModdingAPI
}
}
#endif
internal static void Setup(World physicsWorld)
{
ScalingEngine.Setup(physicsWorld.EntityManager);
}
}
}

+ 216
- 0
GamecraftModdingAPI/BlockGroup.cs View File

@@ -0,0 +1,216 @@
using System;
using System.Collections;
using System.Collections.Generic;

using Gamecraft.Blocks.BlockGroups;
using Unity.Mathematics;
using UnityEngine;

using GamecraftModdingAPI.Blocks;
using GamecraftModdingAPI.Utility;

namespace GamecraftModdingAPI
{
/// <summary>
/// A group of blocks that can be selected together. The placed version of blueprints. Dispose after usage.
/// </summary>
public class BlockGroup : ICollection<Block>, IDisposable
{
internal static BlueprintEngine _engine = new BlueprintEngine();
public int Id { get; }
private readonly Block sourceBlock;
private readonly List<Block> blocks;
private float3 position, rotation;
internal bool PosAndRotCalculated;

internal BlockGroup(int id, Block block)
{
if (id == BlockGroupUtility.GROUP_UNASSIGNED)
throw new BlockException("Cannot create a block group for blocks without a group!");
Id = id;
sourceBlock = block;
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>
/// The position of the block group (center). Can only be used after initialization is complete.
/// </summary>
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>
/// The rotation of the block group. Can only be used after initialization is complete.
/// </summary>
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 can 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)
{
var bg = new BlockGroup(_engine.CreateBlockGroup(block.Position, Quaternion.Euler(block.Rotation)), block);
block.BlockGroup = bg;
return bg;
}

/// <summary>
/// Collects each block that is a part of this group. Also sets the position and rotation.
/// </summary>
/// <returns>An array of blocks</returns>
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);
position = pos;
rotation = ((Quaternion) rot).eulerAngles;
PosAndRotCalculated = true;
return ret;
}

private void Refresh()
{
blocks.Clear();
blocks.AddRange(GetBlocks());
}

internal static void Init()
{
GameEngineManager.AddGameEngine(_engine);
}

public IEnumerator<Block> GetEnumerator() => blocks.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => blocks.GetEnumerator();

/// <summary>
/// Adds a block to the group. You can 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);
_engine.AddBlockToGroup(item.Id, Id);
}

/// <summary>
/// Removes all blocks from this group.
/// You cannot 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 cannot 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

public override string ToString()
{
return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Rotation)}: {Rotation}, {nameof(Count)}: {Count}";
}
}
}

+ 108
- 0
GamecraftModdingAPI/Blocks/BlockCloneEngine.cs View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Gamecraft.Wires;
using GamecraftModdingAPI.Engines;
using HarmonyLib;
using RobocraftX.Blocks;
using RobocraftX.Character;
using RobocraftX.Common;
using RobocraftX.Common.Players;
using Svelto.DataStructures;
using Svelto.ECS;

namespace GamecraftModdingAPI.Blocks
{
public class BlockCloneEngine : IApiEngine
{
private static Type copyEngineType =
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 copyToBlock = AccessTools.Method(copyEngineType, "ApplyTweaksToPlacedBlock");
private MethodBase copyWireFromBlock = AccessTools.Method(copyWireEngineType, "CopyWireInputsAndOutputs");
private MethodBase copyWireToBlock = AccessTools.Method(createWireEngineType, "PlaceWiresOnPlaceNewCube");

public void Ready()
{
}

public EntitiesDB entitiesDB { get; set; }

public void Dispose()
{
}

public void CopyBlockStats(EGID sourceID, EGID targetID)
{
var allCharacters = (LocalFasterReadOnlyList<ExclusiveGroupStruct>) CharacterExclusiveGroups.AllCharacters;
foreach (var ((pickedBlockColl, count), _) in entitiesDB.QueryEntities<PickedBlockExtraDataStruct>(allCharacters))
{
for (int i = 0; i < count; ++i)
{
ref PickedBlockExtraDataStruct pickedBlock = ref pickedBlockColl[i];
var oldStruct = pickedBlock;
pickedBlock.pickedBlockEntityID = sourceID;
pickedBlock.placedBlockEntityID = targetID;
pickedBlock.placedBlockTweaksCopied = false;
pickedBlock.placedBlockTweaksMustCopy = true;
if (entitiesDB.Exists<DBEntityStruct>(pickedBlock.pickedBlockEntityID)
&& entitiesDB.Exists<DBEntityStruct>(pickedBlock.placedBlockEntityID))
{
copyFromBlock.Invoke(Patch.copyEngine, 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.placedBlockTweaksCopied = false;
}

pickedBlock = oldStruct; //Make sure to not interfere with the game - Although that might not be the case with the wire copying
}
}
}

[HarmonyPatch]
private static class Patch
{
public static object copyEngine;
public static object copyWireEngine;
public static object createWireEngine;

public static void Postfix(object __instance)
{
if (__instance.GetType() == copyEngineType)
copyEngine = __instance;
else if (__instance.GetType() == copyWireEngineType)
copyWireEngine = __instance;
else if (__instance.GetType() == createWireEngineType)
createWireEngine = __instance;
}

public static IEnumerable<MethodBase> TargetMethods()
{
return new[]
{
AccessTools.GetDeclaredConstructors(copyEngineType)[0],
AccessTools.GetDeclaredConstructors(copyWireEngineType)[0],
AccessTools.GetDeclaredConstructors(createWireEngineType)[0]
};
}
}

public string Name { get; } = "GamecraftModdingAPIBlockCloneGameEngine";
public bool isRemovable { get; } = false;
}
}

+ 14
- 1
GamecraftModdingAPI/Blocks/BlockColor.cs View File

@@ -1,10 +1,17 @@
namespace GamecraftModdingAPI.Blocks
using System;
using Unity.Mathematics;

namespace GamecraftModdingAPI.Blocks
{
public struct BlockColor
{
public BlockColors Color;
public byte Darkness;

public byte Index => Color == BlockColors.Default
? byte.MaxValue
: (byte) (Darkness * 10 + Color);

public BlockColor(byte index)
{
if (index == byte.MaxValue)
@@ -14,6 +21,8 @@
}
else
{
if (index > 99)
throw new ArgumentOutOfRangeException(nameof(index), "Invalid color index. Must be 0-90 or 255.");
Color = (BlockColors) (index % 10);
Darkness = (byte) (index / 10);
}
@@ -21,10 +30,14 @@

public BlockColor(BlockColors color, byte darkness)
{
if (darkness > 9)
throw new ArgumentOutOfRangeException(nameof(darkness), "Darkness must be 0-9 where 0 is default.");
Color = color;
Darkness = darkness;
}

public float4 RGBA => Block.BlockEngine.ConvertBlockColor(Index);

public override string ToString()
{
return $"{nameof(Color)}: {Color}, {nameof(Darkness)}: {Darkness}";


+ 91
- 39
GamecraftModdingAPI/Blocks/BlockEngine.cs View File

@@ -2,15 +2,19 @@ using System;
using System.Collections.Generic;
using System.Linq;

using Gamecraft.ColourPalette;
using Gamecraft.TimeRunning;
using Gamecraft.Wires;
using RobocraftX.Blocks;
using RobocraftX.Common;
using RobocraftX.GUI.Hotbar.Colours;
using RobocraftX.Physics;
using RobocraftX.Scene.Simulation;
using RobocraftX.Rendering;
using Svelto.ECS.EntityStructs;

using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.Hybrid;
using Unity.Mathematics;

using GamecraftModdingAPI.Engines;

@@ -42,8 +46,14 @@ namespace GamecraftModdingAPI.Blocks
FasterList<EGID> cubes = new FasterList<EGID>(10);
var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
foreach (var (ecoll, _) in coll)
foreach (ref var conn in ecoll)
conn.isProcessed = false;
{
var ecollB = ecoll.ToBuffer();
for(int i = 0; i < ecoll.count; i++)
{
ref var conn = ref ecollB.buffer[i];
conn.isProcessed = false;
}
}

ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
(in GridConnectionsEntityStruct g) => { return false; });
@@ -54,12 +64,10 @@ namespace GamecraftModdingAPI.Blocks
return ret;
}

public void SetBlockColorFromPalette(ref ColourParameterEntityStruct color)
{
ref var paletteEntry = ref entitiesDB.QueryEntity<PaletteEntryEntityStruct>(color.indexInPalette,
CommonExclusiveGroups.COLOUR_PALETTE_GROUP);
color.paletteColour = paletteEntry.Colour;
}
public float4 ConvertBlockColor(byte index) => index == byte.MaxValue
? new float4(-1f, -1f, -1f, -1f)
: entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
CommonExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;

public ref T GetBlockInfo<T>(EGID blockID) where T : unmanaged, IEntityComponent
{
@@ -69,17 +77,17 @@ namespace GamecraftModdingAPI.Blocks
return ref structHolder[0]; //Gets a default value automatically
}
public ref T GetBlockInfoViewStruct<T>(EGID blockID) where T : struct, INeedEGID, IEntityComponent
public ref T GetBlockInfoViewStruct<T>(EGID blockID) where T : struct, INeedEGID, IEntityViewComponent
{
if (entitiesDB.Exists<T>(blockID))
{
// TODO: optimize by using EntitiesDB internal calls instead of iterating over everything
EntityCollection<T> entities = entitiesDB.QueryEntities<T>(blockID.groupID);
BT<MB<T>> entities = entitiesDB.QueryEntities<T>(blockID.groupID).ToBuffer();
for (int i = 0; i < entities.count; i++)
{
if (entities[i].ID == blockID)
if (entities.buffer[i].ID == blockID)
{
return ref entities[i];
return ref entities.buffer[i];
}
}
}
@@ -143,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)
{
return entitiesDB.Exists<DBEntityStruct>(blockID);
@@ -161,43 +178,55 @@ namespace GamecraftModdingAPI.Blocks
public SimBody[] GetSimBodiesFromID(byte id)
{
var ret = new FasterList<SimBody>(4);
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP))
return new SimBody[0];
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP);
var connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP);
foreach (ref ObjectIdEntityStruct oid in oids)
var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
EGIDMapper<GridConnectionsEntityStruct>? connections = null;
foreach (var ((oids, count), _) in oide)
{
if (oid.objectId != id) continue;
var rid = connections.Entity(oid.ID.entityID).machineRigidBodyId;
foreach (var rb in ret)
{
if (rb.Id.entityID == rid)
goto DUPLICATE; //Multiple Object Identifiers on one rigid body
for (int i = 0; i < count; i++)
{
ref ObjectIdEntityStruct oid = ref oids[i];
if (oid.objectId != id) continue;
if (!connections.HasValue) //Would need reflection to get the group from the build group otherwise
connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(oid.ID.groupID);
var rid = connections.Value.Entity(oid.ID.entityID).machineRigidBodyId;
foreach (var rb in ret)
{
if (rb.Id.entityID == rid)
goto DUPLICATE; //Multiple Object Identifiers on one rigid body
}

ret.Add(new SimBody(rid));
DUPLICATE: ;
}
ret.Add(new SimBody(rid));
DUPLICATE: ;
}

return ret.ToArray();
}

public ObjectIdentifier[] GetObjectIDsFromID(byte id, bool sim)
{
var ret = new FasterList<ObjectIdentifier>(4);
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP))
return new ObjectIdentifier[0];
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP);
foreach (ref ObjectIdEntityStruct oid in oids)
if (sim ? oid.simObjectId == id : oid.objectId == id)
ret.Add(new ObjectIdentifier(oid.ID));
var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
foreach (var ((oids, count), _) in oide)
{
for (int i = 0; i < count; i++)
{
ref ObjectIdEntityStruct oid = ref oids[i];
if (sim ? oid.simObjectId == id : oid.objectId == id)
ret.Add(new ObjectIdentifier(oid.ID));
}
}

return ret.ToArray();
}

public SimBody[] GetConnectedSimBodies(uint id)
{
var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP);
var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP).ToBuffer();
var list = new FasterList<SimBody>(4);
foreach (var joint in joints)
for (int i = 0; i < joints.count; i++)
{
ref var joint = ref joints.buffer[i];
if (joint.jointState == JointState.Broken) continue;
if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB));
else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));
@@ -212,14 +241,16 @@ namespace GamecraftModdingAPI.Blocks
var bodies = new HashSet<uint>();
foreach (var (coll, _) in groups)
{
foreach (var conn in coll)
var array = coll.ToBuffer().buffer;
for (var index = 0; index < array.capacity; index++)
{
var conn = array[index];
if (conn.clusterId == cid)
bodies.Add(conn.machineRigidBodyId);
}
}

return bodies.Select(id => new SimBody(id)).ToArray();
return bodies.Select(id => new SimBody(id, cid)).ToArray();
}

public EGID? FindBlockEGID(uint id)
@@ -239,9 +270,12 @@ namespace GamecraftModdingAPI.Blocks
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
foreach (var (coll, _) in groups)
{
foreach (var conn in coll)
var array = coll.ToBuffer().buffer;
for (var index = 0; index < array.capacity; index++)
{
if (conn.machineRigidBodyId == sbid)
var conn = array[index];
//Static blocks don't have a cluster ID but the cluster destruction manager should have one
if (conn.machineRigidBodyId == sbid && conn.clusterId != uint.MaxValue)
return new Cluster(conn.clusterId);
}
}
@@ -249,6 +283,24 @@ namespace GamecraftModdingAPI.Blocks
return null;
}

public Block[] GetBodyBlocks(uint sbid)
{
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
var set = new HashSet<Block>();
foreach (var (coll, _) in groups)
{
var array = coll.ToBuffer().buffer;
for (var index = 0; index < array.capacity; index++)
{
var conn = array[index];
if (conn.machineRigidBodyId == sbid)
set.Add(new Block(conn.ID));
}
}

return set.ToArray();
}

#if DEBUG
public EntitiesDB GetEntitiesDB()
{


+ 2
- 2
GamecraftModdingAPI/Blocks/BlockEngineInit.cs View File

@@ -14,10 +14,10 @@ namespace GamecraftModdingAPI.Blocks
/// </summary>
internal struct BlockInitData
{
public FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> Group;
public FasterDictionary<RefWrapperType, ITypeSafeDictionary> Group;
}

internal delegate FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> GetInitGroup(
internal delegate FasterDictionary<RefWrapperType, ITypeSafeDictionary> GetInitGroup(
EntityComponentInitializer initializer);

/// <summary>


+ 6
- 5
GamecraftModdingAPI/Blocks/BlockEventsEngine.cs View File

@@ -5,10 +5,11 @@ using Svelto.ECS;

using GamecraftModdingAPI.Engines;
using GamecraftModdingAPI.Utility;
using RobocraftX.Blocks;

namespace GamecraftModdingAPI.Blocks
{
public class BlockEventsEngine : IReactionaryEngine<DBEntityStruct>
public class BlockEventsEngine : IReactionaryEngine<BlockTagEntityStruct>
{
public event EventHandler<BlockPlacedRemovedEventArgs> Placed;
public event EventHandler<BlockPlacedRemovedEventArgs> Removed;
@@ -27,20 +28,20 @@ namespace GamecraftModdingAPI.Blocks
public bool isRemovable { get; } = false;

private bool shouldAddRemove;
public void Add(ref DBEntityStruct entityComponent, EGID egid)
public void Add(ref BlockTagEntityStruct entityComponent, EGID egid)
{
if (!(shouldAddRemove = !shouldAddRemove))
return;
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))
return;
ExceptionUtil.InvokeEvent(Removed, this,
new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID});
new BlockPlacedRemovedEventArgs {ID = egid});
}
}



+ 88
- 3
GamecraftModdingAPI/Blocks/BlockIDs.cs View File

@@ -228,7 +228,7 @@ namespace GamecraftModdingAPI.Blocks
ObjectiveHUD,
GameStatsHUD, //231
GameOverBlock,
SFXBlockGameplay=240,
SFXBlockGameplay = 240,
SFXBlock8Bit,
SFXBlockInstrument,
SFXBlockSciFi,
@@ -248,7 +248,92 @@ namespace GamecraftModdingAPI.Blocks
PlasmaCannonBlock,
QuantumRiflePickup = 300,
QuantumRifleAmmoPickup,
MagmaRockCube=777,
AluminiumSlicedFraction,
AluminiumSlicedSlope,
AluminiumHalfPyramidLeft = 305,
AluminiumHalfPyramidRight,
AluminiumPyramidSliced,
AluminiumTubeCross,
AluminiumTubeT,
AluminiumPlateSquare,
AluminiumPlateCircle,
AluminiumPlateTriangle, //312
OiledSlicedFraction = 314,
OiledSlicedSlope,
OiledHalfPyramidLeft,
OiledHalfPyramidRight,
OiledPyramidSliced,
GlassSlicedFraction,
GlassSlicedSlope,
GlassHalfPyramidLeft,
GlassHalfPyramidRight,
GlassPyramidSliced,
RubberSlicedFraction,
RubberSlicedSlope,
RubberHalfPyramidLeft,
RubberHalfPyramidRight,
RubberPyramidSliced,
WoodSlicedFraction,
WoodSlicedSlope, //330
WoodHalfPyramidLeft,
WoodHalfPyramidRight,
WoodPyramidSliced,
HexNetSlicedFraction,
HexNetSlicedSlope,
HexNetHalfPyramidLeft,
HexNetHalfPyramidRight,
HexNetPyramidSliced,
OiledTubeCross,
OiledTubeT, //340
GlassTubeCross,
GlassTubeT,
RubberTubeCross,
RubberTubeT,
WoodTubeCross,
WoodTubeT,
HexNetTubeCross,
HexNetTubeT,
BouncyCube,
BouncySlicedCube, //350
BouncySlope,
BouncyCorner,
OiledTubeCorner,
GlassTubeCorner,
RubberTubeCorner,
WoodTubeCorner,
Basketball,
BowlingBall,
SoccerBall,
GolfBall, //360
HockeyPuck,
PoolBall,
BouncyBall,
TennisBall,
UnlitCube,
IronSlicedFraction,
IronSlicedSlope,
IronHalfPyramidLeft,
IronHalfPyramidRight,
IronPyramidSliced, //370
IronTubeCross,
IronTubeT,
SFXBlockMob = 374,
PointLight,
SpotLight,
SunLight,
AmbientLight,
UnlitGlowCube = 381,
PointLightInvisible,
SpotLightInvisible,
UnlitSlope,
UnlitGlowSlope,
Fog,
Sky,
GridCube,
GridSlicedCube,
GridSlope,
GridCorner,
MagmaRockCube = 777,
MagmaRockCubeSliced,
MagmaRockSlope,
MagmaRockCorner,
@@ -267,7 +352,7 @@ namespace GamecraftModdingAPI.Blocks
HexNetSlopeRounded,
HexNetCornerRounded, //794
MagmaRockBulgedInner,
HexNetCylinder=797,
HexNetCylinder = 797,
HexNetHemisphere,
HexNetSphere,
HexNetTubeCorner //800


+ 319
- 0
GamecraftModdingAPI/Blocks/BlueprintEngine.cs View File

@@ -0,0 +1,319 @@
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; }
}
}

+ 1
- 1
GamecraftModdingAPI/Blocks/ConsoleBlock.cs View File

@@ -16,7 +16,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP))
public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.CONSOLE_BLOCK_GROUP))
{
}



+ 48
- 0
GamecraftModdingAPI/Blocks/DampedSpring.cs View File

@@ -0,0 +1,48 @@
using RobocraftX.Blocks;
using RobocraftX.Common;
using Svelto.ECS;

namespace GamecraftModdingAPI.Blocks
{
public class DampedSpring : Block
{
public DampedSpring(EGID id) : base(id)
{
}

public DampedSpring(uint id) : base(new EGID(id, CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP))
{
}

/// <summary>
/// The spring's maximum force. This is known as Stiffness in-game
/// </summary>
public float MaxForce
{
get => BlockEngine.GetBlockInfo(this, (DampedSpringReadOnlyStruct dsrs) => dsrs.maxForce);

set => BlockEngine.SetBlockInfo(this,
(ref DampedSpringReadOnlyStruct dsrs, float val) => dsrs.maxForce = val, value);
}

/// <summary>
/// Alias of MaxForce.
/// </summary>
public float Stiffness
{
get => MaxForce;
set => MaxForce = value;
}

/// <summary>
/// The spring's maximum damping force.
/// </summary>
public float Damping
{
get => BlockEngine.GetBlockInfo(this, (LinearJointForcesReadOnlyStruct ljf) => ljf.dampingForceMagnitude);

set => BlockEngine.SetBlockInfo(this,
(ref LinearJointForcesReadOnlyStruct ljf, float val) => ljf.dampingForceMagnitude = val, value);
}
}
}

+ 1
- 1
GamecraftModdingAPI/Blocks/LogicGate.cs View File

@@ -9,7 +9,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public LogicGate(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP))
public LogicGate(uint id) : base(new EGID(id, CommonExclusiveGroups.LOGIC_BLOCK_GROUP))
{
}
}

+ 1
- 1
GamecraftModdingAPI/Blocks/Motor.cs View File

@@ -15,7 +15,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public Motor(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP))
public Motor(uint id): base(new EGID(id, CommonExclusiveGroups.MOTOR_BLOCK_GROUP))
{
}



+ 3
- 3
GamecraftModdingAPI/Blocks/MovementEngine.cs View File

@@ -41,9 +41,9 @@ namespace GamecraftModdingAPI.Blocks
{
if (data.Group == null) return float3.zero;
var init = new EntityComponentInitializer(blockID, data.Group);
init.Init(new PositionEntityStruct {position = vector});
init.Init(new GridRotationStruct {position = vector});
init.Init(new LocalTransformEntityStruct {position = vector});
init.GetOrCreate<PositionEntityStruct>().position = vector;
init.GetOrCreate<GridRotationStruct>().position = vector;
init.GetOrCreate<LocalTransformEntityStruct>().position = vector;
return vector;
}
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID);


+ 2
- 2
GamecraftModdingAPI/Blocks/MusicBlock.cs View File

@@ -20,7 +20,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public MusicBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP))
public MusicBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.MUSIC_BLOCK_GROUP))
{
}

@@ -97,7 +97,7 @@ namespace GamecraftModdingAPI.Blocks
{
get
{
Assert.Log("Block exists: " + Exists);
//Assert.Log("Block exists: " + Exists);
return BlockEngine.GetBlockInfo(this,
(MusicBlockDataEntityStruct msdes) => (ChannelType) msdes.channelType);
}


+ 1
- 1
GamecraftModdingAPI/Blocks/ObjectIdentifier.cs View File

@@ -10,7 +10,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public ObjectIdentifier(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP))
public ObjectIdentifier(uint id) : base(new EGID(id, CommonExclusiveGroups.OBJID_BLOCK_GROUP))
{
}



+ 1
- 1
GamecraftModdingAPI/Blocks/Piston.cs View File

@@ -15,7 +15,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public Piston(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP))
public Piston(uint id) : base(new EGID(id, CommonExclusiveGroups.PISTON_BLOCK_GROUP))
{
}



+ 14
- 8
GamecraftModdingAPI/Blocks/PlacementEngine.cs View File

@@ -16,6 +16,7 @@ using UnityEngine;
using GamecraftModdingAPI.Utility;
using GamecraftModdingAPI.Engines;
using GamecraftModdingAPI.Players;
using RobocraftX.Rendering.GPUI;

namespace GamecraftModdingAPI.Blocks
{
@@ -52,15 +53,15 @@ namespace GamecraftModdingAPI.Blocks
private EntityComponentInitializer BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId)
{
if (_blockEntityFactory == null)
throw new Exception("The factory is null.");
throw new BlockException("The factory is null.");
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.y < 4e-5) scale.y = uscale;
if (scale.z < 4e-5) scale.z = uscale;
uint dbid = block;
if (!PrefabsID.DBIDMAP.ContainsKey(dbid))
throw new Exception("Block with ID " + dbid + " not found!");
if (!PrefabsID.HasPrefabRegistered(dbid, 0))
throw new BlockException("Block with ID " + dbid + " not found!");
//RobocraftX.CR.MachineEditing.PlaceBlockEngine
ScalingEntityStruct scaling = new ScalingEntityStruct {scale = scale};
Quaternion rotQ = Quaternion.Euler(rot);
@@ -70,9 +71,7 @@ namespace GamecraftModdingAPI.Blocks
DBEntityStruct dbEntity = new DBEntityStruct {DBID = dbid};
BlockPlacementScaleEntityStruct placementScale = new BlockPlacementScaleEntityStruct
{
blockPlacementHeight = uscale, blockPlacementWidth = uscale, desiredScaleFactor = uscale,
snapGridScale = uscale,
unitSnapOffset = 0, isUsingUnitSize = true
blockPlacementHeight = uscale, blockPlacementWidth = uscale, desiredScaleFactor = uscale
};
EquippedColourStruct colour = new EquippedColourStruct {indexInPalette = color};

@@ -83,7 +82,7 @@ namespace GamecraftModdingAPI.Blocks
structInitializer.Init(new ColourParameterEntityStruct
{
indexInPalette = colour.indexInPalette,
needsUpdate = true
hasNetworkChange = true
});
uint prefabId = PrefabsID.GetPrefabId(dbid, 0);
structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
@@ -102,6 +101,13 @@ namespace GamecraftModdingAPI.Blocks
loadedFromDisk = false,
placedBy = playerId
});
/*structInitializer.Init(new CollisionFilterOverride
{
belongsTo = 32U,
collidesWith = 239532U
});*/

PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer);
EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup);
ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID);


+ 4
- 1
GamecraftModdingAPI/Blocks/RemovalEngine.cs View File

@@ -20,8 +20,11 @@ namespace GamecraftModdingAPI.Blocks
if (!entitiesDB.Exists<MachineGraphConnectionsEntityStruct>(target))
return false;
var connections = entitiesDB.QueryEntity<MachineGraphConnectionsEntityStruct>(target);
var groups = entitiesDB.FindGroups<MachineGraphConnectionsEntityStruct>();
var connStructMapper =
entitiesDB.QueryNativeMappedEntities<MachineGraphConnectionsEntityStruct>(groups);
for (int i = connections.connections.Count<MachineConnectionStruct>() - 1; i >= 0; i--)
_connectionFactory.RemoveConnection(connections, i, entitiesDB);
_connectionFactory.RemoveConnection(connections, i, connStructMapper);
_entityFunctions.RemoveEntity<BlockEntityDescriptor>(target);
return true;
}


+ 3
- 3
GamecraftModdingAPI/Blocks/RotationEngine.cs View File

@@ -41,9 +41,9 @@ namespace GamecraftModdingAPI.Blocks
{
if (data.Group == null) return float3.zero;
var init = new EntityComponentInitializer(blockID, data.Group);
init.Init(new RotationEntityStruct {rotation = new Quaternion {eulerAngles = vector}});
init.Init(new GridRotationStruct {rotation = new Quaternion {eulerAngles = vector}});
init.Init(new LocalTransformEntityStruct {rotation = new Quaternion {eulerAngles = vector}});
init.GetOrCreate<RotationEntityStruct>().rotation = Quaternion.Euler(vector);
init.GetOrCreate<GridRotationStruct>().rotation = Quaternion.Euler(vector);
init.GetOrCreate<LocalTransformEntityStruct>().rotation = Quaternion.Euler(vector);
return vector;
}
ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntity<RotationEntityStruct>(blockID);


+ 3
- 6
GamecraftModdingAPI/Blocks/ScalingEngine.cs View File

@@ -27,10 +27,12 @@ namespace GamecraftModdingAPI.Blocks
public string Name { get; } = "GamecraftModdingAPIScalingEngine";
public bool isRemovable { get; } = false;
private static EntityManager _entityManager; //Unity entity manager
private EntityManager _entityManager; //Unity entity manager

public void UpdateCollision(EGID egid)
{
if (_entityManager == default)
_entityManager = FullGameFields._physicsWorld.EntityManager;
//Assuming the block exists
var entity = entitiesDB.QueryEntity<UECSPhysicsEntityStruct>(egid).uecsEntity;
var pes = new UECSPhysicsEntityCreationStruct();
@@ -38,11 +40,6 @@ namespace GamecraftModdingAPI.Blocks
_entityManager.DestroyEntity(entity);
}

internal void Setup(EntityManager entityManager)
{
_entityManager = entityManager;
}

[HarmonyPatch]
public class PhysicsEnginePatch
{


+ 1
- 1
GamecraftModdingAPI/Blocks/Servo.cs View File

@@ -15,7 +15,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public Servo(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP))
public Servo(uint id) : base(new EGID(id, CommonExclusiveGroups.SERVO_BLOCK_GROUP))
{
}



+ 209
- 0
GamecraftModdingAPI/Blocks/SfxBlock.cs View File

@@ -0,0 +1,209 @@
using System;
using FMOD.Studio;
using FMODUnity;
using Gamecraft.Wires;
using RobocraftX.Blocks;
using RobocraftX.Common;
using Svelto.ECS;

namespace GamecraftModdingAPI.Blocks
{
public class SfxBlock : SignalingBlock
{
public SfxBlock(EGID id) : base(id)
{
}

public SfxBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.SIMPLESFX_BLOCK_GROUP /* This could also be BUILD_LOOPEDSFX_BLOCK_GROUP */))
{
}

public float Volume
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => obj.tweakableVolume);
}

set
{
BlockEngine.SetBlockInfo(this,
(ref SoundSfxBlockDataEntityStruct obj, float val) => obj.tweakableVolume = val, value);
}
}
public float Pitch
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => obj.tweakablePitch);
}

set
{
BlockEngine.SetBlockInfo(this,
(ref SoundSfxBlockDataEntityStruct obj, float val) => obj.tweakablePitch = val, value);
}
}
public bool Is3D
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => obj.is3D);
}
set
{
BlockEngine.SetBlockInfo(this,
(ref SoundSfxBlockDataEntityStruct obj, bool val) => obj.is3D = val, value);
}
}
public ChannelType ChannelType
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => (ChannelType)obj.channelType);
}

set
{
BlockEngine.SetBlockInfo(this,
(ref SoundSfxBlockDataEntityStruct obj, ChannelType val) => obj.tweakableVolume = (byte) val, value);
}
}
public byte TrackIndex
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => obj.soundEffectIndex);
}
set
{
BlockEngine.SetBlockInfo(this,
(ref SoundSfxBlockDataEntityStruct obj, byte val) => obj.soundEffectIndex = val, value);
}
}
// track
public Guid Track
{
get
{
return BlockEngine.GetBlockInfo(this,
(SoundSfxBlockDataEntityStruct obj) => obj.is3D ? obj.fmod3DEventPaths.Get<Guid>(obj.soundEffectIndex) : obj.fmod2DEventPaths.Get<Guid>(obj.soundEffectIndex));
}

set
{
BlockEngine.SetBlockInfo(this, (ref SoundSfxBlockDataEntityStruct obj, Guid val) =>
{
for (byte i = 0; i < obj.fmod2DEventPaths.Count<Guid>(); i++)
{
Guid track = obj.fmod2DEventPaths.Get<Guid>(i);
if (track == val)
{
obj.soundEffectIndex = i;
obj.is3D = false;
return;
}
}
for (byte i = 0; i < obj.fmod3DEventPaths.Count<Guid>(); i++)
{
Guid track = obj.fmod3DEventPaths.Get<Guid>(i);
if (track == val)
{
obj.soundEffectIndex = i;
obj.is3D = true;
return;
}
}
}, value);
}
}
// all tracks
public Guid[] Tracks2D
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) =>
{
Guid[] tracks = new Guid[obj.fmod2DEventPaths.Count<Guid>()];
for (byte i = 0; i < tracks.Length; i++)
{
tracks[i] = obj.fmod2DEventPaths.Get<Guid>(i);
}
return tracks;
});
}
}
public Guid[] Tracks3D
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) =>
{
Guid[] tracks = new Guid[obj.fmod3DEventPaths.Count<Guid>()];
for (byte i = 0; i < tracks.Length; i++)
{
tracks[i] = obj.fmod2DEventPaths.Get<Guid>(i);
}
return tracks;
});
}
}

public bool IsLooped
{
get
{
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => obj.isLoopedBlock);
}
set
{
BlockEngine.SetBlockInfo(this,
(ref SoundSfxBlockDataEntityStruct obj, bool val) => obj.isLoopedBlock = val, value);
}
}
public bool IsPlaying
{
get
{
return BlockEngine.GetBlockInfo(this,
(SoundSfxBlockDataEntityStruct obj) => obj.isPlaying);
}

set
{
BlockEngine.SetBlockInfo(this, (ref SoundSfxBlockDataEntityStruct obj, bool val) =>
{
if (obj.isPlaying == val) return;
if (val)
{
// start playing
EventInstance inst = RuntimeManager.CreateInstance(obj.is3D ? obj.fmod3DEventPaths.Get<Guid>(obj.soundEffectIndex) : obj.fmod2DEventPaths.Get<Guid>(obj.soundEffectIndex));
inst.setVolume(obj.tweakableVolume / 100f);
inst.start();
obj.eventHandle = inst.handle;
}
else
{
// stop playing
EventInstance inst = default(EventInstance);
inst.handle = obj.eventHandle;
inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
inst.release();
}
obj.isPlaying = val;
}, value);
}
}
}
}

+ 29
- 15
GamecraftModdingAPI/Blocks/SignalEngine.cs View File

@@ -115,7 +115,8 @@ namespace GamecraftModdingAPI.Blocks
public bool SetSignal(uint signalID, float signal, bool input = true)
{
var array = GetSignalStruct(signalID, out uint index, input);
if (array.count > 0) array[index].valueAsFloat = signal;
var arrayB = array.ToBuffer();
if (array.count > 0) arrayB.buffer[index].valueAsFloat = signal;
return false;
}

@@ -128,9 +129,10 @@ namespace GamecraftModdingAPI.Blocks
public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = true)
{
var array = GetSignalStruct(signalID, out uint index, input);
var arrayB = array.ToBuffer();
if (array.count > 0)
{
ref var channelData = ref array[index];
ref var channelData = ref arrayB.buffer[index];
channelData.valueAsFloat += signal;
if (clamp)
{
@@ -159,7 +161,8 @@ namespace GamecraftModdingAPI.Blocks
public float GetSignal(uint signalID, bool input = true)
{
var array = GetSignalStruct(signalID, out uint index, input);
return array.count > 0 ? array[index].valueAsFloat : 0f;
var arrayB = array.ToBuffer();
return array.count > 0 ? arrayB.buffer[index].valueAsFloat : 0f;
}

public uint[] GetSignalIDs(EGID blockID, bool input = true)
@@ -244,13 +247,14 @@ namespace GamecraftModdingAPI.Blocks
{
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
var wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group);
var wiresB = wires.ToBuffer().buffer;
for (uint i = 0; i < wires.count; i++)
{
if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID)
|| (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID))
if ((wiresB[i].destinationPortUsage == port.usage && wiresB[i].destinationBlockEGID == blockID)
|| (wiresB[i].sourcePortUsage == port.usage && wiresB[i].sourceBlockEGID == blockID))
{
exists = true;
return ref wires[i];
return ref wiresB[i];
}
}
exists = false;
@@ -286,6 +290,7 @@ namespace GamecraftModdingAPI.Blocks
}
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group);
var wiresB = wires.ToBuffer().buffer;
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
{
PortEntityStruct endPES = entitiesDB.QueryEntity<PortEntityStruct>(endPorts[endIndex]);
@@ -294,11 +299,11 @@ namespace GamecraftModdingAPI.Blocks
PortEntityStruct startPES = entitiesDB.QueryEntity<PortEntityStruct>(startPorts[startIndex]);
for (int w = 0; w < wires.count; w++)
{
if ((wires[w].destinationPortUsage == endPES.usage && wires[w].destinationBlockEGID == endBlock)
&& (wires[w].sourcePortUsage == startPES.usage && wires[w].sourceBlockEGID == startBlock))
if ((wiresB[w].destinationPortUsage == endPES.usage && wiresB[w].destinationBlockEGID == endBlock)
&& (wiresB[w].sourcePortUsage == startPES.usage && wiresB[w].sourceBlockEGID == startBlock))
{
exists = true;
return ref wires[w];
return ref wiresB[w];
}
}
}
@@ -313,10 +318,11 @@ namespace GamecraftModdingAPI.Blocks
{
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group);
var channelsB = channels.ToBuffer();
if (port.firstChannelIndexCachedInSim < channels.count)
{
exists = true;
return ref channels[port.firstChannelIndexCachedInSim];
return ref channelsB.buffer[port.firstChannelIndexCachedInSim];
}
exists = false;
ChannelDataStruct[] defRef = new ChannelDataStruct[1];
@@ -327,8 +333,15 @@ namespace GamecraftModdingAPI.Blocks
{
var res = new FasterList<EGID>();
foreach (var (coll, _) in entitiesDB.QueryEntities<BlockPortsStruct>())
foreach (ref BlockPortsStruct s in coll)
res.Add(s.ID);
{
var collB = coll.ToBuffer();
for (int i = 0; i < coll.count; i++)
{
ref BlockPortsStruct s = ref collB.buffer[i];
res.Add(s.ID);
}
}

return res.ToArray();
}

@@ -358,15 +371,16 @@ namespace GamecraftModdingAPI.Blocks
return result;
}

private T[] Search<T>(ExclusiveGroup group, Func<T, bool> isMatch) where T : struct, IEntityComponent
private T[] Search<T>(ExclusiveGroup group, Func<T, bool> isMatch) where T : unmanaged, IEntityComponent
{
FasterList<T> results = new FasterList<T>();
EntityCollection<T> components = entitiesDB.QueryEntities<T>(group);
var componentsB = components.ToBuffer();
for (uint i = 0; i < components.count; i++)
{
if (isMatch(components[i]))
if (isMatch(componentsB.buffer[i]))
{
results.Add(components[i]);
results.Add(componentsB.buffer[i]);
}
}
return results.ToArray();


+ 1
- 1
GamecraftModdingAPI/Blocks/SpawnPoint.cs View File

@@ -17,7 +17,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public SpawnPoint(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP))
public SpawnPoint(uint id) : base(new EGID(id, CommonExclusiveGroups.SPAWNPOINT_BLOCK_GROUP))
{
}



+ 3
- 1
GamecraftModdingAPI/Blocks/TextBlock.cs View File

@@ -16,7 +16,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public TextBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP))
public TextBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.TEXT_BLOCK_GROUP))
{
}

@@ -31,6 +31,7 @@ namespace GamecraftModdingAPI.Blocks

set
{
if (value == null) value = "";
BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) =>
{
tbds.textCurrent.Set(val);
@@ -50,6 +51,7 @@ namespace GamecraftModdingAPI.Blocks

set
{
if (value == null) value = "";
BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) =>
tbds.textBlockID.Set(val), value);
BlockEngine.SetBlockInfo(this,


+ 1
- 1
GamecraftModdingAPI/Blocks/Timer.cs View File

@@ -17,7 +17,7 @@ namespace GamecraftModdingAPI.Blocks
{
}

public Timer(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP))
public Timer(uint id) : base(new EGID(id, CommonExclusiveGroups.TIMER_BLOCK_GROUP))
{
}



+ 102
- 0
GamecraftModdingAPI/Blueprint.cs View File

@@ -0,0 +1,102 @@
using System;
using Unity.Mathematics;
using UnityEngine;

namespace GamecraftModdingAPI
{
/// <summary>
/// Represents a blueprint in the inventory. When placed it becomes a block group.
/// </summary>
public class Blueprint : IDisposable
{
public uint Id { get; }

internal Blueprint(uint id)
{
Id = id;
BlockGroup._engine.InitBlueprint(id);
Refresh();
}

/// <summary>
/// The center of the blueprint. Can only be set using the StoreBlocks() method.
/// </summary>
public float3 Position { get; private set; }

/// <summary>
/// The rotation of the blueprint. Can only be set using the StoreBlocks() method.
/// </summary>
public float3 Rotation { get; private set; }

/// <summary>
/// The amount of blocks in the blueprint. Gan only be set using the StoreBlocks() method.
/// </summary>
public uint BlockCount { get; private set; }

/// <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.
/// Use the BlockGroup overload for automatically calculated position and rotation.
/// </summary>
/// <param name="blocks">The array of blocks to use</param>
/// <param name="position">The anchor (center) position of the blueprint</param>
/// <param name="rotation">The base rotation of the blueprint</param>
public void StoreBlocks(Block[] blocks, float3 position, float3 rotation)
{
BlockGroup._engine.ReplaceBlueprint(Player.LocalPlayer.Id, Id, blocks, position,
quaternion.Euler(rotation));
Refresh();
}

/// <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));
Refresh();
}

/// <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);
}

/// <summary>
/// Updates the properties based on the blueprint data. Only necessary if the blueprint is changed from the game.
/// </summary>
public void Refresh()
{
BlockGroup._engine.GetBlueprintInfo(Id, out var pos, out var rot, out uint count);
Position = pos;
Rotation = ((Quaternion) rot).eulerAngles;
BlockCount = count;
}

public void Dispose()
{
BlockGroup._engine.DisposeBlueprint(Id);
}

public override string ToString()
{
return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Rotation)}: {Rotation}, {nameof(BlockCount)}: {BlockCount}";
}
}
}

+ 33
- 0
GamecraftModdingAPI/Cluster.cs View File

@@ -6,6 +6,7 @@ namespace GamecraftModdingAPI
{
/// <summary>
/// Represnts a cluster of blocks in time running mode, meaning blocks that are connected either directly or via joints.
/// Only exists if a cluster destruction manager is present. Static blocks like grass and dirt aren't part of a cluster.
/// </summary>
public class Cluster
{
@@ -37,5 +38,37 @@ namespace GamecraftModdingAPI
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier;
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value;
}

/// <summary>
/// Returns the simulation-time rigid bodies for the chunks in this cluster.
/// </summary>
/// <returns>An array of sim-bodies</returns>
public SimBody[] GetSimBodies()
{
return Block.BlockEngine.GetClusterBodies(Id.entityID);
}

public override string ToString()
{
return $"{nameof(Id)}: {Id}";
}

protected bool Equals(Cluster other)
{
return Id.Equals(other.Id);
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Cluster) obj);
}

public override int GetHashCode()
{
return Id.GetHashCode();
}
}
}

+ 0
- 2
GamecraftModdingAPI/Events/GameActivatedComposePatch.cs View File

@@ -31,8 +31,6 @@ namespace GamecraftModdingAPI.Events
GameEngineManager.RegisterEngines(enginesRoot);
// initialize AsyncUtils
AsyncUtils.Setup(enginesRoot);
// initialize Block
Block.Setup(physicsWorld);
// A new EnginesRoot is always created when ActivateGame is called
// so all event emitters and handlers must be re-registered.
EventManager.RegisterEngines(enginesRoot);


+ 182
- 109
GamecraftModdingAPI/GamecraftModdingAPI.csproj View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Version>1.5.0</Version>
<Version>1.7.0</Version>
<Authors>Exmods</Authors>
<PackageLicenseExpression>GNU General Public Licence 3+</PackageLicenseExpression>
<PackageProjectUrl>https://git.exmods.org/modtainers/GamecraftModdingAPI</PackageProjectUrl>
@@ -17,21 +17,18 @@
<DefineConstants>DEBUG;TEST;TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Lib.Harmony" Version="2.0.0.10" />
<PackageReference Include="Lib.Harmony" Version="2.0.4" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

<!--Start Dependencies-->
<ItemGroup>
<Reference Include="IllusionInjector">
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionInjector.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\IllusionInjector.dll</HintPath>
</Reference>
<Reference Include="IllusionPlugin">
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath>
<Reference Include="Accessibility">
<HintPath>..\ref\Gamecraft_Data\Managed\Accessibility.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Accessibility.dll</HintPath>
</Reference>
<Reference Include="Analytics">
<HintPath>..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath>
@@ -77,6 +74,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath>
</Reference>
<Reference Include="Facepunch.Steamworks.Win64">
<HintPath>..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath>
</Reference>
<Reference Include="FMOD">
<HintPath>..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath>
@@ -89,14 +90,14 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.BlockCompositionRoot">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.BlockCompositionRoot.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlockCompositionRoot.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.BlockEntityFactory">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.BlockEntityFactory.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlockEntityFactory.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.BlockGroups">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.BlockGroups.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlockGroups.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.Blocks.ConsoleBlock">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath>
@@ -145,6 +146,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.ColourPalette">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.ColourPalette.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.ColourPalette.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.Damage">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Damage.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Damage.dll</HintPath>
@@ -161,18 +166,74 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GraphicsSettings.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GraphicsSettings.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.BlueprintInventory">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.BlueprintInventory.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.BlueprintInventory.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.BlueprintInventoryMock">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.BlueprintInventoryMock.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.BlueprintInventoryMock.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.Blueprints">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Blueprints.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Blueprints.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.BlueprintSets">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.BlueprintSets.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.BlueprintSets.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.ConsoleBlock">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.GameOptionsScreen">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GameOptionsScreen.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GameOptionsScreen.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.GraphicsScreen">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.Hotbar.Blocks">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Hotbar.Blocks.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Hotbar.Blocks.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.Hotbar.Colours">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Hotbar.Colours.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Hotbar.Colours.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.HUDFeedbackBlocks">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.ModeBar">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ModeBar.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ModeBar.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.OptionsScreen">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.OptionsScreen.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.OptionsScreen.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.TabsBar.Blocks">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Blocks.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Blocks.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.TabsBar.Blueprints">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Blueprints.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Blueprints.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.TabsBar.Colours">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Colours.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Colours.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.TabsBar.Common">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Common.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TabsBar.Common.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.TimeModeClock">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TimeModeClock.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.TimeModeClock.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUI.Tweaks">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath>
@@ -189,6 +250,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.GUIs.Hotbar.BlueprintsHotbar">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUIs.Hotbar.BlueprintsHotbar.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUIs.Hotbar.BlueprintsHotbar.dll</HintPath>
</Reference>
<Reference Include="Gamecraft.InventoryTimeRunning">
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.InventoryTimeRunning.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.InventoryTimeRunning.dll</HintPath>
@@ -249,6 +314,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath>
</Reference>
<Reference Include="GhostShark.Outline">
<HintPath>..\ref\Gamecraft_Data\Managed\GhostShark.Outline.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\GhostShark.Outline.dll</HintPath>
</Reference>
<Reference Include="GPUInstancer">
<HintPath>..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath>
@@ -261,10 +330,26 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Havok.Physics.Hybrid.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Havok.Physics.Hybrid.dll</HintPath>
</Reference>
<Reference Include="IllusionInjector">
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionInjector.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\IllusionInjector.dll</HintPath>
</Reference>
<Reference Include="IllusionPlugin">
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath>
</Reference>
<Reference Include="JWT">
<HintPath>..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath>
</Reference>
<Reference Include="LZ4">
<HintPath>..\ref\Gamecraft_Data\Managed\LZ4.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\LZ4.dll</HintPath>
</Reference>
<Reference Include="mscorlib">
<HintPath>..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath>
</Reference>
<Reference Include="MultiplayerNetworking">
<HintPath>..\ref\Gamecraft_Data\Managed\MultiplayerNetworking.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\MultiplayerNetworking.dll</HintPath>
@@ -273,10 +358,30 @@
<HintPath>..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll</HintPath>
</Reference>
<Reference Include="netstandard">
<HintPath>..\ref\Gamecraft_Data\Managed\netstandard.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\netstandard.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Novell.Directory.Ldap">
<HintPath>..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll</HintPath>
</Reference>
<Reference Include="RCX.ScreenshotTaker">
<HintPath>..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll</HintPath>
</Reference>
<Reference Include="Rewired_Core">
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath>
</Reference>
<Reference Include="Rewired_Windows">
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath>
</Reference>
<Reference Include="RobocraftECS">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftECS.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftECS.dll</HintPath>
@@ -341,6 +446,22 @@
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.GUI.Hotbar">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Hotbar.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Hotbar.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.GUI.Inventory.BlocksInventory">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Inventory.BlocksInventory.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Inventory.BlocksInventory.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.GUI.Inventory.ColourInventory">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Inventory.ColourInventory.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Inventory.ColourInventory.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.GUI.Inventory">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Inventory.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.Inventory.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.GUI.RemoveBlock">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.RemoveBlock.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.RemoveBlock.dll</HintPath>
@@ -349,6 +470,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.ScaleGhost.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.ScaleGhost.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.GUI.TabsBar">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.TabsBar.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.TabsBar.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.GUIs.WorkshopPrefabs">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUIs.WorkshopPrefabs.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUIs.WorkshopPrefabs.dll</HintPath>
@@ -377,6 +502,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.Multiplayer.GUI">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.GUI.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.GUI.dll</HintPath>
</Reference>
<Reference Include="RobocraftX.Multiplayer.NetworkEntityStream">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.NetworkEntityStream.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.NetworkEntityStream.dll</HintPath>
@@ -449,9 +578,9 @@
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX_TextBlock.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX_TextBlock.dll</HintPath>
</Reference>
<Reference Include="RobocratX.SimulationCompositionRoot">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll</HintPath>
<Reference Include="RobocratX.SimulationMockCompositionRoot">
<HintPath>..\ref\Gamecraft_Data\Managed\RobocratX.SimulationMockCompositionRoot.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationMockCompositionRoot.dll</HintPath>
</Reference>
<Reference Include="SpawningPointCompositionRoot">
<HintPath>..\ref\Gamecraft_Data\Managed\SpawningPointCompositionRoot.dll</HintPath>
@@ -465,9 +594,9 @@
<HintPath>..\ref\Gamecraft_Data\Managed\StringFormatter.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\StringFormatter.dll</HintPath>
</Reference>
<Reference Include="Svelto.Common_3">
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll</HintPath>
<Reference Include="Svelto.Common">
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Common.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.Common.dll</HintPath>
</Reference>
<Reference Include="Svelto.ECS">
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll</HintPath>
@@ -489,34 +618,6 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.Curves">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.Curves.Hybrid">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.Hybrid.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.Hybrid.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.DefaultGraphPipeline">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.DefaultGraphPipeline.Hybrid">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.Hybrid.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.Hybrid.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.Graph">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Graph.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Graph.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.Hybrid">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Hybrid.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Hybrid.dll</HintPath>
</Reference>
<Reference Include="Unity.Build.SlimPlayerRuntime">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll</HintPath>
@@ -525,13 +626,17 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.dll</HintPath>
</Reference>
<Reference Include="Unity.Burst.Unsafe">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
</Reference>
<Reference Include="Unity.Collections">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Collections.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Collections.dll</HintPath>
</Reference>
<Reference Include="Unity.DataFlowGraph">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.DataFlowGraph.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.DataFlowGraph.dll</HintPath>
<Reference Include="Unity.Collections.LowLevel.ILSupport">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Collections.LowLevel.ILSupport.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Collections.LowLevel.ILSupport.dll</HintPath>
</Reference>
<Reference Include="Unity.Deformations">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll</HintPath>
@@ -545,6 +650,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Entities.Hybrid.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Entities.Hybrid.dll</HintPath>
</Reference>
<Reference Include="Unity.InternalAPIEngineBridge.012">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.InternalAPIEngineBridge.012.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.InternalAPIEngineBridge.012.dll</HintPath>
</Reference>
<Reference Include="Unity.Jobs">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Jobs.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Jobs.dll</HintPath>
@@ -577,10 +686,6 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Platforms.Common.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Platforms.Common.dll</HintPath>
</Reference>
<Reference Include="Unity.Postprocessing.Runtime">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.Properties">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Properties.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Properties.dll</HintPath>
@@ -621,9 +726,9 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.ResourceManager.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.ResourceManager.dll</HintPath>
</Reference>
<Reference Include="Unity.Scenes.Hybrid">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Scenes.Hybrid.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Scenes.Hybrid.dll</HintPath>
<Reference Include="Unity.Scenes">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Scenes.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Scenes.dll</HintPath>
</Reference>
<Reference Include="Unity.ScriptableBuildPipeline">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.ScriptableBuildPipeline.dll</HintPath>
@@ -653,58 +758,6 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.VisualEffectGraph.Runtime.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.VisualEffectGraph.Runtime.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath>
</Reference>
<Reference Include="uREPL">
<HintPath>..\ref\Gamecraft_Data\Managed\uREPL.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\uREPL.dll</HintPath>
</Reference>
<Reference Include="VisualProfiler">
<HintPath>..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath>
</Reference>
<Reference Include="Accessibility">
<HintPath>..\ref\Gamecraft_Data\Managed\Accessibility.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Accessibility.dll</HintPath>
</Reference>
<Reference Include="Facepunch.Steamworks.Win64">
<HintPath>..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath>
</Reference>
<Reference Include="JWT">
<HintPath>..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath>
</Reference>
<Reference Include="mscorlib">
<HintPath>..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath>
</Reference>
<Reference Include="netstandard">
<HintPath>..\ref\Gamecraft_Data\Managed\netstandard.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\netstandard.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Novell.Directory.Ldap">
<HintPath>..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll</HintPath>
</Reference>
<Reference Include="Rewired_Core">
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath>
</Reference>
<Reference Include="Rewired_Windows">
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath>
</Reference>
<Reference Include="Unity.Burst.Unsafe">
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AccessibilityModule">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath>
@@ -873,10 +926,18 @@
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIElementsModule">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIElementsNativeModule">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsNativeModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsNativeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIModule">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath>
@@ -933,6 +994,10 @@
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VirtualTexturingModule">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VirtualTexturingModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VirtualTexturingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VRModule">
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath>
@@ -945,6 +1010,14 @@
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath>
</Reference>
<Reference Include="uREPL">
<HintPath>..\ref\Gamecraft_Data\Managed\uREPL.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\uREPL.dll</HintPath>
</Reference>
<Reference Include="VisualProfiler">
<HintPath>..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath>
</Reference>
</ItemGroup>
<!--End Dependencies-->
</Project>

+ 2
- 2
GamecraftModdingAPI/Input/FakeInput.cs View File

@@ -76,7 +76,7 @@ namespace GamecraftModdingAPI.Input
case 9: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_9; break;
default: break;
}
if (commandLine) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.ToggleCommandLine;
//if (commandLine) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.ToggleCommandLine; - TODO
if (escape) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Escape;
if (enter) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Return;
if (debug) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.ToggleDebugDisplay;
@@ -125,7 +125,7 @@ namespace GamecraftModdingAPI.Input
if (tertiary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.TertiaryAction;
if (primaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryActionHeld;
if (secondaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryActionHeld;
if (toggleUnitGrid) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid;
//if (toggleUnitGrid) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid;
if (ctrl) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CtrlAction;
if (toggleColourMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleColourMode;
if (scaleBlockUp) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ScaleBlockUp;


+ 4
- 4
GamecraftModdingAPI/Inventory/HotbarEngine.cs View File

@@ -36,13 +36,13 @@ namespace GamecraftModdingAPI.Inventory

public bool SelectBlock(int block, uint playerID, bool cubeSelectedByPick = false)
{
var inputs = entitiesDB.QueryEntities<LocalInputEntityStruct>(InputExclusiveGroups.LocalPlayers);
var inputs = entitiesDB.QueryEntities<LocalInputEntityStruct>(InputExclusiveGroups.LocalPlayers).ToBuffer();
if (inputs.count == 0) return false;
for (int i = 0; i < inputs.count; i++)
{
if (inputs[i].ID.entityID == playerID) {
inputs[i].cubeSelectedByPick = cubeSelectedByPick;
inputs[i].selectedCube = block;
if (inputs.buffer[i].ID.entityID == playerID) {
inputs.buffer[i].cubeSelectedByPick = cubeSelectedByPick;
inputs.buffer[i].selectedCube = block;
return true;
}
}


+ 1
- 3
GamecraftModdingAPI/Inventory/HotbarSlotSelectionHandlerEnginePatch.cs View File

@@ -1,8 +1,6 @@
using System;
using System.Reflection;

using RobocraftX.GUI;
using RobocraftX.GUI.Hotbar;
using Svelto.ECS;

using HarmonyLib;
@@ -17,7 +15,7 @@ namespace GamecraftModdingAPI.Inventory

public static BlockIDs EquippedPartID { get => (BlockIDs)selectedBlockInt; }

private static MethodInfo PatchedMethod { get; } = AccessTools.Method(AccessTools.TypeByName("RobocraftX.GUI.Hotbar.HotbarSlotSelectionHandlerEngine"), "ActivateSlotForCube", parameters: new Type[] { typeof(uint), typeof(int), typeof(ExclusiveGroupStruct) });
private static MethodInfo PatchedMethod { get; } = AccessTools.Method("Gamecraft.GUI.Hotbar.Blocks.SyncHotbarSlotSelectedToEquippedPartEngine:ActivateSlotForCube", parameters: new Type[] { typeof(uint), typeof(int), typeof(ExclusiveGroupStruct) });

public static void Prefix(uint playerID, int selectedDBPartID, ExclusiveGroupStruct groupID)
{


+ 25
- 7
GamecraftModdingAPI/Main.cs View File

@@ -1,17 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using GamecraftModdingAPI.Blocks;
using HarmonyLib;

using RobocraftX;
using RobocraftX.Services;
using Svelto.Context;

using GamecraftModdingAPI.Utility;
using GamecraftModdingAPI.Events;
using GamecraftModdingAPI.Players;
using GamecraftModdingAPI.Tasks;
using uREPL;

namespace GamecraftModdingAPI
{
@@ -46,7 +44,20 @@ namespace GamecraftModdingAPI
Logging.MetaDebugLog($"Patching Gamecraft");
var currentAssembly = Assembly.GetExecutingAssembly();
harmony = new Harmony(currentAssembly.GetName().Name);
harmony.PatchAll(currentAssembly);
try
{
harmony.PatchAll(currentAssembly);
}
catch (Exception e)
{ //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet
Logging.Log(e.ToString());
Logging.LogWarning("Failed to patch Gamecraft. Attempting to patch to display error...");
harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized")
.MakeGenericMethod(typeof(UnityContext<FullGameCompositionRoot>)),
new HarmonyMethod(((Action) OnPatchError).Method)); //Can't use lambdas here :(
return;
}

// init utility
Logging.MetaDebugLog($"Initializing Utility");
#pragma warning disable 0612,0618
@@ -72,6 +83,7 @@ namespace GamecraftModdingAPI
// init object-oriented classes
Player.Init();
Block.Init();
BlockGroup.Init();
Wire.Init();
GameClient.Init();
AsyncUtils.Init();
@@ -102,5 +114,11 @@ namespace GamecraftModdingAPI
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
}
}

private static void OnPatchError()
{
ErrorBuilder.DisplayMustQuitError("Failed to patch Gamecraft!\n" +
"Make sure you're using the latest version of GamecraftModdingAPI or disable mods if the API isn't released yet.");
}
}
}

+ 32
- 2
GamecraftModdingAPI/Player.cs View File

@@ -1,5 +1,4 @@
using System;

using Unity.Mathematics;
using RobocraftX.Common;
using RobocraftX.Common.Players;
@@ -17,6 +16,7 @@ namespace GamecraftModdingAPI
{
// static functionality
private static PlayerEngine playerEngine = new PlayerEngine();
private static Player localPlayer;

/// <summary>
/// Checks if the specified player exists.
@@ -54,6 +54,19 @@ namespace GamecraftModdingAPI
return (uint) playerEngine.GetAllPlayerCount();
}

/// <summary>
/// Returns the current player belonging to this client.
/// </summary>
public static Player LocalPlayer
{
get
{
if (localPlayer == null || localPlayer.Id != playerEngine.GetLocalPlayer())
localPlayer = new Player(PlayerType.Local);
return localPlayer;
}
}

/// <summary>
/// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.Player"/> class.
/// </summary>
@@ -329,7 +342,24 @@ namespace GamecraftModdingAPI
}
}

// object methods
/// <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 LocalBlueprintInputStruct lbis)
? new Blueprint(lbis.selectedBlueprintId)
: null;
set => BlockGroup._engine.SelectBlueprint(value?.Id ?? uint.MaxValue);
}

/// <summary>
/// The player's mode in time stopped mode, determining what they place.
/// </summary>
public PlayerBuildingMode BuildingMode => (PlayerBuildingMode) playerEngine
.GetCharacterStruct<PlayerInputTimeStoppedContextStruct>(Id, out _).timeStoppedContext;

// object methods

/// <summary>
/// Teleport the player to the specified coordinates.


+ 10
- 0
GamecraftModdingAPI/Players/PlayerBuildingMode.cs View File

@@ -0,0 +1,10 @@
namespace GamecraftModdingAPI.Players
{
public enum PlayerBuildingMode
{
BlockMode,
ColourMode,
ConfigMode,
BlueprintMode
}
}

+ 4
- 4
GamecraftModdingAPI/Players/PlayerEngine.cs View File

@@ -50,10 +50,10 @@ namespace GamecraftModdingAPI.Players
public uint GetLocalPlayer()
{
if (!isReady) return uint.MaxValue;
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers);
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers).ToBuffer();
if (localPlayers.count > 0)
{
return localPlayers[0].ID.entityID;
return localPlayers.buffer[0].ID.entityID;
}
return uint.MaxValue;
}
@@ -61,10 +61,10 @@ namespace GamecraftModdingAPI.Players
public uint GetRemotePlayer()
{
if (!isReady) return uint.MaxValue;
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers);
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers).ToBuffer();
if (localPlayers.count > 0)
{
return localPlayers[0].ID.entityID;
return localPlayers.buffer[0].ID.entityID;
}
return uint.MaxValue;
}


+ 12
- 2
GamecraftModdingAPI/SimBody.cs View File

@@ -17,12 +17,13 @@ namespace GamecraftModdingAPI
public EGID Id { get; }

/// <summary>
/// The cluster this chunk belongs to, or null if the chunk doesn't exist. Get the SimBody from a Block if possible for good performance here.
/// The cluster this chunk belongs to, or null if no cluster destruction manager present or the chunk doesn't exist.
/// Get the SimBody from a Block if possible for good performance here.
/// </summary>
public Cluster Cluster => cluster ?? (cluster = clusterId == uint.MaxValue ? Block.BlockEngine.GetCluster(Id.entityID) : new Cluster(clusterId));

private Cluster cluster;
private uint clusterId;
private readonly uint clusterId = uint.MaxValue;

public SimBody(EGID id)
{
@@ -120,6 +121,15 @@ namespace GamecraftModdingAPI
return Block.BlockEngine.GetConnectedSimBodies(Id.entityID);
}

/// <summary>
/// The blocks that form this rigid body.
/// </summary>
/// <returns></returns>
public Block[] GetBlocks()
{
return Block.BlockEngine.GetBodyBlocks(Id.entityID);
}

private ref RigidBodyEntityStruct GetStruct()
{
return ref Block.BlockEngine.GetBlockInfo<RigidBodyEntityStruct>(Id);


+ 19
- 5
GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs View File

@@ -1,18 +1,22 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

using HarmonyLib;
using IllusionInjector;
// test
using GPUInstancer;
using Svelto.ECS;
using RobocraftX.Blocks;
using RobocraftX.Common;
using RobocraftX.SimulationModeState;
using RobocraftX.FrontEnd;
using Unity.Mathematics;
using UnityEngine;
using RobocraftX.Schedulers;
using Svelto.Tasks.ExtraLean;
using uREPL;
@@ -22,6 +26,7 @@ using GamecraftModdingAPI.Events;
using GamecraftModdingAPI.Utility;
using GamecraftModdingAPI.Blocks;
using GamecraftModdingAPI.Players;
using EventType = GamecraftModdingAPI.Events.EventType;

namespace GamecraftModdingAPI.Tests
{
@@ -176,11 +181,6 @@ namespace GamecraftModdingAPI.Tests
Logging.CommandLog("Finished in " + sw.ElapsedMilliseconds + "ms");
})
.Build();
//With Sync(): 1135ms
//Without Sync(): 134ms
//Async: 348 794ms, doesn't freeze game
//Without Sync() but wait for submission: 530ms
//With Sync() at the end: 380ms

Block b = null;
CommandBuilder.Builder("moveBlockInSim", "Run in build mode first while looking at a block, then in sim to move it up")
@@ -277,6 +277,20 @@ namespace GamecraftModdingAPI.Tests
Logging.CommandLog("Health set to: " + val);
}).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);
Block.Placed += (sender, args) =>
Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID);


+ 1
- 1
GamecraftModdingAPI/Tests/TestRoot.cs View File

@@ -65,7 +65,7 @@ namespace GamecraftModdingAPI.Tests
_testsCountPassed = 0;
_testsCountFailed = 0;
// flow control
Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); };
Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_TimeRunningAndStopped); };
Game.Exit += (s, a) => state = "ReturningFromGame";
Client.EnterMenu += (sender, args) =>
{


+ 10
- 1
GamecraftModdingAPI/Utility/FullGameFields.cs View File

@@ -12,8 +12,9 @@ using RobocraftX.GUI;
using RobocraftX.Multiplayer;
using RobocraftX.Rendering;
using Svelto.Context;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.Schedulers.Unity;
using Svelto.ECS.Schedulers;
using UnityEngine;
using Unity.Entities;
using Unity.Physics.Systems;
@@ -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)


+ 1
- 1
doxygen.conf View File

@@ -38,7 +38,7 @@ PROJECT_NAME = "GamecraftModdingAPI"
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = "v1.5.0"
PROJECT_NUMBER = "v1.7.0"

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a


Loading…
Cancel
Save