BuildingTools/BuildingTools/BuildingTools.cs

234 lines
No EOL
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using GamecraftModdingAPI;
using GamecraftModdingAPI.Blocks;
using GamecraftModdingAPI.Commands;
using GamecraftModdingAPI.Utility;
using IllusionPlugin;
using Unity.Mathematics;
using Main = GamecraftModdingAPI.Main;
namespace BuildingTools
{
public class BuildingTools : IEnhancedPlugin
{
private readonly CommandUtils _commandUtils;
private readonly BlockSelections _blockSelections;
public BuildingTools()
{
_blockSelections = new BlockSelections();
_commandUtils = new CommandUtils(_blockSelections);
}
public override void OnApplicationStart()
{
Main.Init();
GameClient.SetDebugInfo("PlayerInfo", GetPlayerInfo);
GameClient.SetDebugInfo("BlockModInfo", GetBlockInfo);
_commandUtils.RegisterBlockCommand("scaleBlocks",
"Scales the selected blocks, relative to current size (current scale * new scale)." +
" The block you're looking at stays where it is, everything else is moved next to it.",
(scaleX, scaleY, scaleZ, blocks, refBlock) => //TODO: Either remove refBlock or add commands for changing it
{
if (!GameState.IsBuildMode()) return; //Scaling & positioning is weird in simulation
if (_blockSelections.CheckNoBlocks(blocks)) return;
// ReSharper disable once PossibleNullReferenceException
float3? reference = Player.LocalPlayer.GetBlockLookedAt()?.Position;
if (!reference.HasValue)
{
Logging.CommandLogError("Look at a block (not too far away) to be used as reference.");
return;
}
float3 scale = new float3(scaleX, scaleY, scaleZ);
foreach (var block in blocks)
{
block.Scale *= scale;
block.Position = (float3) (reference + (block.Position - reference) * scale);
}
Logging.CommandLog("Blocks scaled.");
});
_commandUtils.RegisterBlockCommand("scaleIndividually", "Scales the blocks you're looking at, but doesn't move them." +
" The scale is relative, 1 means no change.",
(scaleX, scaleY, scaleZ, blocks, refBlock) =>
{
if (!GameState.IsBuildMode()) return; //Scaling & positioning is weird in simulation
float3 scale = new float3(scaleX, scaleY, scaleZ);
foreach (var block in blocks)
block.Scale *= scale;
});
_commandUtils.RegisterBlockCommand("moveBlocks", "Moves (teleports) the selected blocks around both in time stopped and running. The latter will be reset as expected.", (x, y, z, blocks, refBlock) =>
{
if (GameState.IsBuildMode())
foreach (var block in blocks)
block.Position += new float3(x, y, z);
else if (GameState.IsSimulationMode())
foreach (var body in GetSimBodies(blocks))
body.Position += new float3(x, y, z);
});
_commandUtils.RegisterBlockCommand("colorBlocks", "Colors the selected blocks permanently both in time stopped and running. It won't be reset when stopping time.",
(color, darkness, blocks, refBlock) =>
{
if (!Enum.TryParse(color, true, out BlockColors clr))
{
Logging.CommandLogWarning("Color " + color + " not found");
}
foreach (var block in blocks)
block.Color = new BlockColor {Color = clr, Darkness = darkness};
});
CommandBuilder.Builder("selectBlocksLookedAt",
"Selects blocks (1 or more) to change. Only works in time stopped mode, however the blocks can be changed afterwards in both modes." +
" Parameter: whether one (true) or all connected (false) blocks should be selected.")
.Action<bool>(single =>
{
if (!GameState.IsBuildMode())
{
Logging.CommandLogError("This command can only be used in time stopped mode.");
return;
}
var refBlock = Player.LocalPlayer.GetBlockLookedAt();
if (refBlock == null)
{
Logging.CommandLogError("Block not found. Make sure to be close enough to the block.");
return;
}
_blockSelections.refBlock = refBlock;
_blockSelections.blocks = single ? new[] {refBlock} : refBlock.GetConnectedCubes() ?? new Block[0];
var blocks = _blockSelections.blocks;
Logging.CommandLog(blocks.Length + " blocks selected.");
}).Build();
CommandBuilder.Builder("selectBlocksWithID", "Selects blocks with a specific object ID.")
.Action<char>(id =>
{
_blockSelections.blocks =
(_blockSelections.refBlock = ObjectIdentifier.GetByID(id).FirstOrDefault())
?.GetConnectedCubes() ?? new Block[0];
Logging.CommandLog(_blockSelections.blocks.Length + " blocks selected.");
}).Build();
CommandBuilder.Builder("selectSelectedBlocks", "Selects blocks that are box selected by the player.")
.Action(() =>
{
_blockSelections.blocks = Player.LocalPlayer.GetSelectedBlocks();
_blockSelections.refBlock = _blockSelections.blocks.Length > 0 ? _blockSelections.blocks[0] : null;
Logging.CommandLog(_blockSelections.blocks.Length + " blocks selected.");
}).Build();
/*ConsoleCommands.RegisterWithChannel("selectSendSignal", ch => { }, ChannelType.Object,
"Sends a signal for selecting a given object ID for a command block.");*/
_commandUtils.RegisterBlockCommand("pushBlocks", "Adds velocity to the selected blocks. Only works in time running mode.",
(x, y, z, blocks, refBlock) =>
{
if (!GameState.IsSimulationMode())
{
Logging.CommandLogError("This command can only be used in time running mode.");
return;
}
foreach (var block in GetSimBodies(blocks))
block.Velocity += new float3(x, y, z);
});
_commandUtils.RegisterBlockCommand("pushRotateBlocks",
"Adds angular velocity to the selected blocks. Only works in simulation.",
(x, y, z, blocks, refBlock) =>
{
if (!GameState.IsSimulationMode())
{
Logging.CommandLogError("This command can only be used in time running mode.");
return;
}
foreach (var block in GetSimBodies(blocks))
block.AngularVelocity += new float3(x, y, z);
});
CommandBuilder.Builder("pushPlayer", "Adds velocity to the player.")
.Action<float, float, float>((x, y, z) =>
{
Player.LocalPlayer.Velocity += new float3(x, y, z);
}).Build();
CommandBuilder.Builder("pushRotatePlayer", "Adds angular velocity to the player.")
.Action<float, float, float>((x, y, z) =>
{
Player.LocalPlayer.AngularVelocity += new float3(x, y, z);
}).Build();
var noClip = new NoClipCommand();
GameEngineManager.AddGameEngine(noClip);
CommandBuilder.Builder("noClip", "Allows you to go through blocks. Run again to disable.")
.Action(noClip.Toggle).Build();
}
private string GetBlockInfo()
{
if (GameState.IsBuildMode())
return GetBlockInfoInBuildMode();
if (GameState.IsSimulationMode())
return GetBodyInfoInSimMode();
return "Switching modes...";
}
private static string GetBlockInfoInBuildMode()
{
var block = Player.LocalPlayer.GetBlockLookedAt();
if (block == null) return "";
float3 pos = block.Position;
float3 rot = block.Rotation;
float3 scale = block.Scale;
return $"Block: {block.Type} at {pos.x:F} {pos.y:F} {pos.z:F}\n" +
$"- Rotation: {rot.x:F}° {rot.y:F}° {rot.z:F}°\n" +
$"- Color: {block.Color.Color} darkness: {block.Color.Darkness}\n" +
$"- Scale: {scale.x:F} {scale.y:F} {scale.z:F}\n" +
$"- Label: {block.Label}\n" +
$"- ID: {block.Id}";
}
private static string GetBodyInfoInSimMode()
{
var body = Player.LocalPlayer.GetSimBodyLookedAt();
if (body == null) return GetBlockInfoInBuildMode();
float3 pos = body.Position;
float3 rot = body.Rotation;
float3 vel = body.Velocity;
float3 ave = body.AngularVelocity;
float3 com = body.CenterOfMass;
Cluster cluster = body.Cluster;
return $"Body at {pos.x:F} {pos.y:F} {pos.z:F}\n" +
$"- Rotation: {rot.x:F}° {rot.y:F}° {rot.z:F}°\n" +
$"- Velocity: {vel.x:F} {vel.y:F} {vel.z:F}\n" +
$"- Angular velocity: {ave.x:F} {ave.y:F} {ave.z:F}\n" +
$"- {(body.Static ? "Static body" : $"Mass: {body.Mass:F} center: {com.x:F} {com.y:F} {com.z:F}")}\n" +
$"- Volume: {body.Volume:F}\n" +
$"- Chunk health: {body.CurrentHealth:F} / {body.InitialHealth:F} - Multiplier: {body.HealthMultiplier:F}\n" +
(cluster == null
? ""
: $"- Cluster health: {cluster.CurrentHealth:F} / {cluster.InitialHealth:F} - Multiplier: {cluster.HealthMultiplier:F}"
);
}
private string GetPlayerInfo()
{
var player = Player.LocalPlayer;
if (player == null) return GetBlockInfoInBuildMode();
float3 pos = player.Position;
float3 rot = player.Rotation;
float3 vel = player.Velocity;
float3 ave = player.AngularVelocity;
return $"Player rotation: {rot.x:F}° {rot.y:F}° {rot.z:F}°\n" +
$"- Velocity: {vel.x:F} {vel.y:F} {vel.z:F}\n" +
$"- Angular velocity: {ave.x:F} {ave.y:F} {ave.z:F}\n" +
$"- Mass: {player.Mass:F}\n" +
$"- Health: {player.CurrentHealth:F} / {player.InitialHealth:F}";
}
private IEnumerable<SimBody> GetSimBodies(Block[] blocks)
=> blocks.Select(block => block.GetSimBody()).Distinct();
public override void OnApplicationQuit() => Main.Shutdown();
public override string Name { get; } = "BuildingTools";
public override string Version { get; } = "v1.0.0";
}
}