Merge pull request 'Add API to remove blocks, change PlaceBlock return type and others' (#4) from removal into master

This commit is contained in:
NGnius 2020-04-13 19:44:12 +00:00
commit 2963517764
12 changed files with 170 additions and 55 deletions

View file

@ -0,0 +1,31 @@
using RobocraftX.Blocks.Ghost;
using RobocraftX.Character.Camera;
using RobocraftX.Character.Factories;
using Svelto.ECS;
namespace GamecraftModdingAPI.Blocks
{
public class BlockUtility
{
/// <summary>
/// Returns the block the player is currently looking at.
/// </summary>
/// <param name="playerId">The player's ID</param>
/// <param name="entitiesDB">The entities DB</param>
/// <param name="maxDistance">The maximum distance from the player (default is the player's building reach)</param>
/// <returns>The block's EGID or null if not found</returns>
public static EGID? GetBlockLookedAt(uint playerId, EntitiesDB entitiesDB, float maxDistance = -1f)
{
if (!entitiesDB.TryQueryMappedEntities<CharacterCameraRayCastEntityStruct>(
CameraExclusiveGroups.CameraGroup, out var mapper))
return null;
mapper.TryGetEntity(playerId, out CharacterCameraRayCastEntityStruct rayCast);
float distance = maxDistance < 0
? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast)
: maxDistance;
if (rayCast.hit && rayCast.distance <= distance)
return rayCast.hitEgid;
return null;
}
}
}

View file

