XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
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());
            }
        });
    }
}