Fixes, added SimBody class

This commit is contained in:
Norbi Peti 2020-05-23 00:06:49 +02:00
parent 084cbb40c4
commit dca6fe4c1b
15 changed files with 242 additions and 127 deletions

View file

@ -23,15 +23,14 @@ namespace GamecraftModdingAPI
protected static readonly MovementEngine MovementEngine = new MovementEngine();
protected static readonly RotationEngine RotationEngine = new RotationEngine();
protected static readonly RemovalEngine RemovalEngine = new RemovalEngine();
protected static readonly BlockEngine BlockEngine = new BlockEngine();
protected static readonly SignalEngine SignalEngine = new SignalEngine();
protected internal static readonly BlockEngine BlockEngine = new BlockEngine();
/// <summary>
/// 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>This method causes a sync which may have a performance impact. Use the async version if possible.</para>
/// </summary>
/// <param name="block">The block's type</param>
/// <param name="color">The block's color</param>
@ -48,15 +47,8 @@ namespace GamecraftModdingAPI
{
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
return new Block(PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation));
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
return new Block(PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation));
}
return null;
@ -122,17 +114,8 @@ namespace GamecraftModdingAPI
}
}
public Block(uint id)
public Block(uint id) : this(new EGID(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP))
{
Id = new EGID(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP);
if (!BlockEngine.BlockExists(Id))
{
Sync();
if (!BlockEngine.BlockExists(Id))
{
throw new BlockDoesNotExistException($"Block {Id.entityID} must be placed using PlaceNew(...) since it does not exist yet");
}
}
}
/// <summary>
@ -264,6 +247,17 @@ namespace GamecraftModdingAPI
/// <returns>True if the block exists and could be removed.</returns>
public bool Remove() => RemovalEngine.RemoveBlock(Id);
/// <summary>
/// Returns the rigid body of the cluster 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></returns>
public SimBody ToSimBody()
{
uint id = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(Id).machineRigidBodyId;
return new SimBody(id);
}
public override string ToString()
{
return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Rotation)}: {Rotation}";

View file

@ -15,21 +15,14 @@ namespace GamecraftModdingAPI.Blocks
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
int uscale = 1, float3 scale = default, Player player = null)
{
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(BlockIDs.ConsoleBlock, color, darkness,
position, uscale, scale, player, rotation);
return new ConsoleBlock(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
}
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
EGID id = PlacementEngine.PlaceBlock(BlockIDs.ConsoleBlock, color, darkness,
position, uscale, scale, player, rotation);
return new ConsoleBlock(id);
}
return null;
return null;
}
public ConsoleBlock(EGID id): base(id)

View file

@ -25,16 +25,9 @@ namespace GamecraftModdingAPI.Blocks
}
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new Motor(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new Motor(id);
}
return null;

View file

@ -25,16 +25,9 @@ namespace GamecraftModdingAPI.Blocks
}
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new Piston(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new Piston(id);
}
return null;

View file