@ -26,7 +26,7 @@ namespace GamecraftModdingAPI.Blocks
/// <returns>Whether the operation was successful</returns> /// <returns>Whether the operation was successful</returns>
public static bool MoveBlock(uint id, float3 vector) public static bool MoveBlock(uint id, float3 vector)
{ {
if (movementEngine.IsInGame && movementEngine.IsBuildMode()) if (movementEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
{ {
movementEngine.MoveBlock(id, vector); movementEngine.MoveBlock(id, vector);
return true; return true;
@ -45,7 +45,7 @@ namespace GamecraftModdingAPI.Blocks
/// <returns>Whether the operation was successful</returns> /// <returns>Whether the operation was successful</returns>
public static bool MoveConnectedBlocks(uint id, float3 vector) public static bool MoveConnectedBlocks(uint id, float3 vector)
{ {
if (movementEngine.IsInGame && movementEngine.IsBuildMode()) if (movementEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
{ {
movementEngine.MoveConnectedBlocks(id, vector); movementEngine.MoveConnectedBlocks(id, vector);
return true; return true;

View file

@ -79,10 +79,5 @@ namespace GamecraftModdingAPI.Blocks
} }
return this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).position; return this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).position;
} }
public bool IsBuildMode()
{
return GamecraftModdingAPI.Utility.GameState.IsBuildMode();
}
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using Unity.Mathematics; using Unity.Mathematics;
using Svelto.ECS;
using GamecraftModdingAPI.Utility; using GamecraftModdingAPI.Utility;
@ -27,8 +28,8 @@ namespace GamecraftModdingAPI.Blocks
/// <param name="uscale">The block's uniform scale - default scale is 1 (with 0.2 width)</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> /// <param name="scale">The block's non-uniform scale - 0 means <paramref name="uscale"/> is used</param>
/// <param name="playerId">The player who placed the block</param> /// <param name="playerId">The player who placed the block</param>
/// <returns>Whether the operation was successful</returns> /// <returns>The placed block's ID or null if failed</returns>
public static bool PlaceBlock(BlockIDs block, float3 position, public static EGID? PlaceBlock(BlockIDs block, float3 position,
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
int uscale = 1, float3 scale = default, uint playerId = 0) int uscale = 1, float3 scale = default, uint playerId = 0)
{ {
@ -36,19 +37,14 @@ namespace GamecraftModdingAPI.Blocks
{ {
try try
{ {
placementEngine.PlaceBlock(block, color, darkness, position, uscale, scale, playerId, rotation); return placementEngine.PlaceBlock(block, color, darkness, position, uscale, scale, playerId, rotation);
} }
catch (Exception e) catch (Exception e)
{ {
uREPL.Log.Output(e.Message); Logging.MetaDebugLog(e);
#if DEBUG
//Logging.LogException(e);
#endif
return false;
} }
return true;
} }
return false; return null;
} }
public static void Init() public static void Init()

View file

@ -42,17 +42,17 @@ namespace GamecraftModdingAPI.Blocks
} }
public EntitiesDB entitiesDB { get; set; } public EntitiesDB entitiesDB { get; set; }
internal static BlockEntityFactory _blockEntityFactory; //Injected from PlaceBlockEngine private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceBlockEngine
public void PlaceBlock(BlockIDs block, BlockColors color, byte darkness, float3 position, int uscale, public EGID PlaceBlock(BlockIDs block, BlockColors color, byte darkness, float3 position, int uscale,
float3 scale, uint playerId, float3 rotation) float3 scale, uint playerId, float3 rotation)
{ //It appears that only the non-uniform scale has any visible effect, but if that's not given here it will be set to the uniform one { //It appears that only the non-uniform scale has any visible effect, but if that's not given here it will be set to the uniform one
if (darkness > 9) if (darkness > 9)
throw new Exception("That is too dark. Make sure to use 0-9 as darkness. (0 is default.)"); throw new Exception("That is too dark. Make sure to use 0-9 as darkness. (0 is default.)");
BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, playerId); return BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, playerId);
} }
private void BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) private EGID BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId)
{ {
if (_blockEntityFactory == null) if (_blockEntityFactory == null)
throw new Exception("The factory is null."); throw new Exception("The factory is null.");
@ -80,21 +80,21 @@ namespace GamecraftModdingAPI.Blocks
unitSnapOffset = 0, isUsingUnitSize = true unitSnapOffset = 0, isUsingUnitSize = true
}; };
EquippedColourStruct colour = new EquippedColourStruct {indexInPalette = color}; EquippedColourStruct colour = new EquippedColourStruct {indexInPalette = color};
EGID egid2; EGID newBlockID;
switch (category.category) switch (category.category)
{ {
case CubeCategory.SpawnPoint: case CubeCategory.SpawnPoint:
case CubeCategory.BuildingSpawnPoint: case CubeCategory.BuildingSpawnPoint:
egid2 = MachineEditingGroups.NewSpawnPointBlockID; newBlockID = MachineEditingGroups.NewSpawnPointBlockID;
break; break;
default: default:
egid2 = MachineEditingGroups.NewBlockID; newBlockID = MachineEditingGroups.NewBlockID;
break; break;
} }
EntityStructInitializer EntityStructInitializer
structInitializer = structInitializer =
_blockEntityFactory.Build(egid2, dbid); //The ghost block index is only used for triggers _blockEntityFactory.Build(newBlockID, dbid); //The ghost block index is only used for triggers
if (colour.indexInPalette != byte.MaxValue) if (colour.indexInPalette != byte.MaxValue)
structInitializer.Init(new ColourParameterEntityStruct structInitializer.Init(new ColourParameterEntityStruct
{ {
@ -113,17 +113,17 @@ namespace GamecraftModdingAPI.Blocks
{ {
scaleFactor = placementScale.desiredScaleFactor scaleFactor = placementScale.desiredScaleFactor
}); });
structInitializer.Init( structInitializer.Init(new BlockPlacementInfoStruct()
new BlockPlacementInfoStruct() {
{ loadedFromDisk = false,
loadedFromDisk = false, placedBy = playerId
placedBy = playerId });
});
PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer); PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer);
EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup); EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup);
ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID); ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID);
pickedBlock.placedBlockEntityID = playerEGID; pickedBlock.placedBlockEntityID = playerEGID;
pickedBlock.placedBlockWasAPickedBlock = false; pickedBlock.placedBlockWasAPickedBlock = false;
return newBlockID;
} }
public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine"; public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine";
@ -139,7 +139,7 @@ namespace GamecraftModdingAPI.Blocks
static MethodBase TargetMethod(HarmonyInstance instance) static MethodBase TargetMethod(HarmonyInstance instance)
{ {
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceBlockEngine").GetConstructors()[0]; return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceBlockEngine").GetConstructors()[0];
} }
} }
} }

View file

@ -0,0 +1,28 @@
using Svelto.ECS;
using GamecraftModdingAPI.Utility;
namespace GamecraftModdingAPI.Blocks
{
public class Removal
{
private static RemovalEngine _removalEngine = new RemovalEngine();
/// <summary>
/// Removes the block with the given ID. Returns false if the block doesn't exist or the game isn't in build mode.
/// </summary>
/// <param name="targetBlock">The block to remove</param>
/// <returns>Whether the block was successfully removed</returns>
public static bool RemoveBlock(EGID targetBlock)
{
if (GameState.IsBuildMode())
return _removalEngine.RemoveBlock(targetBlock);
return false;
}
public static void Init()
{
GameEngineManager.AddGameEngine(_removalEngine);
}
}
}

