using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using Sandbox.Game.Entities;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame;
using VRageMath;
using Terminal = Sandbox.ModAPI.Ingame.IMyTerminalBlock;
namespace XFE.SeAgent.Plugin.Game
{
public sealed partial class GameDebugApi
{
private JObject ListGrids(JObject args)
{
var grids = MyEntities.GetEntities().OfType<MyCubeGrid>().Where(g => !g.Closed).OrderBy(g => g.EntityId).ToList();
string name = (string)args["name"];
if (!string.IsNullOrEmpty(name)) grids = grids.Where(g => (g.DisplayName ?? "").IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
int offset = Math.Max(0, (int?)args["offset"] ?? 0);
var items = new JArray(grids.Skip(offset).Take(Limit(args)).Select(DescribeGrid));
return new JObject { ["grids"] = items, ["total"] = grids.Count, ["offset"] = offset, ["truncated"] = offset + items.Count < grids.Count };
}
private static JObject DescribeGrid(MyCubeGrid grid)
{
var result = new JObject { ["entityId"] = Sid(grid.EntityId), ["name"] = grid.DisplayName, ["isStatic"] = grid.IsStatic,
["gridSize"] = grid.GridSize, ["blockCount"] = grid.GetBlocks().Count, ["pose"] = Pose(grid.WorldMatrix), ["bounds"] = Bounds(grid.PositionComp.WorldAABB) };
if (grid.Physics != null)
{
result["linearVelocity"] = Vec(grid.Physics.LinearVelocity);
result["angularVelocity"] = Vec(grid.Physics.AngularVelocity);
result["speed"] = grid.Physics.LinearVelocity.Length();
}
return result;
}
private IEnumerable<Terminal> SelectBlocks(JObject args)
{
if (args["entityIds"] is JArray ids)
{
if (ids.Count > 256) throw new ArgumentException("entityIds accepts at most 256 blocks.");
return ids.Select(id => Block(Id(new JObject { ["id"] = id.DeepClone() }, "id"))).Distinct().ToList();
}
IEnumerable<MyCubeGrid> grids = args["gridId"] != null ? new[] { Grid(Id(args, "gridId")) } : MyEntities.GetEntities().OfType<MyCubeGrid>();
IEnumerable<Terminal> blocks = grids.Where(g => !g.Closed).SelectMany(g => g.GetFatBlocks().OfType<Terminal>()).Where(b => !b.Closed);
string name = (string)args["name"], type = (string)args["type"];
if (!string.IsNullOrEmpty(name)) blocks = blocks.Where(b => (b.CustomName ?? "").IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0);
if (!string.IsNullOrEmpty(type)) blocks = blocks.Where(b => b.BlockDefinition.TypeIdString.IndexOf(type, StringComparison.OrdinalIgnoreCase) >= 0 || b.BlockDefinition.SubtypeName.IndexOf(type, StringComparison.OrdinalIgnoreCase) >= 0);
return blocks.OrderBy(b => b.EntityId);
}
private JObject ListBlocks(JObject args)
{
var blocks = SelectBlocks(args).ToList();
int offset = Math.Max(0, (int?)args["offset"] ?? 0);
var array = new JArray(blocks.Skip(offset).Take(Limit(args)).Select(b => DescribeBlock(b, false)));
return new JObject { ["blocks"] = array, ["total"] = blocks.Count, ["offset"] = offset, ["truncated"] = offset + array.Count < blocks.Count };
}
private static JObject DescribeBlock(Terminal block, bool details)
{
var result = new JObject { ["entityId"] = Sid(block.EntityId), ["gridId"] = Sid(block.CubeGrid.EntityId), ["name"] = block.CustomName,
["type"] = block.BlockDefinition.TypeIdString, ["subtype"] = block.BlockDefinition.SubtypeName, ["functional"] = block.IsFunctional,
["working"] = block.IsWorking, ["ownerId"] = Sid(block.OwnerId), ["positionInGrid"] = Vec(block.Position), ["pose"] = Pose(block.WorldMatrix),
["bounds"] = Bounds(block.WorldAABB), ["inventoryCount"] = block.InventoryCount };
if (block is IMyFunctionalBlock functional) result["enabled"] = functional.Enabled;
if (details) { result["customData"] = block.CustomData ?? ""; result["detailedInfo"] = Clip(block.DetailedInfo, 32768); result["customInfo"] = Clip(block.CustomInfo, 32768); }
return result;
}
private JObject Telemetry(JObject args)
{
int limit = Limit(args, 256, 1024);
var selected = SelectBlocks(args).ToList();
var blocks = selected.Take(limit).ToList();
var result = new JArray();
foreach (var block in blocks)
{
var item = DescribeBlock(block, false);
try { AddTelemetry(item, block, (bool?)args["includeInventoryItems"] ?? true, (bool?)args["includeScreens"] ?? true); }
catch (Exception error) { item["telemetryError"] = error.GetType().Name + ": " + error.Message; }
result.Add(item);
}
var grids = blocks.Select(b => b.CubeGrid.EntityId).Distinct().Select(id => DescribeGrid(Grid(id)));
return new JObject { ["utc"] = DateTime.UtcNow, ["frame"] = RequireWorld().GameplayFrameCounter, ["grids"] = new JArray(grids), ["blocks"] = result, ["total"] = selected.Count, ["truncated"] = selected.Count > limit };
}
private static void AddTelemetry(JObject item, Terminal block, bool includeInventoryItems, bool includeScreens)
{
if (block is IMyBatteryBlock battery) item["battery"] = new JObject { ["storedMWh"] = battery.CurrentStoredPower, ["maxStoredMWh"] = battery.MaxStoredPower, ["inputMW"] = battery.CurrentInput, ["outputMW"] = battery.CurrentOutput, ["chargeMode"] = battery.ChargeMode.ToString(), ["charging"] = battery.IsCharging };
if (block is IMyThrust thrust) item["thrust"] = new JObject { ["currentN"] = thrust.CurrentThrust, ["maximumN"] = thrust.MaxThrust, ["maxEffectiveN"] = thrust.MaxEffectiveThrust, ["overrideN"] = thrust.ThrustOverride, ["overrideRatio"] = thrust.ThrustOverridePercentage, ["gridDirection"] = Vec(thrust.GridThrustDirection), ["forceDirection"] = Vec(thrust.WorldMatrix.Backward) };
if (block is IMyGyro gyro) item["gyro"] = new JObject { ["override"] = gyro.GyroOverride, ["power"] = gyro.GyroPower, ["yaw"] = gyro.Yaw, ["pitch"] = gyro.Pitch, ["roll"] = gyro.Roll };
if (block is IMyShipConnector connector) item["connector"] = new JObject { ["status"] = connector.Status.ToString(), ["otherConnectorId"] = connector.OtherConnector == null ? null : Sid(connector.OtherConnector.EntityId), ["throwOut"] = connector.ThrowOut, ["collectAll"] = connector.CollectAll, ["pullStrength"] = connector.PullStrength };
if (block is IMyCameraBlock camera) item["camera"] = new JObject { ["enabledRaycast"] = camera.EnableRaycast, ["availableScanRange"] = camera.AvailableScanRange, ["coneLimitDegrees"] = camera.RaycastConeLimit, ["distanceLimit"] = camera.RaycastDistanceLimit };
if (block is IMyGasTank tank) item["gasTank"] = new JObject { ["capacity"] = tank.Capacity, ["filledRatio"] = tank.FilledRatio, ["stockpile"] = tank.Stockpile };
if (block is IMyShipController controller)
{
var velocities = controller.GetShipVelocities(); var mass = controller.CalculateShipMass();
item["flight"] = new JObject { ["linearVelocity"] = Vec(velocities.LinearVelocity), ["angularVelocity"] = Vec(velocities.AngularVelocity),
["speed"] = controller.GetShipSpeed(), ["naturalGravity"] = Vec(controller.GetNaturalGravity()), ["artificialGravity"] = Vec(controller.GetArtificialGravity()),
["totalMassKg"] = mass.TotalMass, ["physicalMassKg"] = mass.PhysicalMass, ["baseMassKg"] = mass.BaseMass,
["centerOfMass"] = Vec(controller.CenterOfMass), ["dampeners"] = controller.DampenersOverride, ["underControl"] = controller.IsUnderControl,
["controlThrusters"] = controller.ControlThrusters, ["moveIndicator"] = Vec(controller.MoveIndicator), ["rotationIndicator"] = new JObject { ["x"] = controller.RotationIndicator.X, ["y"] = controller.RotationIndicator.Y }, ["rollIndicator"] = controller.RollIndicator };
}
if (block is Sandbox.ModAPI.IMyProgrammableBlock pb)
{
var instance = PbField(pb, "m_instance") as Sandbox.ModAPI.IMyGridProgram;
item["programmableBlock"] = new JObject { ["sha256"] = Sha(pb.ProgramData), ["compileErrors"] = pb.HasCompileErrors, ["hasInstance"] = instance != null,
["runtime"] = instance == null ? null : Runtime(instance.Runtime), ["echo"] = Clip(PbField(pb, "m_echoOutput")?.ToString(), 8192), ["terminationReason"] = PbField(pb, "m_terminationReason")?.ToString() };
}
if (block.HasInventory)
{
var inventories = new JArray();
for (int i = 0; i < Math.Min(block.InventoryCount, 16); i++)
{
var inventory = block.GetInventory(i);
var inv = new JObject { ["index"] = i, ["massKg"] = (double)inventory.CurrentMass, ["volumeM3"] = (double)inventory.CurrentVolume, ["maxVolumeM3"] = (double)inventory.MaxVolume, ["itemCount"] = inventory.ItemCount };
if (includeInventoryItems)
{
var items = new List<MyInventoryItem>(); inventory.GetItems(items, null);
inv["items"] = new JArray(items.Take(128).Select(value => new JObject { ["itemId"] = value.ItemId, ["type"] = value.Type.TypeId, ["subtype"] = value.Type.SubtypeId, ["amount"] = (double)value.Amount }));
inv["truncated"] = items.Count > 128;
}
inventories.Add(inv);
}
item["inventories"] = inventories;
item["cargoInventory"] = block is IMyCargoContainer || block is IMyShipDrill || block is IMyShipConnector;
}
if (includeScreens)
{
var screens = new JArray();
if (block is IMyTextSurfaceProvider provider) for (int i = 0; i < Math.Min(provider.SurfaceCount, 16); i++) screens.Add(Surface(provider.GetSurface(i), i));
else if (block is IMyTextSurface surface) screens.Add(Surface(surface, 0));
if (screens.Count > 0) item["screens"] = screens;
}
}
private static JObject Surface(IMyTextSurface surface, int index)
{
return new JObject { ["index"] = index, ["name"] = surface.Name, ["displayName"] = surface.DisplayName, ["contentType"] = surface.ContentType.ToString(), ["text"] = Clip(surface.GetText(), 8192), ["script"] = surface.Script, ["surfaceSize"] = new JObject { ["x"] = surface.SurfaceSize.X, ["y"] = surface.SurfaceSize.Y } };
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using Sandbox.Game.Entities;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame;
using VRageMath;
using Terminal = Sandbox.ModAPI.Ingame.IMyTerminalBlock;
namespace XFE.SeAgent.Plugin.Game
{
public sealed partial class GameDebugApi
{
private JObject ListGrids(JObject args)
{
var grids = MyEntities.GetEntities().OfType<MyCubeGrid>().Where(g => !g.Closed).OrderBy(g => g.EntityId).ToList();
string name = (string)args["name"];
if (!string.IsNullOrEmpty(name)) grids = grids.Where(g => (g.DisplayName ?? "").IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
int offset = Math.Max(0, (int?)args["offset"] ?? 0);
var items = new JArray(grids.Skip(offset).Take(Limit(args)).Select(DescribeGrid));
return new JObject { ["grids"] = items, ["total"] = grids.Count, ["offset"] = offset, ["truncated"] = offset + items.Count < grids.Count };
}
private static JObject DescribeGrid(MyCubeGrid grid)
{
var result = new JObject { ["entityId"] = Sid(grid.EntityId), ["name"] = grid.DisplayName, ["isStatic"] = grid.IsStatic,
["gridSize"] = grid.GridSize, ["blockCount"] = grid.GetBlocks().Count, ["pose"] = Pose(grid.WorldMatrix), ["bounds"] = Bounds(grid.PositionComp.WorldAABB) };
if (grid.Physics != null)
{
result["linearVelocity"] = Vec(grid.Physics.LinearVelocity);
result["angularVelocity"] = Vec(grid.Physics.AngularVelocity);
result["speed"] = grid.Physics.LinearVelocity.Length();
}
return result;
}
private IEnumerable<Terminal> SelectBlocks(JObject args)
{
if (args["entityIds"] is JArray ids)
{
if (ids.Count > 256) throw new ArgumentException("entityIds accepts at most 256 blocks.");
return ids.Select(id => Block(Id(new JObject { ["id"] = id.DeepClone() }, "id"))).Distinct().ToList();
}
IEnumerable<MyCubeGrid> grids = args["gridId"] != null ? new[] { Grid(Id(args, "gridId")) } : MyEntities.GetEntities().OfType<MyCubeGrid>();
IEnumerable<Terminal> blocks = grids.Where(g => !g.Closed).SelectMany(g => g.GetFatBlocks().OfType<Terminal>()).Where(b => !b.Closed);
string name = (string)args["name"], type = (string)args["type"];
if (!string.IsNullOrEmpty(name)) blocks = blocks.Where(b => (b.CustomName ?? "").IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0);
if (!string.IsNullOrEmpty(type)) blocks = blocks.Where(b => b.BlockDefinition.TypeIdString.IndexOf(type, StringComparison.OrdinalIgnoreCase) >= 0 || b.BlockDefinition.SubtypeName.IndexOf(type, StringComparison.OrdinalIgnoreCase) >= 0);
return blocks.OrderBy(b => b.EntityId);
}
private JObject ListBlocks(JObject args)
{
var blocks = SelectBlocks(args).ToList();
int offset = Math.Max(0, (int?)args["offset"] ?? 0);
var array = new JArray(blocks.Skip(offset).Take(Limit(args)).Select(b => DescribeBlock(b, false)));
return new JObject { ["blocks"] = array, ["total"] = blocks.Count, ["offset"] = offset, ["truncated"] = offset + array.Count < blocks.Count };
}
private static JObject DescribeBlock(Terminal block, bool details)
{
var result = new JObject { ["entityId"] = Sid(block.EntityId), ["gridId"] = Sid(block.CubeGrid.EntityId), ["name"] = block.CustomName,
["type"] = block.BlockDefinition.TypeIdString, ["subtype"] = block.BlockDefinition.SubtypeName, ["functional"] = block.IsFunctional,
["working"] = block.IsWorking, ["ownerId"] = Sid(block.OwnerId), ["positionInGrid"] = Vec(block.Position), ["pose"] = Pose(block.WorldMatrix),
["bounds"] = Bounds(block.WorldAABB), ["inventoryCount"] = block.InventoryCount };
if (block is IMyFunctionalBlock functional) result["enabled"] = functional.Enabled;
if (details) { result["customData"] = block.CustomData ?? ""; result["detailedInfo"] = Clip(block.DetailedInfo, 32768); result["customInfo"] = Clip(block.CustomInfo, 32768); }
return result;
}
private JObject Telemetry(JObject args)
{
int limit = Limit(args, 256, 1024);
var selected = SelectBlocks(args).ToList();
var blocks = selected.Take(limit).ToList();
var result = new JArray();
foreach (var block in blocks)
{
var item = DescribeBlock(block, false);
try { AddTelemetry(item, block, (bool?)args["includeInventoryItems"] ?? true, (bool?)args["includeScreens"] ?? true); }
catch (Exception error) { item["telemetryError"] = error.GetType().Name + ": " + error.Message; }
result.Add(item);
}
var grids = blocks.Select(b => b.CubeGrid.EntityId).Distinct().Select(id => DescribeGrid(Grid(id)));
return new JObject { ["utc"] = DateTime.UtcNow, ["frame"] = RequireWorld().GameplayFrameCounter, ["grids"] = new JArray(grids), ["blocks"] = result, ["total"] = selected.Count, ["truncated"] = selected.Count > limit };
}
private static void AddTelemetry(JObject item, Terminal block, bool includeInventoryItems, bool includeScreens)
{
if (block is IMyBatteryBlock battery) item["battery"] = new JObject { ["storedMWh"] = battery.CurrentStoredPower, ["maxStoredMWh"] = battery.MaxStoredPower, ["inputMW"] = battery.CurrentInput, ["outputMW"] = battery.CurrentOutput, ["chargeMode"] = battery.ChargeMode.ToString(), ["charging"] = battery.IsCharging };
if (block is IMyThrust thrust) item["thrust"] = new JObject { ["currentN"] = thrust.CurrentThrust, ["maximumN"] = thrust.MaxThrust, ["maxEffectiveN"] = thrust.MaxEffectiveThrust, ["overrideN"] = thrust.ThrustOverride, ["overrideRatio"] = thrust.ThrustOverridePercentage, ["gridDirection"] = Vec(thrust.GridThrustDirection), ["forceDirection"] = Vec(thrust.WorldMatrix.Backward) };
if (block is IMyGyro gyro) item["gyro"] = new JObject { ["override"] = gyro.GyroOverride, ["power"] = gyro.GyroPower, ["yaw"] = gyro.Yaw, ["pitch"] = gyro.Pitch, ["roll"] = gyro.Roll };
if (block is IMyShipConnector connector) item["connector"] = new JObject { ["status"] = connector.Status.ToString(), ["otherConnectorId"] = connector.OtherConnector == null ? null : Sid(connector.OtherConnector.EntityId), ["throwOut"] = connector.ThrowOut, ["collectAll"] = connector.CollectAll, ["pullStrength"] = connector.PullStrength };
if (block is IMyCameraBlock camera) item["camera"] = new JObject { ["enabledRaycast"] = camera.EnableRaycast, ["availableScanRange"] = camera.AvailableScanRange, ["coneLimitDegrees"] = camera.RaycastConeLimit, ["distanceLimit"] = camera.RaycastDistanceLimit };
if (block is IMyGasTank tank) item["gasTank"] = new JObject { ["capacity"] = tank.Capacity, ["filledRatio"] = tank.FilledRatio, ["stockpile"] = tank.Stockpile };
if (block is IMyShipController controller)
{
var velocities = controller.GetShipVelocities(); var mass = controller.CalculateShipMass();
item["flight"] = new JObject { ["linearVelocity"] = Vec(velocities.LinearVelocity), ["angularVelocity"] = Vec(velocities.AngularVelocity),
["speed"] = controller.GetShipSpeed(), ["naturalGravity"] = Vec(controller.GetNaturalGravity()), ["artificialGravity"] = Vec(controller.GetArtificialGravity()),
["totalMassKg"] = mass.TotalMass, ["physicalMassKg"] = mass.PhysicalMass, ["baseMassKg"] = mass.BaseMass,
["centerOfMass"] = Vec(controller.CenterOfMass), ["dampeners"] = controller.DampenersOverride, ["underControl"] = controller.IsUnderControl,
["controlThrusters"] = controller.ControlThrusters, ["moveIndicator"] = Vec(controller.MoveIndicator), ["rotationIndicator"] = new JObject { ["x"] = controller.RotationIndicator.X, ["y"] = controller.RotationIndicator.Y }, ["rollIndicator"] = controller.RollIndicator };
}
if (block is Sandbox.ModAPI.IMyProgrammableBlock pb)
{
var instance = PbField(pb, "m_instance") as Sandbox.ModAPI.IMyGridProgram;
item["programmableBlock"] = new JObject { ["sha256"] = Sha(pb.ProgramData), ["compileErrors"] = pb.HasCompileErrors, ["hasInstance"] = instance != null,
["runtime"] = instance == null ? null : Runtime(instance.Runtime), ["echo"] = Clip(PbField(pb, "m_echoOutput")?.ToString(), 8192), ["terminationReason"] = PbField(pb, "m_terminationReason")?.ToString() };
}
if (block.HasInventory)
{
var inventories = new JArray();
for (int i = 0; i < Math.Min(block.InventoryCount, 16); i++)
{
var inventory = block.GetInventory(i);
var inv = new JObject { ["index"] = i, ["massKg"] = (double)inventory.CurrentMass, ["volumeM3"] = (double)inventory.CurrentVolume, ["maxVolumeM3"] = (double)inventory.MaxVolume, ["itemCount"] = inventory.ItemCount };
if (includeInventoryItems)
{
var items = new List<MyInventoryItem>(); inventory.GetItems(items, null);
inv["items"] = new JArray(items.Take(128).Select(value => new JObject { ["itemId"] = value.ItemId, ["type"] = value.Type.TypeId, ["subtype"] = value.Type.SubtypeId, ["amount"] = (double)value.Amount }));
inv["truncated"] = items.Count > 128;
}
inventories.Add(inv);
}
item["inventories"] = inventories;
item["cargoInventory"] = block is IMyCargoContainer || block is IMyShipDrill || block is IMyShipConnector;
}
if (includeScreens)
{
var screens = new JArray();
if (block is IMyTextSurfaceProvider provider) for (int i = 0; i < Math.Min(provider.SurfaceCount, 16); i++) screens.Add(Surface(provider.GetSurface(i), i));
else if (block is IMyTextSurface surface) screens.Add(Surface(surface, 0));
if (screens.Count > 0) item["screens"] = screens;
}
}
private static JObject Surface(IMyTextSurface surface, int index)
{
return new JObject { ["index"] = index, ["name"] = surface.Name, ["displayName"] = surface.DisplayName, ["contentType"] = surface.ContentType.ToString(), ["text"] = Clip(surface.GetText(), 8192), ["script"] = surface.Script, ["surfaceSize"] = new JObject { ["x"] = surface.SurfaceSize.X, ["y"] = surface.SurfaceSize.Y } };
}
}
}