@ -21,20 +21,13 @@ namespace GamecraftModdingAPI.Blocks
{
if (!(block == BlockIDs.ServoAxle || block == BlockIDs.ServoHinge || block == BlockIDs.ServoPiston))
{
throw new BlockTypeException($"Block is not a {typeof(Servo).Name} block");
throw new BlockTypeException($"Block is not a {nameof(Servo)} block");
}
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new Servo(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new Servo(id);
}
return null;

View file

@ -25,16 +25,9 @@ namespace GamecraftModdingAPI.Blocks
{
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new SignalingBlock(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new SignalingBlock(id);
}
return null;

View file

@ -23,20 +23,13 @@ namespace GamecraftModdingAPI.Blocks
{
if (!(block == BlockIDs.LargeSpawn || block == BlockIDs.SmallSpawn || block == BlockIDs.MediumSpawn || block == BlockIDs.PlayerSpawn))
{
throw new BlockTypeException($"Block is not a {typeof(SpawnPoint).Name} block");
throw new BlockTypeException($"Block is not a {nameof(SpawnPoint)} block");
}
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
position, uscale, scale, player, rotation);
return new SpawnPoint(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
}
return null;

View file

@ -18,16 +18,9 @@ namespace GamecraftModdingAPI.Blocks
{
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(BlockIDs.TextBlock, color, darkness,
position, uscale, scale, player, rotation);
return new TextBlock(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
EGID id = PlacementEngine.PlaceBlock(BlockIDs.TextBlock, color, darkness,
position, uscale, scale, player, rotation);
return new TextBlock(id);
}
return null;

View file

@ -21,17 +21,9 @@ namespace GamecraftModdingAPI.Blocks
{
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
try
{
EGID id = PlacementEngine.PlaceBlock(BlockIDs.Timer, color, darkness,
position, uscale, scale, player, rotation);
return new Timer(id);
}
catch (Exception e)
{
Logging.MetaDebugLog(e);
}
EGID id = PlacementEngine.PlaceBlock(BlockIDs.Timer, color, darkness,
position, uscale, scale, player, rotation);
return new Timer(id);
}
return null;

View file

@ -1,6 +1,7 @@
using System;
using Unity.Mathematics;
using RobocraftX.Common;
using GamecraftModdingAPI.Players;
@ -221,13 +222,27 @@ namespace GamecraftModdingAPI
/// <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>
/// <returns>The block or null if not found</returns>
public Block GetBlockLookedAt(float maxDistance = -1f)
{
return playerEngine.GetBlockLookedAt(Id, maxDistance);
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.OWNED_BLOCKS_GROUP
? new Block(egid.Value)
: null;
}
/// <summary>
/// Returns the rigid body the player is currently looking at during simulation.
/// </summary>
/// <param name="maxDistance">The maximum distance from the player (default is the player's building reach)</param>
/// <returns>The block or null if not found</returns>
public SimBody GetSimBodyLookedAt(float maxDistance = -1f)
{
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.SIMULATION_BODIES_GROUP
? new SimBody(egid.Value)
: null;
}
// internal methods

View file

@ -238,7 +238,7 @@ namespace GamecraftModdingAPI.Players
return false;
}
public Block GetBlockLookedAt(uint playerId, float maxDistance = -1f)
public EGID? GetThingLookedAt(uint playerId, float maxDistance = -1f)
{
if (!entitiesDB.TryQueryMappedEntities<CharacterCameraRayCastEntityStruct>(
CameraExclusiveGroups.CameraGroup, out var mapper))
@ -248,7 +248,22 @@ namespace GamecraftModdingAPI.Players
? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast)
: maxDistance;
if (rayCast.hit && rayCast.distance <= distance)
return new Block(rayCast.hitEgid);
return rayCast.hitEgid;
/*if (rayCast.hit)
{
*Logging.MetaDebugLog("RayCast EGID: " + rayCast.hitEgid);
var d = AccessTools.Field(typeof(ExclusiveGroup), "_knownGroups").GetValue(null) as
Dictionary<string, ExclusiveGroupStruct>;
foreach (var groupStruct in d)
{
if (groupStruct.Value == rayCast.hitEgid.groupID)
{
Logging.MetaDebugLog("Group name: " + groupStruct.Key);
break; //SIMULATION_BODIES_GROUP
}
}*
//Logging.MetaDebugLog("Position: " + Block.GetBlockPositionTest(rayCast.hitEgid));
}*/
return null;
}

View file

@ -0,0 +1,88 @@
using RobocraftX.Common;
using RobocraftX.Physics;
using Svelto.ECS;
using Unity.Mathematics;
using Unity.Physics;
using UnityEngine;
namespace GamecraftModdingAPI
{
/// <summary>
/// A rigid body (like a cluster of connected blocks) during simulation.
/// </summary>
public class SimBody
{
public EGID Id { get; }
public SimBody(EGID id)
{
Id = id;
}
public SimBody(uint id) : this(new EGID(id, CommonExclusiveGroups.SIMULATION_BODIES_GROUP))
{
}
public float3 Position
{
get => GetStruct().position;
set => GetStruct().position = value;
}
public float3 Velocity
{
get => GetStruct().velocity;
set => GetStruct().velocity = value;
}
public float3 AngularVelocity
{
get => GetStruct().angularVelocity;
set => GetStruct().angularVelocity = value;
}
public float3 DeltaVelocity
{
get => GetStruct().deltaVelocity;
set => GetStruct().deltaVelocity = value;
}
public float3 DeltaAngularVelocity
{
get => GetStruct().deltaAngularVelocity;
set => GetStruct().deltaAngularVelocity = value;
}
public float3 Rotation
{
get => ((Quaternion) GetStruct().rotation).eulerAngles;
set
{
ref var str = ref GetStruct();
Quaternion quaternion = str.rotation;
quaternion.eulerAngles = value;
str.rotation = quaternion;
}
}
public float Mass
{
get => math.rcp(GetStruct().physicsMass.InverseMass);
set => GetStruct().physicsMass.InverseMass = math.rcp(value);
}
/// <summary>
/// Whether the body can be moved or static
/// </summary>
public bool Static
{
get => Block.BlockEngine.GetBlockInfo<MassEntityStruct>(Id).isStatic;
set => Block.BlockEngine.GetBlockInfo<MassEntityStruct>(Id).isStatic = value;
}
private ref RigidBodyEntityStruct GetStruct()
{
return ref Block.BlockEngine.GetBlockInfo<RigidBodyEntityStruct>(Id);
}
}
}

View file

@ -1,8 +1,11 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using HarmonyLib;
using IllusionInjector;
// test
using Svelto.ECS;
using RobocraftX.Blocks;
@ -143,15 +146,46 @@ namespace GamecraftModdingAPI.Tests
CommandBuilder.Builder()
.Name("PlaceAluminium")
.Description("Place a block of aluminium at the given coordinates")
.Action(async (float x, float y, float z) =>
.Action((float x, float y, float z) =>
{
var block = await Block.PlaceNewAsync(BlockIDs.AluminiumCube, new float3(x, y, z));
Logging.MetaDebugLog("Block placed with type: " + block.Type);
var block = Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x, y, z));
Logging.CommandLog("Block placed with type: " + block.Type);
})
.Build();
CommandBuilder.Builder("getBlock")
.Action(() => uREPL.Log.Output(new Player(Players.PlayerType.Local).GetBlockLookedAt()+"")).Build();
CommandBuilder.Builder()
.Name("PlaceAluminiumLots")
.Description("Place a lot of blocks of aluminium at the given coordinates")
.Action((float x, float y, float z) =>
{
Logging.CommandLog("Starting...");
var sw = Stopwatch.StartNew();
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x + i, y, z + j));
//Block.Sync();
sw.Stop();
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, then in sim while looking at a block to move it up")
.Action(() =>
{
if (b == null)
{
b = new Player(PlayerType.Local).GetBlockLookedAt();
Logging.CommandLog("Block saved: " + b);
}
else
Logging.CommandLog("Block moved to: " + (b.ToSimBody().Position += new float3(0, 2, 0)));
}).Build();
CommandBuilder.Builder("Error", "Throw an error to make sure SimpleCustomCommandEngine's wrapper catches it.")
.Action(() => { throw new Exception("Error Command always throws an error"); })
@ -176,6 +210,7 @@ namespace GamecraftModdingAPI.Tests
}).Build();
GameClient.SetDebugInfo("lookedAt", LookedAt);
GameClient.SetDebugInfo("InstalledMods", InstalledMods);
/*
CommandManager.AddCommand(new SimpleCustomCommandEngine<float>((float d) => { UnityEngine.Camera.main.fieldOfView = d; },
@ -237,10 +272,35 @@ namespace GamecraftModdingAPI.Tests
private string LookedAt()
{
if (player == null)
player = new Player(Players.PlayerType.Local);
Block block = player.GetBlockLookedAt();
if (block == null) return "Block: none";
return "Block: " + block.Type + "\nColor: " + block.Color + "\n" + "At: " + block.Position;
player = new Player(PlayerType.Local);
if (GameState.IsBuildMode())
{
Block block = player.GetBlockLookedAt();
if (block == null) return "Block: none";
return "Block: " + block.Type + "\nColor: " + block.Color + "\n" + "At: " + block.Position;
}
if (GameState.IsSimulationMode())
{
SimBody body = player.GetSimBodyLookedAt();
if (body == null) return "Body: none";
return "Body: " + (body.Static ? "static" : "non-static")
+ "\nAt: " + body.Position + " - rotated: " + body.Rotation
+ "\nWith mass: " + body.Mass
+ "\nVelocity: " + body.Velocity + " - angular: " + body.AngularVelocity
+ "\nDelta velocity: " + body.DeltaVelocity + " - angular: " + body.DeltaAngularVelocity;
}
return "Switching modes...";
}
private string modsString;
private string InstalledMods()
{
if (modsString != null) return modsString;
StringBuilder sb = new StringBuilder("Installed mods:");
foreach (var plugin in PluginManager.Plugins)
sb.Append("\n" + plugin);
return modsString = sb.ToString();
}
public void OnFixedUpdate() { }

View file

@ -52,7 +52,7 @@ namespace GamecraftModdingAPI.Utility
}
catch (Exception e)
{
Logging.LogException(e, "Failed to inject AddInfo method for the debug display!");
Logging.LogWarning("Failed to inject AddInfo method for the debug display!\n" + e);
}
return list;
@ -68,7 +68,7 @@ namespace GamecraftModdingAPI.Utility
}
catch (Exception e)
{
Logging.LogException(e, "Unable to get info for " + info.Key);
Logging.LogWarning("Unable to get info for " + info.Key + "\n" + e);
}
}
}

View file

@ -83,7 +83,7 @@ namespace GamecraftModdingAPI.Utility
}
/// <summary>
/// Write an exception to Gamecraft's log
/// Write an exception to Gamecraft's log and to the screen and exit game
/// </summary>
/// <param name="e">The exception to log</param>
/// <param name="extraData">The extra data to pass to the ILogger.
@ -95,7 +95,7 @@ namespace GamecraftModdingAPI.Utility
}
/// <summary>
/// Write an exception message to Gamecraft's log
/// Write an exception message to Gamecraft's log and to the screen and exit game
/// </summary>
/// <param name="obj">The object to log</param>
/// <param name="e">The exception to log</param>