View file

@ -0,0 +1,74 @@
using System.Reflection;
using Harmony;
using RobocraftX.Blocks;
using RobocraftX.Blocks.Ghost;
using RobocraftX.Character.Camera;
using RobocraftX.Character.Factories;
using RobocraftX.Common;
using RobocraftX.Players;
using Svelto.ECS;
using uREPL;
using GamecraftModdingAPI.Commands;
using GamecraftModdingAPI.Utility;
namespace GamecraftModdingAPI.Blocks
{
public class RemovalEngine : IApiEngine
{
private static IEntityFunctions _entityFunctions;
private static MachineGraphConnectionEntityFactory _connectionFactory;
public bool RemoveBlock(EGID target)
{
if (!entitiesDB.Exists<MachineGraphConnectionsEntityStruct>(target))
return false;
var connections = entitiesDB.QueryEntity<MachineGraphConnectionsEntityStruct>(target);
for (int i = connections.connections.Length - 1; i >= 0; i--)
_connectionFactory.RemoveConnection(connections, i, entitiesDB);
_entityFunctions.RemoveEntity<BlockEntityDescriptor>(target);
return true;
}
public void Ready()
{
/*CommandManager.AddCommand(new SimpleCustomCommandEngine(() =>
{
var block = BlockUtility.GetBlockLookedAt(LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB), entitiesDB);
if (block.HasValue)
{
RemoveBlock(block.Value);
Log.Output("Removed block.");
}
else
Log.Output("No block found where you're looking at.");
}, "removeCube", "Removes the cube you're looking at."));*/
}
public EntitiesDB entitiesDB { get; set; }
public void Dispose()
{
}
public string Name { get; } = "GamecraftModdingAPIRemovalGameEngine";
[HarmonyPatch]
public class FactoryObtainerPatch
{
static void Postfix(IEntityFunctions entityFunctions,
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
{
_entityFunctions = entityFunctions;
_connectionFactory = machineGraphConnectionEntityFactory;
Logging.MetaDebugLog("Requirements injected.");
}
static MethodBase TargetMethod(HarmonyInstance instance)
{
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine").GetConstructors()[0];
}
}
}
}

View file

@ -26,7 +26,7 @@ namespace GamecraftModdingAPI.Blocks
/// <returns>Whether the operation was successful</returns> /// <returns>Whether the operation was successful</returns>
public static bool RotateBlock(uint id, float3 vector) public static bool RotateBlock(uint id, float3 vector)
{ {
if (rotationEngine.IsInGame && rotationEngine.IsBuildMode()) if (rotationEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
{ {
rotationEngine.RotateBlock(id, vector); rotationEngine.RotateBlock(id, vector);
return true; return true;
@ -43,7 +43,7 @@ namespace GamecraftModdingAPI.Blocks
/// <returns>Whether the operation was successful</returns> /// <returns>Whether the operation was successful</returns>
public static bool RotateConnectedBlocks(uint id, float3 vector) public static bool RotateConnectedBlocks(uint id, float3 vector)
{ {
if (rotationEngine.IsInGame && rotationEngine.IsBuildMode()) if (rotationEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
{ {
rotationEngine.RotateConnectedBlocks(id, vector); rotationEngine.RotateConnectedBlocks(id, vector);
return true; return true;

View file

@ -44,7 +44,7 @@ namespace GamecraftModdingAPI.Blocks
IsInGame = true; IsInGame = true;
} }
// implementations for Movement static class // implementations for Rotation static class
public float3 RotateBlock(uint blockID, Vector3 vector) public float3 RotateBlock(uint blockID, Vector3 vector)
{ {
@ -78,10 +78,5 @@ namespace GamecraftModdingAPI.Blocks
// TODO: Implement and figure out the math // TODO: Implement and figure out the math
throw new NotImplementedException(); throw new NotImplementedException();
} }
public bool IsBuildMode()
{
return GamecraftModdingAPI.Utility.GameState.IsBuildMode();
}
} }
} }

View file

@ -147,10 +147,5 @@ namespace GamecraftModdingAPI.Blocks
} }
return res; return res;
} }
public bool IsSimulationMode()
{
return GamecraftModdingAPI.Utility.GameState.IsSimulationMode();
}
} }
} }

View file

