PJ/Assets/Editor/LPJConverterEditor.cs

198 lines
No EOL
7.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
}
}
}