|
|
@@ -17,20 +17,27 @@ namespace BlockMod |
|
|
|
{ |
|
|
|
public class BlockMod : IEnhancedPlugin |
|
|
|
{ |
|
|
|
private Block[] blocks = new Block[0]; |
|
|
|
private Block refBlock; |
|
|
|
private readonly CommandUtils _commandUtils; |
|
|
|
private readonly BlockSelections _blockSelections; |
|
|
|
|
|
|
|
public BlockMod() |
|
|
|
{ |
|
|
|
_blockSelections = new BlockSelections(); |
|
|
|
_commandUtils = new CommandUtils(_blockSelections); |
|
|
|
} |
|
|
|
|
|
|
|
public override void OnApplicationStart() |
|
|
|
{ |
|
|
|
Main.Init(); |
|
|
|
GameClient.SetDebugInfo("PlayerInfo", GetPlayerInfo); |
|
|
|
GameClient.SetDebugInfo("BlockModInfo", GetBlockInfo); |
|
|
|
RegisterBlockCommand("scaleBlocks", |
|
|
|
"Scales the blocks you're looking at, 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.", |
|
|
|
_commandUtils.RegisterBlockCommand("scaleBlocks", |
|
|
|
"Scales the selected blocks, relative to current size (current scale * new scale)." + |
|
|
|
" The block you're looking at (when selected based on that) stays where it is, everything else is moved next to it.", |
|
|
|
(scaleX, scaleY, scaleZ, blocks, refBlock) => |
|
|
|
{ |
|
|
|
if (!GameState.IsBuildMode()) return; //Scaling & positioning is weird in simulation |
|
|
|
if (CheckNoBlocks(blocks)) return; |
|
|
|
if (_blockSelections.CheckNoBlocks(blocks)) return; |
|
|
|
// ReSharper disable once PossibleNullReferenceException |
|
|
|
float3 reference = refBlock.Position; |
|
|
|
float3 scale = new float3(scaleX, scaleY, scaleZ); |
|
|
@@ -42,8 +49,8 @@ namespace BlockMod |
|
|
|
|
|
|
|
Logging.CommandLog("Blocks scaled."); |
|
|
|
}); |
|
|
|
RegisterBlockCommand("scaleIndividually", "Scales the blocks you're looking at, but doesn't move them." + |
|
|
|
"The scale is relative, 1 means no change. Look at a block previously scaled to scale all of the blocks that were connected to it.", |
|
|
|
_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 |
|
|
@@ -51,7 +58,7 @@ namespace BlockMod |
|
|
|
foreach (var block in blocks) |
|
|
|
block.Scale *= scale; |
|
|
|
}); |
|
|
|
RegisterBlockCommand("moveBlocks", "Moves the blocks around.", (x, y, z, blocks, refBlock) => |
|
|
|
_commandUtils.RegisterBlockCommand("moveBlocks", "Moves the blocks around.", (x, y, z, blocks, refBlock) => |
|
|
|
{ |
|
|
|
if (GameState.IsBuildMode()) |
|
|
|
foreach (var block in blocks) |
|
|
@@ -60,7 +67,7 @@ namespace BlockMod |
|
|
|
foreach (var body in GetSimBodies(blocks)) |
|
|
|
body.Position += new float3(x, y, z); |
|
|
|
}); |
|
|
|
RegisterBlockCommand("colorBlocks", "Colors the blocks you're looking at", |
|
|
|
_commandUtils.RegisterBlockCommand("colorBlocks", "Colors the blocks you're looking at", |
|
|
|
(color, darkness, blocks, refBlock) => |
|
|
|
{ |
|
|
|
|
|
|
@@ -75,34 +82,36 @@ namespace BlockMod |
|
|
|
|
|
|
|
CommandBuilder.Builder("selectBlocksLookedAt", |
|
|
|
"Selects blocks (1 or more) to change. Only works in build mode, however the blocks can be changed afterwards." + |
|
|
|
" Paramter: whether one (true) or all connected (false) blocks should be selected.") |
|
|
|
" Parameter: whether one (true) or all connected (false) blocks should be selected.") |
|
|
|
.Action<bool>(single => |
|
|
|
{ |
|
|
|
refBlock = new Player(PlayerType.Local).GetBlockLookedAt(); |
|
|
|
blocks = single ? new[] {refBlock} : refBlock?.GetConnectedCubes() ?? new Block[0]; |
|
|
|
_blockSelections.refBlock = new Player(PlayerType.Local).GetBlockLookedAt(); |
|
|
|
var refBlock = _blockSelections.refBlock; |
|
|
|
_blockSelections.blocks = single ? new[] {refBlock} : refBlock?.GetConnectedCubes() ?? new Block[0]; |
|
|
|
var blocks = _blockSelections.blocks; |
|
|
|
Logging.CommandLog(blocks == null ? "Selection cleared." : blocks.Length + " blocks selected."); |
|
|
|
}).Build(); |
|
|
|
CommandBuilder.Builder("selectBlocksWithID", "Selects blocks with a specific object ID.") |
|
|
|
.Action<char>(id => |
|
|
|
blocks = (refBlock = ObjectIdentifier.GetByID(id).FirstOrDefault())?.GetConnectedCubes() ?? |
|
|
|
new Block[0]).Build(); |
|
|
|
_blockSelections.blocks = (_blockSelections.refBlock = ObjectIdentifier.GetByID(id).FirstOrDefault()) |
|
|
|
?.GetConnectedCubes() ?? new Block[0]).Build(); |
|
|
|
CommandBuilder.Builder("selectSelectedBlocks", "Selects blocks that are box selected by the player.") |
|
|
|
.Action(() => |
|
|
|
{ |
|
|
|
blocks = new Player(PlayerType.Local).GetSelectedBlocks(); |
|
|
|
refBlock = blocks.Length > 0 ? blocks[0] : null; |
|
|
|
_blockSelections.blocks = new Player(PlayerType.Local).GetSelectedBlocks(); |
|
|
|
_blockSelections.refBlock = _blockSelections.blocks.Length > 0 ? _blockSelections.blocks[0] : null; |
|
|
|
}).Build(); |
|
|
|
|
|
|
|
ConsoleCommands.RegisterWithChannel("selectSendSignal", ch => { }, ChannelType.Object, |
|
|
|
"Sends a signal for selecting a given object ID for a command block."); |
|
|
|
|
|
|
|
RegisterBlockCommand("pushBlocks", "Adds velocity to the selected blocks. Only works in simulation.", |
|
|
|
_commandUtils.RegisterBlockCommand("pushBlocks", "Adds velocity to the selected blocks. Only works in simulation.", |
|
|
|
(x, y, z, blocks, refBlock) => |
|
|
|
{ |
|
|
|
foreach (var block in GetSimBodies(blocks)) |
|
|
|
block.Velocity += new float3(x, y, z); |
|
|
|
}); |
|
|
|
RegisterBlockCommand("pushRotateBlocks", |
|
|
|
_commandUtils.RegisterBlockCommand("pushRotateBlocks", |
|
|
|
"Adds angular velocity to the selected blocks. Only works in simulation.", |
|
|
|
(x, y, z, blocks, refBlock) => |
|
|
|
{ |
|
|
@@ -133,7 +142,7 @@ namespace BlockMod |
|
|
|
|
|
|
|
private static string GetBlockInfoInBuildMode() |
|
|
|
{ |
|
|
|
var block = new Player(PlayerType.Local).GetBlockLookedAt(); |
|
|
|
var block = Player.LocalPlayer.GetBlockLookedAt(); |
|
|
|
if (block == null) return ""; |
|
|
|
float3 pos = block.Position; |
|
|
|
float3 rot = block.Rotation; |
|
|
@@ -148,7 +157,7 @@ namespace BlockMod |
|
|
|
|
|
|
|
private static string GetBodyInfoInSimMode() |
|
|
|
{ |
|
|
|
var body = new Player(PlayerType.Local).GetSimBodyLookedAt(); |
|
|
|
var body = Player.LocalPlayer.GetSimBodyLookedAt(); |
|
|
|
if (body == null) return GetBlockInfoInBuildMode(); |
|
|
|
float3 pos = body.Position; |
|
|
|
float3 rot = body.Rotation; |
|
|
@@ -166,115 +175,26 @@ namespace BlockMod |
|
|
|
$"- Cluster health: {cluster?.CurrentHealth:F} / {cluster?.InitialHealth:F} - Multiplier: {cluster?.HealthMultiplier:F}"; |
|
|
|
} |
|
|
|
|
|
|
|
private bool CheckNoBlocks(Block[] blocks) |
|
|
|
private string GetPlayerInfo() |
|
|
|
{ |
|
|
|
if (blocks.Length == 0) |
|
|
|
{ |
|
|
|
Logging.CommandLogWarning("No blocks selected. Use selectBlocks first."); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
var body = Player.LocalPlayer; |
|
|
|
if (body == null) return GetBlockInfoInBuildMode(); |
|
|
|
float3 pos = body.Position; |
|
|
|
float3 rot = body.Rotation; |
|
|
|
float3 vel = body.Velocity; |
|
|
|
float3 ave = body.AngularVelocity; |
|
|
|
return $"You are 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" + |
|
|
|
$"- Mass: {body.Mass:F}\n" + |
|
|
|
$"- Health: {body.CurrentHealth:F} / {body.InitialHealth:F}"; |
|
|
|
} |
|
|
|
|
|
|
|
private IEnumerable<SimBody> GetSimBodies(Block[] blocks) |
|
|
|
=> blocks.Select(block => block.GetSimBody()).Distinct(); |
|
|
|
|
|
|
|
private Block[] SelectBlocks(byte id) |
|
|
|
{ |
|
|
|
var blocks = ObjectIdentifier.GetBySimID(id).SelectMany(block => block.GetConnectedCubes()).ToArray(); |
|
|
|
return blocks; |
|
|
|
} |
|
|
|
|
|
|
|
private Block[] SelectBlocks(char id) |
|
|
|
{ |
|
|
|
var blocks = ObjectIdentifier.GetByID(id).SelectMany(oid => oid.GetConnectedCubes()) |
|
|
|
.ToArray(); |
|
|
|
return blocks; |
|
|
|
} |
|
|
|
|
|
|
|
private void RegisterBlockCommandInternal(string name, string desc, Action<string, Block[], Block> action) |
|
|
|
{ |
|
|
|
RuntimeCommands.Register<string>(name, a1 => |
|
|
|
{ |
|
|
|
action(a1, blocks, refBlock); |
|
|
|
}, desc); |
|
|
|
ConsoleCommands.RegisterWithChannel<string>(name, (a1, ch) => |
|
|
|
{ |
|
|
|
Console.WriteLine($"Command {name} with args {a1} and channel {ch} executing"); |
|
|
|
var blks = SelectBlocks(ch); |
|
|
|
action(a1, blks, blks[0]); |
|
|
|
}, ChannelType.Object, desc); |
|
|
|
} |
|
|
|
|
|
|
|
private void RegisterBlockCommand(string name, string desc, Action<float, float, float, Block[], Block> action) |
|
|
|
{ |
|
|
|
RegisterBlockCommandInternal(name, desc, (args, bs, b) => |
|
|
|
{ |
|
|
|
var argsa = args.Split(' '); |
|
|
|
if (argsa.Length < 3) |
|
|
|
{ |
|
|
|
Log.Error("Too few arguments. Needed arguments are: <x> <y> <z> and [id] is optional."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!float.TryParse(argsa[0], out float x) || !float.TryParse(argsa[1], out float y) || |
|
|
|
!float.TryParse(argsa[2], out float z)) |
|
|
|
{ |
|
|
|
Log.Error("Could not parse arguments as floats."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (argsa.Length > 3) |
|
|
|
{ |
|
|
|
if (argsa[3].Length == 0) |
|
|
|
{ |
|
|
|
Log.Error("Missing channel."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var blocks = SelectBlocks(argsa[3][0]); |
|
|
|
if (CheckNoBlocks(blocks)) return; |
|
|
|
action(x, y, z, blocks, blocks[0]); |
|
|
|
} |
|
|
|
else if (!CheckNoBlocks(bs)) |
|
|
|
action(x, y, z, bs, b); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private void RegisterBlockCommand(string name, string desc, Action<string, byte, Block[], Block> action) |
|
|
|
{ |
|
|
|
RegisterBlockCommandInternal(name, desc, (args, bs, b) => |
|
|
|
{ |
|
|
|
var argsa = args.Split(' '); |
|
|
|
if (argsa.Length < 2) |
|
|
|
{ |
|
|
|
Log.Error("Too few arguments. Needed arguments are: <color> <darkness> and [id] is optional."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!byte.TryParse(argsa[1], out byte darkness)) |
|
|
|
{ |
|
|
|
Log.Error("Could not parse color darkness."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (argsa.Length > 2) |
|
|
|
{ |
|
|
|
if (argsa[2].Length == 0) |
|
|
|
{ |
|
|
|
Log.Error("Missing channel."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var blocks = SelectBlocks(argsa[2][0]); |
|
|
|
if (CheckNoBlocks(blocks)) return; |
|
|
|
action(argsa[0], darkness, blocks, blocks[0]); |
|
|
|
} |
|
|
|
else if(!CheckNoBlocks(bs)) |
|
|
|
action(argsa[0], darkness, bs, b); |
|
|
|
}); |
|
|
|
} |
|
|
|
public override void OnApplicationQuit() => Main.Shutdown(); |
|
|
|
|
|
|
|
public override string Name { get; } = "BlockMod"; |
|
|
|
public override string Version { get; } = "v1.0.0"; |
|
|
|