using Sandbox.Definitions;
using Sandbox.ModAPI;
using System.Text;
using VRage.Game;
using VRage.Game.ModAPI;
using VRage.Utils;
using VRageMath;
namespace SpaceEngineersBlueprintEditor.SpaceEngineersCore.GridConverter;
public class GridExportHelper
{
private const float MAX_DISTANCE = 1000;
private const string SEPARATOR = "|";
private const string FILE_PREFIX = "GridExport_";
private const string FILE_TYPE = ".txt";
private const float UNIFIED_SIZE = 0.25f;
private const string DEFAULT_LARGE_BLOCK = "2eacbbf2-d8fb-4a78-91dc-7b492517ef97";
private const string DEFAULT_SMALL_BLOCK = "632d7385-12b9-47a6-802a-a610d0cbd1e0";
private List<IMySlimBlock> _blocks = new List<IMySlimBlock>();
private HashSet<MyDefinitionId> _unrecognizedBlocks = new HashSet<MyDefinitionId>();
private MyStringId _debugMaterial = MyStringId.GetOrCompute("Square");
private Vector4 _forwardColor = new Vector4(0, 0, 10, 10);
private Vector4 _upColor = new Vector4(0, 10, 0, 10);
private Vector4 _rightColor = new Vector4(10, 0, 0, 10);
private const float LINE_THICKNESS = 0.01f;
private ConversionDefinitions _definitions;
/// <summary>
/// Exports the grid to a text file
/// </summary>
/// <param name="grid"></param>
/// <param name="replaceUnknownBlocks">Unknown blocks will be replaced with armor unless told to skip</param>
/// /// <param name="replacePhysicless">Unknown blocks without physics will be replaced with armor unless told to skip</param>
public void ExportGrid(IMyCubeGrid grid, string blueprintName, Action<string> showMessage, bool replaceUnknownBlocks = true, bool replacePhysicless = false)
{
_blocks.Clear();
_unrecognizedBlocks.Clear();
grid.GetBlocks(_blocks);
StringBuilder export = new StringBuilder();
MyAPIGateway.Parallel.Start(() =>
{
foreach (var block in _blocks)
{
if (_definitions.BlackList.Contains(block.BlockDefinition.Id))
continue;
MyCubeBlockDefinition blockDefinition = block.BlockDefinition as MyCubeBlockDefinition;
BlockConversionDefinition conversionDefinition;
bool knownBlock = _definitions.BlockTypes.Dictionary.TryGetValue(block.BlockDefinition.Id, out conversionDefinition);
int gridToUniform = (int)(grid.GridSize / UNIFIED_SIZE);
if (!knownBlock && _unrecognizedBlocks.Add(block.BlockDefinition.Id))
{
showMessage($"Did not recognize block '{block.BlockDefinition.Id}'");
}
if (!knownBlock && !replaceUnknownBlocks || !knownBlock && replaceUnknownBlocks && !blockDefinition.HasPhysics && !replacePhysicless)
continue;
/*
* Follows the format of
* BlockId|PositionX|PositionY|PositionZ|ColorHUE|ColorSATURATION|ColorVALUE|OrientationFORWARD|OrientationUP|Integrity|
*/
Vector3 color = MyColorPickerConstants.HSVOffsetToHSV(block.ColorMaskHSV);
MyBlockOrientation orientation;
MatrixI matrix = MatrixI.CreateRotation(Base6Directions.Direction.Forward, Base6Directions.Direction.Up, block.Orientation.Forward, block.Orientation.Up);
Vector3I size = blockDefinition.Size * gridToUniform;
Vector3 minOffset = (size - 1) / 2f;
Vector3 maxOffset = size / 2f;
if (knownBlock)
{
foreach (var conversion in conversionDefinition.Blocks)
{
Quaternion quaternion;
orientation = block.Orientation;
orientation.GetQuaternion(out quaternion);
if (!Quaternion.IsZero(conversion.Rotation))
{
quaternion *= conversion.Rotation;
orientation.Forward = Base6Directions.GetForward(quaternion);
orientation.Up = Base6Directions.GetUp(quaternion);
}
if (!orientation.IsValid)
{
showMessage($"Invalid rotation for block {block.BlockDefinition.Id} F:'{orientation.Forward}' U:'{orientation.Up}'");
continue;
}
Vector3I transformSize = Vector3I.Transform(size, quaternion);
Vector3 minOffsetTransformed = Vector3.Transform(minOffset, quaternion);
Vector3 maxOffsetTransformed = Vector3.Transform(maxOffset, quaternion);
Vector3I offset = Vector3I.Round(minOffset - minOffsetTransformed) - Vector3I.Round(maxOffset - maxOffsetTransformed);
Vector3I forwardOffset = Vector3I.TransformNormal(Vector3I.Forward * conversion.ForwardOffset, ref matrix);
Vector3I upOffset = Vector3I.TransformNormal(Vector3I.Up * conversion.UpOffset, ref matrix);
Vector3I rightOffset = Vector3I.TransformNormal(Vector3I.Right * conversion.RightOffset, ref matrix);
Vector3I origin = Vector3I.Round((block.Min * gridToUniform + block.Max * gridToUniform) / 2f) - offset + forwardOffset + upOffset + rightOffset;
export.Append(conversion.BlockServerPrefab + SEPARATOR);
export.Append(origin.X + SEPARATOR + origin.Y + SEPARATOR + origin.Z + SEPARATOR);
export.Append(color.X + SEPARATOR + color.Y + SEPARATOR + color.Z + SEPARATOR);
export.Append((int)orientation.Forward + SEPARATOR + (int)orientation.Up + SEPARATOR);
export.Append(block.Integrity / block.MaxIntegrity + SEPARATOR);
export.AppendLine();
}
}
else if (replaceUnknownBlocks)
{
string prefab;
if (grid.GridSizeEnum == MyCubeSize.Large)
prefab = DEFAULT_LARGE_BLOCK;
else
prefab = DEFAULT_SMALL_BLOCK;
for (int x = block.Min.X; x <= block.Max.X; x++)
{
for (int y = block.Min.Y; y <= block.Max.Y; y++)
{
for (int z = block.Min.Z; z <= block.Max.Z; z++)
{
Vector3I origin = new Vector3I(x, y, z) * gridToUniform;
export.Append(prefab + SEPARATOR);
export.Append(origin.X + SEPARATOR + origin.Y + SEPARATOR + origin.Z + SEPARATOR);
export.Append(color.X + SEPARATOR + color.Y + SEPARATOR + color.Z + SEPARATOR);
export.Append((int)Base6Directions.Direction.Forward + SEPARATOR + (int)Base6Directions.Direction.Up + SEPARATOR);
export.Append(block.Integrity / block.MaxIntegrity + SEPARATOR);
export.AppendLine();
}
}
}
}
}
try
{
string fileName = FILE_PREFIX + blueprintName + FILE_TYPE;
TextWriter writer = MyAPIGateway.Utilities.WriteFileInGlobalStorage(fileName);
writer.Write(export);
writer.Close();
showMessage($"Saved grid to '{MyAPIGateway.Utilities.GamePaths.UserDataPath + "\\Storage\\" + fileName}'");
}
catch (Exception e)
{
showMessage("Encountered an exception when writing to storage, see log.");
MyLog.Default.WriteLine(e.ToString());
}
});
}
}
using Sandbox.Definitions;
using Sandbox.ModAPI;
using System.Text;
using VRage.Game;
using VRage.Game.ModAPI;
using VRage.Utils;
using VRageMath;
namespace SpaceEngineersBlueprintEditor.SpaceEngineersCore.GridConverter;
public class GridExportHelper
{
private const float MAX_DISTANCE = 1000;
private const string SEPARATOR = "|";
private const string FILE_PREFIX = "GridExport_";
private const string FILE_TYPE = ".txt";
private const float UNIFIED_SIZE = 0.25f;
private const string DEFAULT_LARGE_BLOCK = "2eacbbf2-d8fb-4a78-91dc-7b492517ef97";
private const string DEFAULT_SMALL_BLOCK = "632d7385-12b9-47a6-802a-a610d0cbd1e0";
private List<IMySlimBlock> _blocks = new List<IMySlimBlock>();
private HashSet<MyDefinitionId> _unrecognizedBlocks = new HashSet<MyDefinitionId>();
private MyStringId _debugMaterial = MyStringId.GetOrCompute("Square");
private Vector4 _forwardColor = new Vector4(0, 0, 10, 10);
private Vector4 _upColor = new Vector4(0, 10, 0, 10);
private Vector4 _rightColor = new Vector4(10, 0, 0, 10);
private const float LINE_THICKNESS = 0.01f;
private ConversionDefinitions _definitions;
/// <summary>
/// Exports the grid to a text file
/// </summary>
/// <param name="grid"></param>
/// <param name="replaceUnknownBlocks">Unknown blocks will be replaced with armor unless told to skip</param>
/// /// <param name="replacePhysicless">Unknown blocks without physics will be replaced with armor unless told to skip</param>
public void ExportGrid(IMyCubeGrid grid, string blueprintName, Action<string> showMessage, bool replaceUnknownBlocks = true, bool replacePhysicless = false)
{
_blocks.Clear();
_unrecognizedBlocks.Clear();
grid.GetBlocks(_blocks);
StringBuilder export = new StringBuilder();
MyAPIGateway.Parallel.Start(() =>
{
foreach (var block in _blocks)
{
if (_definitions.BlackList.Contains(block.BlockDefinition.Id))
continue;
MyCubeBlockDefinition blockDefinition = block.BlockDefinition as MyCubeBlockDefinition;
BlockConversionDefinition conversionDefinition;
bool knownBlock = _definitions.BlockTypes.Dictionary.TryGetValue(block.BlockDefinition.Id, out conversionDefinition);
int gridToUniform = (int)(grid.GridSize / UNIFIED_SIZE);
if (!knownBlock && _unrecognizedBlocks.Add(block.BlockDefinition.Id))
{
showMessage($"Did not recognize block '{block.BlockDefinition.Id}'");
}
if (!knownBlock && !replaceUnknownBlocks || !knownBlock && replaceUnknownBlocks && !blockDefinition.HasPhysics && !replacePhysicless)
continue;
/*
* Follows the format of
* BlockId|PositionX|PositionY|PositionZ|ColorHUE|ColorSATURATION|ColorVALUE|OrientationFORWARD|OrientationUP|Integrity|
*/
Vector3 color = MyColorPickerConstants.HSVOffsetToHSV(block.ColorMaskHSV);
MyBlockOrientation orientation;
MatrixI matrix = MatrixI.CreateRotation(Base6Directions.Direction.Forward, Base6Directions.Direction.Up, block.Orientation.Forward, block.Orientation.Up);
Vector3I size = blockDefinition.Size * gridToUniform;
Vector3 minOffset = (size - 1) / 2f;
Vector3 maxOffset = size / 2f;
if (knownBlock)
{
foreach (var conversion in conversionDefinition.Blocks)
{
Quaternion quaternion;
orientation = block.Orientation;
orientation.GetQuaternion(out quaternion);
if (!Quaternion.IsZero(conversion.Rotation))
{
quaternion *= conversion.Rotation;
orientation.Forward = Base6Directions.GetForward(quaternion);
orientation.Up = Base6Directions.GetUp(quaternion);
}
if (!orientation.IsValid)
{
showMessage($"Invalid rotation for block {block.BlockDefinition.Id} F:'{orientation.Forward}' U:'{orientation.Up}'");
continue;
}
Vector3I transformSize = Vector3I.Transform(size, quaternion);
Vector3 minOffsetTransformed = Vector3.Transform(minOffset, quaternion);
Vector3 maxOffsetTransformed = Vector3.Transform(maxOffset, quaternion);
Vector3I offset = Vector3I.Round(minOffset - minOffsetTransformed) - Vector3I.Round(maxOffset - maxOffsetTransformed);
Vector3I forwardOffset = Vector3I.TransformNormal(Vector3I.Forward * conversion.ForwardOffset, ref matrix);
Vector3I upOffset = Vector3I.TransformNormal(Vector3I.Up * conversion.UpOffset, ref matrix);
Vector3I rightOffset = Vector3I.TransformNormal(Vector3I.Right * conversion.RightOffset, ref matrix);
Vector3I origin = Vector3I.Round((block.Min * gridToUniform + block.Max * gridToUniform) / 2f) - offset + forwardOffset + upOffset + rightOffset;
export.Append(conversion.BlockServerPrefab + SEPARATOR);
export.Append(origin.X + SEPARATOR + origin.Y + SEPARATOR + origin.Z + SEPARATOR);
export.Append(color.X + SEPARATOR + color.Y + SEPARATOR + color.Z + SEPARATOR);
export.Append((int)orientation.Forward + SEPARATOR + (int)orientation.Up + SEPARATOR);
export.Append(block.Integrity / block.MaxIntegrity + SEPARATOR);
export.AppendLine();
}
}
else if (replaceUnknownBlocks)
{
string prefab;
if (grid.GridSizeEnum == MyCubeSize.Large)
prefab = DEFAULT_LARGE_BLOCK;
else
prefab = DEFAULT_SMALL_BLOCK;
for (int x = block.Min.X; x <= block.Max.X; x++)
{
for (int y = block.Min.Y; y <= block.Max.Y; y++)
{
for (int z = block.Min.Z; z <= block.Max.Z; z++)
{
Vector3I origin = new Vector3I(x, y, z) * gridToUniform;
export.Append(prefab + SEPARATOR);
export.Append(origin.X + SEPARATOR + origin.Y + SEPARATOR + origin.Z + SEPARATOR);
export.Append(color.X + SEPARATOR + color.Y + SEPARATOR + color.Z + SEPARATOR);
export.Append((int)Base6Directions.Direction.Forward + SEPARATOR + (int)Base6Directions.Direction.Up + SEPARATOR);
export.Append(block.Integrity / block.MaxIntegrity + SEPARATOR);
export.AppendLine();
}
}
}
}
}
try
{
string fileName = FILE_PREFIX + blueprintName + FILE_TYPE;
TextWriter writer = MyAPIGateway.Utilities.WriteFileInGlobalStorage(fileName);
writer.Write(export);
writer.Close();
showMessage($"Saved grid to '{MyAPIGateway.Utilities.GamePaths.UserDataPath + "\\Storage\\" + fileName}'");
}
catch (Exception e)
{
showMessage("Encountered an exception when writing to storage, see log.");
MyLog.Default.WriteLine(e.ToString());
}
});
}
}