PJ/Assets/Editor/LPJConverterEditor.cs

198 lines
7.7 KiB
C#
Raw Permalink Normal View History

using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;
public class LPJExporterWindow : EditorWindow
{
private float zoomValue = 1f;
private DefaultAsset sceneFolder;
[MenuItem("Tools/LPJ Batch Exporter")]
public static void ShowWindow()
{
GetWindow<LPJExporterWindow>("LPJ Exporter");
}
private void OnGUI()
{
GUILayout.Label("Настройки экспорта", EditorStyles.boldLabel);
zoomValue = EditorGUILayout.FloatField("Zoom Value", zoomValue);
GUILayout.Space(15);
GUILayout.Label("Режим: Build Settings", EditorStyles.boldLabel);
if (GUILayout.Button("Экспортировать сцены из Build Settings"))
{
ExportBuildSettingsScenes();
}
GUILayout.Space(15);
GUILayout.Label("Режим: Из папки", EditorStyles.boldLabel);
sceneFolder = (DefaultAsset)EditorGUILayout.ObjectField("Папка со сценами", sceneFolder, typeof(DefaultAsset), false);
if (GUILayout.Button("Экспортировать сцены из папки"))
{
if (sceneFolder != null)
{
string folderPath = AssetDatabase.GetAssetPath(sceneFolder);
ExportScenesFromFolder(folderPath);
}
else
{
EditorUtility.DisplayDialog("Ошибка", "Сначала выберите папку со сценами!", "OK");
}
}
}
private void ExportBuildSettingsScenes()
{
List<string> scenePaths = new List<string>();
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
{
if (scene.enabled) scenePaths.Add(scene.path);
}
ProcessScenes(scenePaths.ToArray());
}
private void ExportScenesFromFolder(string folderPath)
{
string[] guids = AssetDatabase.FindAssets("t:Scene", new[] { folderPath });
string[] scenePaths = new string[guids.Length];
for (int i = 0; i < guids.Length; i++)
{
scenePaths[i] = AssetDatabase.GUIDToAssetPath(guids[i]);
}
ProcessScenes(scenePaths);
}
private void ProcessScenes(string[] scenePaths)
{
if (scenePaths.Length == 0)
{
Debug.LogWarning("Сцены для экспорта не найдены.");
return;
}
// Сохраняем текущую открытую сцену, чтобы вернуться к ней после экспорта
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) return;
string originalScenePath = EditorSceneManager.GetActiveScene().path;
int processedCount = 0;
try
{
for (int i = 0; i < scenePaths.Length; i++)
{
EditorUtility.DisplayProgressBar("Экспорт в .lpj", $"Обработка сцены {i + 1}/{scenePaths.Length}: {Path.GetFileNameWithoutExtension(scenePaths[i])}", (float)i / scenePaths.Length);
Scene scene = EditorSceneManager.OpenScene(scenePaths[i], OpenSceneMode.Single);
ExportSingleScene(scene);
processedCount++;
}
}
finally
{
EditorUtility.ClearProgressBar();
// Возвращаемся в исходную сцену
if (!string.IsNullOrEmpty(originalScenePath))
{
EditorSceneManager.OpenScene(originalScenePath, OpenSceneMode.Single);
}
Debug.Log($"<color=green><b>Успешно экспортировано {processedCount} сцен в {Application.persistentDataPath}</b></color>");
EditorUtility.RevealInFinder(Application.persistentDataPath); // Откроет папку в проводнике
}
}
private void ExportSingleScene(Scene scene)
{
List<string> BlockData = new List<string>();
BlockData.Add(scene.name); // Первым элементом идет имя уровня
// Находим все объекты Rtool. (Используем старый метод для совместимости со всеми версиями Unity)
Rtool[] rtools = FindObjectsOfType<Rtool>();
foreach (Rtool o in rtools)
{
List<float> TBD = new List<float>();
TBD.Add(o.gameObject.transform.position.x * zoomValue); // 0
TBD.Add(o.gameObject.transform.position.y * zoomValue); // 1
TBD.Add(o.gameObject.transform.position.z * zoomValue); // 2
TBD.Add(o.gameObject.transform.rotation.x); // 3
TBD.Add(o.gameObject.transform.rotation.y); // 4
TBD.Add(o.gameObject.transform.rotation.z); // 5
TBD.Add(o.gameObject.transform.rotation.w); // 6
TBD.Add(o.BlockID); // 7
if (o.BlockID==10) o.pos1 = o.gameObject.GetComponent<TPBlock>().SecondTeleport.transform.position;
TBD.Add(o.pos1.x * zoomValue); // 8
TBD.Add(o.pos1.y * zoomValue); // 9
TBD.Add(o.pos1.z * zoomValue); // 10
// Защита от выхода за пределы массива (на случай если values не инициализирован или меньше 4 элементов)
float v0 = o.values != null && o.values.Count > 0 ? o.values[0] : 0f;
float v1 = o.values != null && o.values.Count > 1 ? o.values[1] : 0f;
float v2 = o.values != null && o.values.Count > 2 ? o.values[2] : 0f;
float v3 = o.values != null && o.values.Count > 3 ? o.values[3] : 0f;
TBD.AddRange(new List<float> { v0, v1, v2, v3 }); // 11, 12, 13, 14
BlockData.Add(string.Join(", ", TBD));
}
SaveLevelData(BlockData, scene.name);
}
private void SaveLevelData(List<string> BlockData, string name)
{
try
{
byte[] data = ListToBytes(BlockData);
string fileHash = GetSHA256Hash(data);
string correctPath = Path.Combine(Application.persistentDataPath, $"{name}.lpj");
File.WriteAllBytes(correctPath, data);
}
catch (System.Exception e)
{
Debug.LogError($"Save failed for level {BlockData[0]}: {e.Message}");
}
}
private byte[] ListToBytes<T>(List<T> list)
{
// Примечание: BinaryFormatter устарел в новых версиях .NET из-за уязвимостей безопасности.
// Так как это локальный Editor-скрипт и данные формируешь ты сам, это не критично.
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
#pragma warning disable SYSLIB0011 // Подавляем предупреждение об устаревании BinaryFormatter
formatter.Serialize(stream, list);
#pragma warning restore SYSLIB0011
return stream.ToArray();
}
}
private string GetSHA256Hash(byte[] data)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(data);
StringBuilder sb = new StringBuilder();
foreach (byte b in hashBytes)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
}
}