198 lines
No EOL
7.7 KiB
C#
198 lines
No EOL
7.7 KiB
C#
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();
|
||
}
|
||
}
|
||
} |