@ -34,7 +34,7 @@ namespace GamecraftModdingAPI.Blocks
public static void SetSignalByBlock(uint blockID, float signal, bool input = true, bool owned = true) public static void SetSignalByBlock(uint blockID, float signal, bool input = true, bool owned = true)
{ {
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS);
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GameState.IsSimulationMode())
{ {
signalEngine.SetSignal(egid, signal, out uint _, input); signalEngine.SetSignal(egid, signal, out uint _, input);
} }
@ -42,7 +42,7 @@ namespace GamecraftModdingAPI.Blocks
public static void SetSignalByBlock(EGID blockID, float signal, bool input = true) public static void SetSignalByBlock(EGID blockID, float signal, bool input = true)
{ {
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GameState.IsSimulationMode())
{ {
signalEngine.SetSignal(blockID, signal, out uint _, input); signalEngine.SetSignal(blockID, signal, out uint _, input);
} }
@ -56,7 +56,7 @@ namespace GamecraftModdingAPI.Blocks
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> /// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
public static void SetSignalByID(uint signalID, float signal, bool input = true) public static void SetSignalByID(uint signalID, float signal, bool input = true)
{ {
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
{ {
signalEngine.SetSignal(signalID, signal, input); signalEngine.SetSignal(signalID, signal, input);
} }
@ -74,7 +74,7 @@ namespace GamecraftModdingAPI.Blocks
public static float AddSignalByBlock(uint blockID, float signal, bool clamp = true, bool input = true, bool owned = true) public static float AddSignalByBlock(uint blockID, float signal, bool clamp = true, bool input = true, bool owned = true)
{ {
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS);
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
{ {
return signalEngine.AddSignal(egid, signal, out uint _, clamp, input); return signalEngine.AddSignal(egid, signal, out uint _, clamp, input);
} }
@ -83,7 +83,7 @@ namespace GamecraftModdingAPI.Blocks
public static float AddSignalByBlock(EGID blockID, float signal, bool clamp = true, bool input = true) public static float AddSignalByBlock(EGID blockID, float signal, bool clamp = true, bool input = true)
{ {
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
{ {
return signalEngine.AddSignal(blockID, signal, out uint _, clamp, input); return signalEngine.AddSignal(blockID, signal, out uint _, clamp, input);
} }
@ -100,7 +100,7 @@ namespace GamecraftModdingAPI.Blocks
/// <returns>The signal's new value.</returns> /// <returns>The signal's new value.</returns>
public static float AddSignalByID(uint signalID, float signal, bool clamp = true, bool input = true) public static float AddSignalByID(uint signalID, float signal, bool clamp = true, bool input = true)
{ {
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
{ {
return signalEngine.AddSignal(signalID, signal, clamp, input); return signalEngine.AddSignal(signalID, signal, clamp, input);
} }
@ -117,7 +117,7 @@ namespace GamecraftModdingAPI.Blocks
public static float GetSignalByBlock(uint blockID, bool input = true, bool owned = true) public static float GetSignalByBlock(uint blockID, bool input = true, bool owned = true)
{ {
EGID egid = new EGID(blockID, owned? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); EGID egid = new EGID(blockID, owned? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS);
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
{ {
return signalEngine.GetSignal(egid, out uint _, input); return signalEngine.GetSignal(egid, out uint _, input);
} }
@ -126,7 +126,7 @@ namespace GamecraftModdingAPI.Blocks
public static float GetSignalByBlock(EGID blockID, bool input = true) public static float GetSignalByBlock(EGID blockID, bool input = true)
{ {
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
{ {
return signalEngine.GetSignal(blockID, out uint _, input); return signalEngine.GetSignal(blockID, out uint _, input);
} }
@ -141,7 +141,7 @@ namespace GamecraftModdingAPI.Blocks
/// <returns>The signal's value.</returns> /// <returns>The signal's value.</returns>
public static float GetSignalByID(uint signalID, bool input = true) public static float GetSignalByID(uint signalID, bool input = true)
{ {
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
{ {
return signalEngine.GetSignal(signalID, input); return signalEngine.GetSignal(signalID, input);
} }

View file

@ -65,6 +65,7 @@ namespace GamecraftModdingAPI
Blocks.Signals.Init(); Blocks.Signals.Init();
Blocks.Placement.Init(); Blocks.Placement.Init();
Blocks.Tweakable.Init(); Blocks.Tweakable.Init();
Blocks.Removal.Init();
// init inventory // init inventory
Inventory.Hotbar.Init(); Inventory.Hotbar.Init();
// init input // init input