From 3469e19f0a26b8ff0ff1a0b2c31e6d49dcd5c885 Mon Sep 17 00:00:00 2001 From: techan <50950268+te-chan@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:12:15 +0900 Subject: [PATCH 1/8] 2022.3.62f2 --- Assets/Resources/land.asset | Bin 6551720 -> 6551720 bytes Assets/Resources/water.asset | Bin 3576868 -> 3576868 bytes Packages/manifest.json | 4 ++-- Packages/packages-lock.json | 4 ++-- ProjectSettings/ProjectVersion.txt | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Assets/Resources/land.asset b/Assets/Resources/land.asset index 701f1be71916af181ac654929f75ea734ac33e57..e7d8bd193f33bc0eef9c3a0cae018b94ae32270a 100644 GIT binary patch delta 378 zcmWN=M=t{a0EXe9_TGC_wW%8Q+G@8oYj5IzNPKZ5F790V2gKE1a&+@O$&>zl$x8d{ zWMCrv5Pn2th)j_s0wP=Fh+L5;@bult5?`j*E%@f}Gd?^FL^TY`}Q delta 378 zcmWN=M=t{a0EXe9_TGE1+DfTdPDn*s37B!+))QNi0AR0xJ zXcjG^RkVqA(IGlTm*^HfqE`e(pXe6@Vo(f;VKE{`MM#W^aS;|1Vp2rJ)ECje?dRBM z!gqYv_k7`@Byj-+F@YKOc#w=Wsmg(~i&h itk3zpFZiM_`Lf4+#aDgJ*L}k`eap8!{vD1dQpta0q=J+H diff --git a/Assets/Resources/water.asset b/Assets/Resources/water.asset index 6c8df56bafd0e74c80d1b5efd325423b5d4aa22c..c63936a2c153d65010ed295e3c0e6f5eee40e226 100644 GIT binary patch delta 181 zcmWN=$87=u002P&XOamfM`KLR;Yg3|hd%t+KN2nQpaGh32Xp}=&F%glxxHUb!7)6C ze@H~45|cnaBrXX_N=nl5DH+L1PV(|41u05N%2JW4)TAyAX-Z4l@+}?tk*@qoPx>;D fp^RiK6Pe0P=CY8btYj@4*-9uo*~{U<@p*j#M4~p& delta 181 zcmWN=$xQ+Q06@_U3<84eyC}-O$TAFQ% Date: Mon, 17 Nov 2025 11:12:23 +0900 Subject: [PATCH 2/8] Map Version 10 --- Assets/Facepunch/RustWorldSDK/WorldSerialization.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs b/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs index c4028dca..21e72e81 100644 --- a/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs +++ b/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs @@ -7,7 +7,7 @@ public class WorldSerialization { - public const uint CurrentVersion = 9; + public const uint CurrentVersion = 10; public static uint Version { @@ -167,7 +167,7 @@ public void Load(string fileName) using (var binaryReader = new BinaryReader(fileStream)) { Version = binaryReader.ReadUInt32(); - + long Timestamp = binaryReader.ReadInt64(); if (Version != CurrentVersion) Debug.LogWarning("Map Version is: " + Version + " whilst Rust is on: " + CurrentVersion); From 0f34391a4501afa6857f92ec89cfeac974059c9d Mon Sep 17 00:00:00 2001 From: techan <50950268+te-chan@users.noreply.github.com> Date: Tue, 2 Dec 2025 03:34:02 +0900 Subject: [PATCH 3/8] Add Jungle --- Assets/Facepunch/RustWorldSDK/TerrainBiome.cs | 6 +++- .../RustWorldSDK/WorldSerialization.cs | 2 ++ Assets/MapEditor/Managers/TerrainManager.cs | 33 ++++++++++++++----- Assets/MapEditor/Scripts/WorldConverter.cs | 14 ++++---- .../Textures/Biome/Jungle.terrainlayer | 22 +++++++++++++ .../Textures/Biome/Jungle.terrainlayer.meta | 8 +++++ 6 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 Assets/Resources/Textures/Biome/Jungle.terrainlayer create mode 100644 Assets/Resources/Textures/Biome/Jungle.terrainlayer.meta diff --git a/Assets/Facepunch/RustWorldSDK/TerrainBiome.cs b/Assets/Facepunch/RustWorldSDK/TerrainBiome.cs index 119bc22c..e3150ec7 100644 --- a/Assets/Facepunch/RustWorldSDK/TerrainBiome.cs +++ b/Assets/Facepunch/RustWorldSDK/TerrainBiome.cs @@ -8,9 +8,10 @@ public enum Enum Temperate = 1 << TEMPERATE_IDX, Tundra = 1 << TUNDRA_IDX, Arctic = 1 << ARCTIC_IDX, + Jungle = 1 << JUNGLE_IDX, } - public const int COUNT = 4; + public const int COUNT = 5; public const int EVERYTHING = ~0; public const int NOTHING = 0; @@ -18,17 +19,20 @@ public enum Enum public const int TEMPERATE = (int)Enum.Temperate; public const int TUNDRA = (int)Enum.Tundra; public const int ARCTIC = (int)Enum.Arctic; + public const int JUNGLE = (int)Enum.Jungle; public const int ARID_IDX = 0; public const int TEMPERATE_IDX = 1; public const int TUNDRA_IDX = 2; public const int ARCTIC_IDX = 3; + public const int JUNGLE_IDX = 4; private static Dictionary type2index = new Dictionary() { { ARID, ARID_IDX }, { TEMPERATE, TEMPERATE_IDX }, { TUNDRA, TUNDRA_IDX }, { ARCTIC, ARCTIC_IDX }, + { JUNGLE, JUNGLE_IDX }, }; public static int TypeToIndex(int id) diff --git a/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs b/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs index 21e72e81..1b0e44be 100644 --- a/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs +++ b/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs @@ -78,6 +78,7 @@ public class PathData [ProtoMember(13)] public int splat; [ProtoMember(14)] public int topology; [ProtoMember(15)] public VectorData[] nodes; + [ProtoMember(16)] public int toplogy; } [Serializable] @@ -146,6 +147,7 @@ public void Save(string fileName) using (var binaryWriter = new BinaryWriter(fileStream)) { binaryWriter.Write(Version); + binaryWriter.Write((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds); using (var compressionStream = new LZ4Stream(fileStream, LZ4StreamMode.Compress)) Serializer.Serialize(compressionStream, world); diff --git a/Assets/MapEditor/Managers/TerrainManager.cs b/Assets/MapEditor/Managers/TerrainManager.cs index 52375495..f620ca06 100644 --- a/Assets/MapEditor/Managers/TerrainManager.cs +++ b/Assets/MapEditor/Managers/TerrainManager.cs @@ -65,6 +65,9 @@ public static class Callbacks /// Resolution of the splatmap/alphamap. /// Power of ^2, between 512 - 2048. public static int SplatMapRes { get; private set; } + /// Resolution of the biomemap. + /// Power of ^2, between 512 - 2048. + public static int BiomeMapRes { get; private set; } /// The world size of each splat relative to the terrain size it covers. public static float SplatSize { get => Land.terrainData.size.x / SplatMapRes; } @@ -89,7 +92,7 @@ public static class Callbacks case LayerType.Biome: if (CurrentLayerType == layer && LayerDirty) { - Biome = Land.terrainData.GetAlphamaps(0, 0, SplatMapRes, SplatMapRes); + Biome = Land.terrainData.GetAlphamaps(0, 0, BiomeMapRes, BiomeMapRes); LayerDirty = false; } return Biome; @@ -139,10 +142,10 @@ public static void SetSplatMap(float[,,] array, LayerType layer, int topology = } // Check for array dimensions not matching alphamap. - if (array.GetLength(0) != SplatMapRes || array.GetLength(1) != SplatMapRes || array.GetLength(2) != LayerCount(layer)) + if (array.GetLength(0) != LayerRes(layer) || array.GetLength(1) != LayerRes(layer) || array.GetLength(2) != LayerCount(layer)) { - Debug.LogError($"SetSplatMap(array[{array.GetLength(0)}, {array.GetLength(1)}, {LayerCount(layer)}]) dimensions invalid, should be " + - $"array[{ SplatMapRes}, { SplatMapRes}, {LayerCount(layer)}]."); + Debug.LogError($"SetSplatMap(array[{array.GetLength(0)}, {array.GetLength(1)}, {array.GetLength(2)}]) dimensions invalid, should be " + + $"array[{LayerRes(layer)}, {LayerRes(layer)}, {LayerCount(layer)}]."); return; } @@ -202,7 +205,6 @@ public static void SetAlphaMap(bool[,] array) }); Land.terrainData.SetHoles(0, 0, Alpha); - AlphaDirty = false; return; } @@ -215,7 +217,6 @@ public static void SetAlphaMap(bool[,] array) Alpha = array; Land.terrainData.SetHoles(0, 0, Alpha); - AlphaDirty = false; } private static void SplatMapChanged(Terrain terrain, string textureName, RectInt texelRegion, bool synched) @@ -584,7 +585,7 @@ private static TerrainLayer[] GetGroundLayers() private static TerrainLayer[] GetBiomeLayers() { - TerrainLayer[] textures = new TerrainLayer[4]; + TerrainLayer[] textures = new TerrainLayer[5]; textures[0] = AssetDatabase.LoadAssetAtPath("Assets/Resources/Textures/Biome/Arid.terrainlayer"); textures[0].diffuseTexture = Resources.Load("Textures/Biome/arid"); textures[1] = AssetDatabase.LoadAssetAtPath("Assets/Resources/Textures/Biome/Temperate.terrainlayer"); @@ -593,6 +594,8 @@ private static TerrainLayer[] GetBiomeLayers() textures[2].diffuseTexture = Resources.Load("Textures/Biome/tundra"); textures[3] = AssetDatabase.LoadAssetAtPath("Assets/Resources/Textures/Biome/Arctic.terrainlayer"); textures[3].diffuseTexture = Resources.Load("Textures/Biome/arctic"); + textures[4] = AssetDatabase.LoadAssetAtPath("Assets/Resources/Textures/Biome/Jungle.terrainlayer"); + textures[4].diffuseTexture = Resources.Load("Textures/Biome/jungle"); return textures; } @@ -663,6 +666,19 @@ public static void ChangeLayer(LayerType layer, int topology = -1) Callbacks.InvokeLayerChanged(layer, topology); } + /// Layer resolution in layer chosen, used for determining the size of the splatmap array. + /// The LayerType to return the texture count from. (Ground, Biome or Topology) + public static int LayerRes(LayerType layer) + { + return layer switch + { + LayerType.Ground => SplatMapRes, + LayerType.Biome => BiomeMapRes, + LayerType.Alpha => AlphaMapRes, + _ => SplatMapRes + }; + } + /// Layer count in layer chosen, used for determining the size of the splatmap array. /// The LayerType to return the texture count from. (Ground, Biome or Topology) public static int LayerCount(LayerType layer) @@ -670,7 +686,7 @@ public static int LayerCount(LayerType layer) return layer switch { LayerType.Ground => 8, - LayerType.Biome => 4, + LayerType.Biome => 5, _ => 2 }; } @@ -743,6 +759,7 @@ private static IEnumerator SetupTerrain(MapInfo mapInfo, Terrain terrain) private static IEnumerator SetSplatMaps(MapInfo mapInfo, int progressID) { SplatMapRes = mapInfo.splatRes; + BiomeMapRes = mapInfo.biomeMap.GetLength(0); SetSplatMap(mapInfo.splatMap, LayerType.Ground); SetSplatMap(mapInfo.biomeMap, LayerType.Biome); diff --git a/Assets/MapEditor/Scripts/WorldConverter.cs b/Assets/MapEditor/Scripts/WorldConverter.cs index c1b71ae0..72e96c16 100644 --- a/Assets/MapEditor/Scripts/WorldConverter.cs +++ b/Assets/MapEditor/Scripts/WorldConverter.cs @@ -56,7 +56,7 @@ public static MapInfo EmptyMap(int size, float landHeight, TerrainSplat.Enum gro terrains.splatMap[i, j, gndIdx] = 1f; }); - terrains.biomeMap = new float[splatRes, splatRes, 4]; + terrains.biomeMap = new float[splatRes, splatRes, 5]; int biomeIdx = TerrainBiome.TypeToIndex((int)biome); Parallel.For(0, splatRes, i => { @@ -78,7 +78,7 @@ public static MapInfo EmptyMap(int size, float landHeight, TerrainSplat.Enum gro public static MapInfo ConvertMaps(MapInfo terrains, TerrainMap splatMap, TerrainMap biomeMap, TerrainMap alphaMap) { terrains.splatMap = new float[splatMap.res, splatMap.res, 8]; - terrains.biomeMap = new float[biomeMap.res, biomeMap.res, 4]; + terrains.biomeMap = new float[biomeMap.res, biomeMap.res, 5]; terrains.alphaMap = new bool[alphaMap.res, alphaMap.res]; var groundTask = Task.Run(() => @@ -96,7 +96,7 @@ public static MapInfo ConvertMaps(MapInfo terrains, TerrainMap splatMap, T Parallel.For(0, terrains.splatRes, i => { for (int j = 0; j < terrains.splatRes; j++) - for (int k = 0; k < 4; k++) + for (int k = 0; k < 5; k++) terrains.biomeMap[i, j, k] = BitUtility.Byte2Float(biomeMap[k, i, j]); }); }); @@ -130,7 +130,7 @@ public static MapInfo WorldToTerrain(WorldSerialization world) var waterMap = new TerrainMap(world.GetMap("water").data, 1); var splatMap = new TerrainMap(world.GetMap("splat").data, 8); var topologyMap = new TerrainMap(world.GetMap("topology").data, 1); - var biomeMap = new TerrainMap(world.GetMap("biome").data, 4); + var biomeMap = new TerrainMap(world.GetMap("biome").data, 5); var alphaMap = new TerrainMap(world.GetMap("alpha").data, 1); terrains.topology = topologyMap; @@ -173,11 +173,11 @@ public static WorldSerialization TerrainToWorld(Terrain land, Terrain water, (in splatBytes = splatMap.ToByteArray(); }); - byte[] biomeBytes = new byte[textureResolution * textureResolution * 4]; - var biomeMap = new TerrainMap(biomeBytes, 4); + byte[] biomeBytes = new byte[textureResolution * textureResolution * 5]; + var biomeMap = new TerrainMap(biomeBytes, 5); var biomeTask = Task.Run(() => { - Parallel.For(0, 4, i => + Parallel.For(0, 5, i => { for (int j = 0; j < textureResolution; j++) for (int k = 0; k < textureResolution; k++) diff --git a/Assets/Resources/Textures/Biome/Jungle.terrainlayer b/Assets/Resources/Textures/Biome/Jungle.terrainlayer new file mode 100644 index 00000000..e0c7f855 --- /dev/null +++ b/Assets/Resources/Textures/Biome/Jungle.terrainlayer @@ -0,0 +1,22 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1953259897 &8574412962073106935 +TerrainLayer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Jungle + m_DiffuseTexture: {fileID: 0} + m_NormalMapTexture: {fileID: 0} + m_MaskMapTexture: {fileID: 0} + m_TileSize: {x: 2, y: 2} + m_TileOffset: {x: 0, y: 0} + m_Specular: {r: 0, g: 0, b: 0, a: 0} + m_Metallic: 0 + m_Smoothness: 0 + m_NormalScale: 1 + m_DiffuseRemapMin: {x: 0, y: 0, z: 0, w: 0} + m_DiffuseRemapMax: {x: 1, y: 1, z: 1, w: 1} + m_MaskMapRemapMin: {x: 0, y: 0, z: 0, w: 0} + m_MaskMapRemapMax: {x: 1, y: 1, z: 1, w: 1} diff --git a/Assets/Resources/Textures/Biome/Jungle.terrainlayer.meta b/Assets/Resources/Textures/Biome/Jungle.terrainlayer.meta new file mode 100644 index 00000000..a3aacda7 --- /dev/null +++ b/Assets/Resources/Textures/Biome/Jungle.terrainlayer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 30fbd512222b0fd49913ec8d20f73f39 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: From c23f7e1af8deb041146898b829c8b00c97a05ae0 Mon Sep 17 00:00:00 2001 From: techan <50950268+te-chan@users.noreply.github.com> Date: Tue, 2 Dec 2025 03:45:16 +0900 Subject: [PATCH 4/8] fix: struct is nullable --- Assets/Facepunch/RustWorldSDK/WorldSerialization.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs b/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs index 1b0e44be..ba2346e3 100644 --- a/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs +++ b/Assets/Facepunch/RustWorldSDK/WorldSerialization.cs @@ -175,6 +175,17 @@ public void Load(string fileName) using (var compressionStream = new LZ4Stream(fileStream, LZ4StreamMode.Decompress)) world = Serializer.Deserialize(compressionStream); + + // Fix null VectorData fields in PrefabData (game uses struct, we use class) + foreach (var prefab in world.prefabs) + { + if (prefab.position == null) + prefab.position = new VectorData(0, 0, 0); + if (prefab.rotation == null) + prefab.rotation = new VectorData(0, 0, 0); + if (prefab.scale == null) + prefab.scale = new VectorData(1, 1, 1); + } } } } From 3fec281650246d3f2012792221a8b41ee5ac1428 Mon Sep 17 00:00:00 2001 From: techan <50950268+te-chan@users.noreply.github.com> Date: Tue, 2 Dec 2025 03:49:49 +0900 Subject: [PATCH 5/8] revert unnecessary changes --- Assets/MapEditor/Managers/TerrainManager.cs | 27 +++++---------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/Assets/MapEditor/Managers/TerrainManager.cs b/Assets/MapEditor/Managers/TerrainManager.cs index f620ca06..860ad19c 100644 --- a/Assets/MapEditor/Managers/TerrainManager.cs +++ b/Assets/MapEditor/Managers/TerrainManager.cs @@ -65,9 +65,6 @@ public static class Callbacks /// Resolution of the splatmap/alphamap. /// Power of ^2, between 512 - 2048. public static int SplatMapRes { get; private set; } - /// Resolution of the biomemap. - /// Power of ^2, between 512 - 2048. - public static int BiomeMapRes { get; private set; } /// The world size of each splat relative to the terrain size it covers. public static float SplatSize { get => Land.terrainData.size.x / SplatMapRes; } @@ -92,7 +89,7 @@ public static class Callbacks case LayerType.Biome: if (CurrentLayerType == layer && LayerDirty) { - Biome = Land.terrainData.GetAlphamaps(0, 0, BiomeMapRes, BiomeMapRes); + Biome = Land.terrainData.GetAlphamaps(0, 0, SplatMapRes, SplatMapRes); LayerDirty = false; } return Biome; @@ -142,10 +139,10 @@ public static void SetSplatMap(float[,,] array, LayerType layer, int topology = } // Check for array dimensions not matching alphamap. - if (array.GetLength(0) != LayerRes(layer) || array.GetLength(1) != LayerRes(layer) || array.GetLength(2) != LayerCount(layer)) + if (array.GetLength(0) != SplatMapRes || array.GetLength(1) != SplatMapRes || array.GetLength(2) != LayerCount(layer)) { - Debug.LogError($"SetSplatMap(array[{array.GetLength(0)}, {array.GetLength(1)}, {array.GetLength(2)}]) dimensions invalid, should be " + - $"array[{LayerRes(layer)}, {LayerRes(layer)}, {LayerCount(layer)}]."); + Debug.LogError($"SetSplatMap(array[{array.GetLength(0)}, {array.GetLength(1)}, {LayerCount(layer)}]) dimensions invalid, should be " + + $"array[{ SplatMapRes}, { SplatMapRes}, {LayerCount(layer)}]."); return; } @@ -205,6 +202,7 @@ public static void SetAlphaMap(bool[,] array) }); Land.terrainData.SetHoles(0, 0, Alpha); + AlphaDirty = false; return; } @@ -217,6 +215,7 @@ public static void SetAlphaMap(bool[,] array) Alpha = array; Land.terrainData.SetHoles(0, 0, Alpha); + AlphaDirty = false; } private static void SplatMapChanged(Terrain terrain, string textureName, RectInt texelRegion, bool synched) @@ -666,19 +665,6 @@ public static void ChangeLayer(LayerType layer, int topology = -1) Callbacks.InvokeLayerChanged(layer, topology); } - /// Layer resolution in layer chosen, used for determining the size of the splatmap array. - /// The LayerType to return the texture count from. (Ground, Biome or Topology) - public static int LayerRes(LayerType layer) - { - return layer switch - { - LayerType.Ground => SplatMapRes, - LayerType.Biome => BiomeMapRes, - LayerType.Alpha => AlphaMapRes, - _ => SplatMapRes - }; - } - /// Layer count in layer chosen, used for determining the size of the splatmap array. /// The LayerType to return the texture count from. (Ground, Biome or Topology) public static int LayerCount(LayerType layer) @@ -759,7 +745,6 @@ private static IEnumerator SetupTerrain(MapInfo mapInfo, Terrain terrain) private static IEnumerator SetSplatMaps(MapInfo mapInfo, int progressID) { SplatMapRes = mapInfo.splatRes; - BiomeMapRes = mapInfo.biomeMap.GetLength(0); SetSplatMap(mapInfo.splatMap, LayerType.Ground); SetSplatMap(mapInfo.biomeMap, LayerType.Biome); From e279e3d1f08dbd126d01b89fb6751f5065b17250 Mon Sep 17 00:00:00 2001 From: techan <50950268+te-chan@users.noreply.github.com> Date: Tue, 2 Dec 2025 03:55:34 +0900 Subject: [PATCH 6/8] jungle color --- .../Textures/Biome/Jungle.terrainlayer | 2 +- Assets/Resources/Textures/Biome/jungle.png | Bin 0 -> 361 bytes .../Resources/Textures/Biome/jungle.png.meta | 114 ++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 Assets/Resources/Textures/Biome/jungle.png create mode 100644 Assets/Resources/Textures/Biome/jungle.png.meta diff --git a/Assets/Resources/Textures/Biome/Jungle.terrainlayer b/Assets/Resources/Textures/Biome/Jungle.terrainlayer index e0c7f855..447455c4 100644 --- a/Assets/Resources/Textures/Biome/Jungle.terrainlayer +++ b/Assets/Resources/Textures/Biome/Jungle.terrainlayer @@ -7,7 +7,7 @@ TerrainLayer: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: Jungle - m_DiffuseTexture: {fileID: 0} + m_DiffuseTexture: {fileID: 2800000, guid: 554862263fae6584b85651d2ea5b1f81, type: 3} m_NormalMapTexture: {fileID: 0} m_MaskMapTexture: {fileID: 0} m_TileSize: {x: 2, y: 2} diff --git a/Assets/Resources/Textures/Biome/jungle.png b/Assets/Resources/Textures/Biome/jungle.png new file mode 100644 index 0000000000000000000000000000000000000000..717bc0436b02b3b51f91290c5e593dfdb853a431 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1SEZ8zRh7^U^MV_aSW-L^Y*f#AcFx9^TsU! zhgSYsDRN9-h>^eE?swUXI|b5=RdNEt3Th5M4Ko-F8Izcfuyk;aP=U+8B&--`wztj7 Q1qLC5r>mdKI;Vst0C!JYU;qFB literal 0 HcmV?d00001 diff --git a/Assets/Resources/Textures/Biome/jungle.png.meta b/Assets/Resources/Textures/Biome/jungle.png.meta new file mode 100644 index 00000000..de0fa7da --- /dev/null +++ b/Assets/Resources/Textures/Biome/jungle.png.meta @@ -0,0 +1,114 @@ +fileFormatVersion: 2 +guid: 554862263fae6584b85651d2ea5b1f81 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: From 4149ca3f74f954e5b49bc7bf423d668ca947b269 Mon Sep 17 00:00:00 2001 From: techan <50950268+te-chan@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:44:19 +0900 Subject: [PATCH 7/8] exp: load from play mode --- .../PrefabsList/PrefabsListTreeView.cs | 13 +- Assets/MapEditor/Managers/AssetManager.cs | 65 +++- Assets/MapEditor/Managers/PrefabManager.cs | 15 + .../MapEditor/Managers/SceneAssetManager.cs | 339 ++++++++++++++++++ .../Managers/SceneAssetManager.cs.meta | 11 + .../MapEditor/Scripts/AssetSceneManifest.cs | 17 + .../Scripts/AssetSceneManifest.cs.meta | 11 + 7 files changed, 462 insertions(+), 9 deletions(-) create mode 100644 Assets/MapEditor/Managers/SceneAssetManager.cs create mode 100644 Assets/MapEditor/Managers/SceneAssetManager.cs.meta create mode 100644 Assets/MapEditor/Scripts/AssetSceneManifest.cs create mode 100644 Assets/MapEditor/Scripts/AssetSceneManifest.cs.meta diff --git a/Assets/MapEditor/Editor/TreeView/PrefabsList/PrefabsListTreeView.cs b/Assets/MapEditor/Editor/TreeView/PrefabsList/PrefabsListTreeView.cs index bdacd1fe..bf9f8631 100644 --- a/Assets/MapEditor/Editor/TreeView/PrefabsList/PrefabsListTreeView.cs +++ b/Assets/MapEditor/Editor/TreeView/PrefabsList/PrefabsListTreeView.cs @@ -82,7 +82,18 @@ public static List GetPrefabsListElements(bool showAll = fal List prefabsListElements = new List(); prefabsListElements.Add(new PrefabsListElement("Root", -1, 0)); - var prefabStrings = showAll ? AssetManager.AssetPaths.Where(x => x.Contains(".prefab")) : AssetManager.AssetPaths.Where(x => SettingsManager.PrefabPaths.Any(y => x.Contains(y) && x.Contains(".prefab"))); + // Use scene manifest prefab paths if available, otherwise fall back to legacy AssetPaths + IEnumerable sourcePaths; + if (SceneAssetManager.IsManifestLoaded && SceneAssetManager.ManifestPrefabPaths.Count > 0) + { + sourcePaths = SceneAssetManager.ManifestPrefabPaths; + } + else + { + sourcePaths = AssetManager.AssetPaths; + } + + var prefabStrings = showAll ? sourcePaths.Where(x => x.Contains(".prefab")) : sourcePaths.Where(x => SettingsManager.PrefabPaths.Any(y => x.Contains(y) && x.Contains(".prefab"))); int prefabID = 1, parentID = -1; foreach (var manifestString in prefabStrings) { diff --git a/Assets/MapEditor/Managers/AssetManager.cs b/Assets/MapEditor/Managers/AssetManager.cs index bf7b865a..873e4d6d 100644 --- a/Assets/MapEditor/Managers/AssetManager.cs +++ b/Assets/MapEditor/Managers/AssetManager.cs @@ -44,6 +44,7 @@ public static class Callbacks public const string AssetDumpPath = "AssetDump.txt"; public const string MaterialsListPath = "MaterialsList.txt"; public const string VolumesListPath = "VolumesList.txt"; + public const string SceneManifestFileName = "AssetSceneManifest.json"; public static Dictionary IDLookup { get; private set; } = new Dictionary(); public static Dictionary PathLookup { get; private set; } = new Dictionary(); @@ -104,19 +105,39 @@ public static GameObject LoadPrefab(string filePath) if (AssetCache.ContainsKey(filePath)) return AssetCache[filePath] as GameObject; - else + // Play mode: use scene-based loading + if (Application.isPlaying && SceneAssetManager.IsManifestLoaded) { - GameObject val = GetAsset(filePath); + GameObject val = SceneAssetManager.GetPrefabFromScene(filePath); if (val != null) { - PrefabManager.Setup(val, filePath); - AssetCache.Add(filePath, val); - PrefabManager.Callbacks.OnPrefabLoaded(val); - return val; + PrefabManager.Setup(val, filePath); + AssetCache.Add(filePath, val); + PrefabManager.Callbacks.OnPrefabLoaded(val); + return val; } - Debug.LogWarning("Prefab not loaded from bundle: " + filePath); + Debug.LogWarning("Prefab not loaded from scene: " + filePath); + return PrefabManager.DefaultPrefab; + } + + // Edit mode: try legacy bundle loading (fallback) + GameObject legacyVal = GetAsset(filePath); + if (legacyVal != null) + { + PrefabManager.Setup(legacyVal, filePath); + AssetCache.Add(filePath, legacyVal); + PrefabManager.Callbacks.OnPrefabLoaded(legacyVal); + return legacyVal; + } + + // Edit mode with manifest loaded: return default prefab + if (SceneAssetManager.IsManifestLoaded) + { return PrefabManager.DefaultPrefab; } + + Debug.LogWarning("Prefab not loaded from bundle: " + filePath); + return PrefabManager.DefaultPrefab; } /// Returns a preview image of the asset located at the filepath. Caches the results. @@ -184,6 +205,28 @@ public static void AssetDump() streamWriter.WriteLine(item + " : " + ToID(item)); } + /// Loads the AssetSceneManifest.json from the Rust directory. + public static void LoadSceneManifest() + { + string manifestPath = Path.Combine(SettingsManager.RustDirectory, "Bundles", SceneManifestFileName); + if (File.Exists(manifestPath)) + { + try + { + string json = File.ReadAllText(manifestPath); + SceneAssetManager.ParseManifest(json); + } + catch (System.Exception e) + { + Debug.LogError($"Failed to load AssetSceneManifest: {e.Message}"); + } + } + else + { + Debug.LogWarning($"AssetSceneManifest not found at: {manifestPath}"); + } + } + public static string ToPath(uint i) { if ((int)i == 0) @@ -230,17 +273,23 @@ public static IEnumerator Initialise(string bundlesRoot) yield return EditorCoroutineUtility.StartCoroutineOwnerless(SetBundleReferences((progressID, bundleID))); yield return EditorCoroutineUtility.StartCoroutineOwnerless(SetMaterials(materialID)); + // Load scene manifest for scene-based prefab loading + LoadSceneManifest(); + IsInitialised = true; IsInitialising = false; SetVolumeGizmos(); Callbacks.OnBundlesLoaded(); PrefabManager.ReplaceWithLoaded(PrefabManager.CurrentMapPrefabs, prefabID); } - public static IEnumerator Dispose() + public static IEnumerator Dispose() { IsInitialising = true; ProgressManager.RemoveProgressBars("Unload Asset Bundles"); + // Dispose scene asset manager first + SceneAssetManager.Dispose(); + int progressID = Progress.Start("Unload Asset Bundles", null, Progress.Options.Sticky); int bundleID = Progress.Start("Bundles", null, Progress.Options.Sticky, progressID); int prefabID = Progress.Start("Prefabs", null, Progress.Options.Sticky, progressID); diff --git a/Assets/MapEditor/Managers/PrefabManager.cs b/Assets/MapEditor/Managers/PrefabManager.cs index 25b0f3fd..a18f9681 100644 --- a/Assets/MapEditor/Managers/PrefabManager.cs +++ b/Assets/MapEditor/Managers/PrefabManager.cs @@ -239,7 +239,22 @@ public static IEnumerator SpawnPrefabs(PrefabData[] prefabs, int progressID) Progress.Report(progressID, (float)i / prefabs.Length, "Spawning Prefabs: " + i + " / " + prefabs.Length); sw.Restart(); } + + string prefabPath = AssetManager.ToPath(prefabs[i].id); + + // Play mode: ensure scene is loaded before accessing prefab + if (UnityEngine.Application.isPlaying && SceneAssetManager.IsManifestLoaded) + { + yield return SceneAssetManager.EnsurePrefabAvailable(prefabPath); + } + Spawn(Load(prefabs[i].id), prefabs[i], GetParent(prefabs[i].category)); + + // Play mode: try to unload unused scenes to save memory + if (UnityEngine.Application.isPlaying && SceneAssetManager.IsManifestLoaded) + { + yield return SceneAssetManager.TryUnloadUnusedScenes(prefabs, i); + } } Progress.Report(progressID, 0.99f, "Spawned " + prefabs.Length + " prefabs."); diff --git a/Assets/MapEditor/Managers/SceneAssetManager.cs b/Assets/MapEditor/Managers/SceneAssetManager.cs new file mode 100644 index 00000000..02749da4 --- /dev/null +++ b/Assets/MapEditor/Managers/SceneAssetManager.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.SceneManagement; +using static WorldSerialization; + +public static class SceneAssetManager +{ + public static AssetSceneManifest Manifest { get; private set; } + + // Maps prefab path (lowercase) -> scene name + public static Dictionary PrefabToSceneLookup { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + + // Maps scene name -> SceneEntry (for CanUnload check) + public static Dictionary SceneEntryLookup { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + + // Currently loaded scenes (scene name -> Scene handle) + public static Dictionary LoadedScenes { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + + // Cached GameObjects from scenes (prefab path -> GameObject) + public static Dictionary ScenePrefabCache { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + + // All prefab paths from manifest (for UI listing) + public static List ManifestPrefabPaths { get; private set; } = new List(); + + public static bool IsManifestLoaded { get; private set; } + public static bool IsLoadingScene { get; private set; } + + /// Parses the JSON manifest and builds lookup tables. + public static void ParseManifest(string json) + { + try + { + Manifest = JsonUtility.FromJson(json); + if (Manifest == null || Manifest.Scenes == null) + { + Debug.LogError("Failed to parse AssetSceneManifest: Invalid JSON structure"); + return; + } + BuildLookupTables(); + IsManifestLoaded = true; + Debug.Log($"SceneAssetManager: Loaded manifest with {Manifest.Scenes.Count} scenes, {ManifestPrefabPaths.Count} prefabs"); + } + catch (Exception e) + { + Debug.LogError($"Failed to parse AssetSceneManifest: {e.Message}"); + } + } + + private static void BuildLookupTables() + { + PrefabToSceneLookup.Clear(); + SceneEntryLookup.Clear(); + ManifestPrefabPaths.Clear(); + LoadedScenes.Clear(); + ScenePrefabCache.Clear(); + + foreach (var scene in Manifest.Scenes) + { + SceneEntryLookup[scene.Name] = scene; + + if (scene.IncludedAssets != null) + { + foreach (var prefabPath in scene.IncludedAssets) + { + if (!string.IsNullOrEmpty(prefabPath)) + { + PrefabToSceneLookup[prefabPath] = scene.Name; + ManifestPrefabPaths.Add(prefabPath); + } + } + } + } + + ManifestPrefabPaths.Sort(); + } + + /// Ensures the scene containing the prefab is loaded and the prefab is cached. + public static IEnumerator EnsurePrefabAvailable(string prefabPath) + { + if (string.IsNullOrEmpty(prefabPath)) + yield break; + + // Check if prefab already cached + if (ScenePrefabCache.ContainsKey(prefabPath)) + yield break; + + if (!PrefabToSceneLookup.TryGetValue(prefabPath, out string sceneName)) + { + Debug.LogWarning($"SceneAssetManager: Prefab not found in manifest: {prefabPath}"); + yield break; + } + + // Check if scene already loaded + if (!LoadedScenes.ContainsKey(sceneName)) + { + yield return LoadSceneAdditive(sceneName); + } + + // Cache the prefab from the loaded scene + CachePrefabFromScene(sceneName, prefabPath); + } + + private static IEnumerator LoadSceneAdditive(string sceneName) + { + // Wait if another scene is loading (enforce sequential) + while (IsLoadingScene) + yield return null; + + IsLoadingScene = true; + + string scenePath = GetScenePathFromBundle(sceneName); + if (string.IsNullOrEmpty(scenePath)) + { + Debug.LogError($"SceneAssetManager: Scene not found in bundles: {sceneName}"); + IsLoadingScene = false; + yield break; + } + + Debug.Log($"SceneAssetManager: Loading scene: {sceneName}"); + + AsyncOperation asyncOp = null; + try + { + asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(scenePath, LoadSceneMode.Additive); + } + catch (Exception e) + { + Debug.LogError($"SceneAssetManager: Failed to load scene {sceneName}: {e.Message}"); + IsLoadingScene = false; + yield break; + } + + if (asyncOp == null) + { + Debug.LogError($"SceneAssetManager: LoadSceneAsync returned null for: {scenePath}"); + IsLoadingScene = false; + yield break; + } + + while (!asyncOp.isDone) + yield return null; + + var loadedScene = UnityEngine.SceneManagement.SceneManager.GetSceneByPath(scenePath); + if (loadedScene.IsValid()) + { + LoadedScenes[sceneName] = loadedScene; + Debug.Log($"SceneAssetManager: Successfully loaded scene: {sceneName}"); + } + else + { + Debug.LogError($"SceneAssetManager: Scene loaded but invalid: {sceneName}"); + } + + IsLoadingScene = false; + } + + private static void CachePrefabFromScene(string sceneName, string prefabPath) + { + if (!LoadedScenes.TryGetValue(sceneName, out Scene scene)) + { + Debug.LogWarning($"SceneAssetManager: Scene not loaded when caching prefab: {sceneName}"); + return; + } + + if (!scene.IsValid() || !scene.isLoaded) + { + Debug.LogWarning($"SceneAssetManager: Scene invalid or not loaded: {sceneName}"); + return; + } + + // Search for GameObject with matching name (full path) + foreach (var rootObj in scene.GetRootGameObjects()) + { + GameObject found = FindGameObjectByName(rootObj, prefabPath); + if (found != null) + { + ScenePrefabCache[prefabPath] = found; + return; + } + } + + Debug.LogWarning($"SceneAssetManager: Prefab '{prefabPath}' not found in scene '{sceneName}'"); + } + + private static GameObject FindGameObjectByName(GameObject root, string name) + { + if (root.name.Equals(name, StringComparison.OrdinalIgnoreCase)) + return root; + + foreach (Transform child in root.transform) + { + var found = FindGameObjectByName(child.gameObject, name); + if (found != null) + return found; + } + + return null; + } + + /// Gets a cached prefab from a loaded scene. + public static GameObject GetPrefabFromScene(string prefabPath) + { + if (string.IsNullOrEmpty(prefabPath)) + return null; + + if (ScenePrefabCache.TryGetValue(prefabPath, out GameObject prefab)) + return prefab; + + return null; + } + + /// Tries to unload scenes that are no longer needed. + public static IEnumerator TryUnloadUnusedScenes(PrefabData[] allPrefabs, int currentIndex) + { + if (allPrefabs == null || currentIndex < 0) + yield break; + + // Build set of scenes still needed by remaining prefabs + HashSet scenesStillNeeded = new HashSet(StringComparer.OrdinalIgnoreCase); + for (int i = currentIndex + 1; i < allPrefabs.Length; i++) + { + string path = AssetManager.ToPath(allPrefabs[i].id); + if (!string.IsNullOrEmpty(path) && PrefabToSceneLookup.TryGetValue(path, out string sceneName)) + { + scenesStillNeeded.Add(sceneName); + } + } + + // Find scenes that can be unloaded + List scenesToUnload = new List(); + foreach (var kvp in LoadedScenes) + { + string sceneName = kvp.Key; + if (!scenesStillNeeded.Contains(sceneName) && + SceneEntryLookup.TryGetValue(sceneName, out SceneEntry entry) && + entry.CanUnload) + { + scenesToUnload.Add(sceneName); + } + } + + // Unload the scenes + foreach (string sceneName in scenesToUnload) + { + yield return UnloadScene(sceneName); + } + } + + private static IEnumerator UnloadScene(string sceneName) + { + if (!LoadedScenes.TryGetValue(sceneName, out Scene scene)) + yield break; + + // Remove cached prefabs from this scene + List keysToRemove = new List(); + foreach (var kvp in PrefabToSceneLookup) + { + if (kvp.Value.Equals(sceneName, StringComparison.OrdinalIgnoreCase)) + { + keysToRemove.Add(kvp.Key); + } + } + foreach (var key in keysToRemove) + { + ScenePrefabCache.Remove(key); + } + + Debug.Log($"SceneAssetManager: Unloading scene: {sceneName}"); + + if (scene.IsValid() && scene.isLoaded) + { + var asyncOp = UnityEngine.SceneManagement.SceneManager.UnloadSceneAsync(scene); + if (asyncOp != null) + { + while (!asyncOp.isDone) + yield return null; + } + } + + LoadedScenes.Remove(sceneName); + } + + /// Gets the scene path in the bundle from the scene name. + private static string GetScenePathFromBundle(string sceneName) + { + // Scene name format: "AssetScene-bootstrap" -> "AssetScene-bootstrap.unity" + string searchName = sceneName + ".unity"; + + foreach (var kvp in AssetManager.BundleLookup) + { + // Check if the path ends with the scene file name + if (kvp.Key.EndsWith(searchName, StringComparison.OrdinalIgnoreCase)) + return kvp.Key; + } + + // Also try searching for just the scene name in the path + foreach (var kvp in AssetManager.BundleLookup) + { + if (kvp.Key.Contains(sceneName) && kvp.Key.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)) + return kvp.Key; + } + + return null; + } + + /// Disposes all loaded scenes and clears caches. + public static void Dispose() + { + // Unload all loaded scenes + foreach (var scene in LoadedScenes.Values) + { + if (scene.IsValid() && scene.isLoaded) + { + try + { + UnityEngine.SceneManagement.SceneManager.UnloadSceneAsync(scene); + } + catch (Exception e) + { + Debug.LogWarning($"SceneAssetManager: Failed to unload scene: {e.Message}"); + } + } + } + + Manifest = null; + PrefabToSceneLookup.Clear(); + SceneEntryLookup.Clear(); + LoadedScenes.Clear(); + ScenePrefabCache.Clear(); + ManifestPrefabPaths.Clear(); + IsManifestLoaded = false; + IsLoadingScene = false; + + Debug.Log("SceneAssetManager: Disposed"); + } +} diff --git a/Assets/MapEditor/Managers/SceneAssetManager.cs.meta b/Assets/MapEditor/Managers/SceneAssetManager.cs.meta new file mode 100644 index 00000000..a39fabf7 --- /dev/null +++ b/Assets/MapEditor/Managers/SceneAssetManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 85a58cd6f75347f4b9be77e44fa93c2b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MapEditor/Scripts/AssetSceneManifest.cs b/Assets/MapEditor/Scripts/AssetSceneManifest.cs new file mode 100644 index 00000000..32ee42a1 --- /dev/null +++ b/Assets/MapEditor/Scripts/AssetSceneManifest.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +[Serializable] +public class AssetSceneManifest +{ + public List Scenes; +} + +[Serializable] +public class SceneEntry +{ + public string Name; + public bool AutoLoad; + public bool CanUnload; + public List IncludedAssets; +} diff --git a/Assets/MapEditor/Scripts/AssetSceneManifest.cs.meta b/Assets/MapEditor/Scripts/AssetSceneManifest.cs.meta new file mode 100644 index 00000000..7b1f9571 --- /dev/null +++ b/Assets/MapEditor/Scripts/AssetSceneManifest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 92bba74495134a04b8b6ebba92c875fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From fc371ee310cba108c7a974a77c0e538a966488c8 Mon Sep 17 00:00:00 2001 From: techan <50950268+te-chan@users.noreply.github.com> Date: Wed, 17 Dec 2025 14:55:57 +0900 Subject: [PATCH 8/8] fix: dont unload scenes and faster --- Assets/MapEditor/Managers/PrefabManager.cs | 21 +++--- .../MapEditor/Managers/SceneAssetManager.cs | 72 ++++++++++--------- 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/Assets/MapEditor/Managers/PrefabManager.cs b/Assets/MapEditor/Managers/PrefabManager.cs index a18f9681..ad0b23e3 100644 --- a/Assets/MapEditor/Managers/PrefabManager.cs +++ b/Assets/MapEditor/Managers/PrefabManager.cs @@ -233,27 +233,26 @@ public static IEnumerator SpawnPrefabs(PrefabData[] prefabs, int progressID) for (int i = 0; i < prefabs.Length; i++) { - if (sw.Elapsed.TotalSeconds > 4f) - { - yield return null; - Progress.Report(progressID, (float)i / prefabs.Length, "Spawning Prefabs: " + i + " / " + prefabs.Length); - sw.Restart(); - } - string prefabPath = AssetManager.ToPath(prefabs[i].id); // Play mode: ensure scene is loaded before accessing prefab + // Only yield if prefab is not already cached (scene needs loading) if (UnityEngine.Application.isPlaying && SceneAssetManager.IsManifestLoaded) { - yield return SceneAssetManager.EnsurePrefabAvailable(prefabPath); + if (!SceneAssetManager.IsPrefabCached(prefabPath)) + { + yield return SceneAssetManager.EnsurePrefabAvailable(prefabPath); + } } Spawn(Load(prefabs[i].id), prefabs[i], GetParent(prefabs[i].category)); - // Play mode: try to unload unused scenes to save memory - if (UnityEngine.Application.isPlaying && SceneAssetManager.IsManifestLoaded) + // Yield periodically for progress reporting (every 8 seconds) + if (sw.Elapsed.TotalSeconds > 8f) { - yield return SceneAssetManager.TryUnloadUnusedScenes(prefabs, i); + yield return null; + Progress.Report(progressID, (float)i / prefabs.Length, "Spawning Prefabs: " + i + " / " + prefabs.Length); + sw.Restart(); } } diff --git a/Assets/MapEditor/Managers/SceneAssetManager.cs b/Assets/MapEditor/Managers/SceneAssetManager.cs index 02749da4..3a7acb03 100644 --- a/Assets/MapEditor/Managers/SceneAssetManager.cs +++ b/Assets/MapEditor/Managers/SceneAssetManager.cs @@ -200,6 +200,14 @@ private static GameObject FindGameObjectByName(GameObject root, string name) return null; } + /// Checks if a prefab is already cached. + public static bool IsPrefabCached(string prefabPath) + { + if (string.IsNullOrEmpty(prefabPath)) + return false; + return ScenePrefabCache.ContainsKey(prefabPath); + } + /// Gets a cached prefab from a loaded scene. public static GameObject GetPrefabFromScene(string prefabPath) { @@ -215,38 +223,38 @@ public static GameObject GetPrefabFromScene(string prefabPath) /// Tries to unload scenes that are no longer needed. public static IEnumerator TryUnloadUnusedScenes(PrefabData[] allPrefabs, int currentIndex) { - if (allPrefabs == null || currentIndex < 0) - yield break; - - // Build set of scenes still needed by remaining prefabs - HashSet scenesStillNeeded = new HashSet(StringComparer.OrdinalIgnoreCase); - for (int i = currentIndex + 1; i < allPrefabs.Length; i++) - { - string path = AssetManager.ToPath(allPrefabs[i].id); - if (!string.IsNullOrEmpty(path) && PrefabToSceneLookup.TryGetValue(path, out string sceneName)) - { - scenesStillNeeded.Add(sceneName); - } - } - - // Find scenes that can be unloaded - List scenesToUnload = new List(); - foreach (var kvp in LoadedScenes) - { - string sceneName = kvp.Key; - if (!scenesStillNeeded.Contains(sceneName) && - SceneEntryLookup.TryGetValue(sceneName, out SceneEntry entry) && - entry.CanUnload) - { - scenesToUnload.Add(sceneName); - } - } - - // Unload the scenes - foreach (string sceneName in scenesToUnload) - { - yield return UnloadScene(sceneName); - } + // if (allPrefabs == null || currentIndex < 0) + yield break; + + // // Build set of scenes still needed by remaining prefabs + // HashSet scenesStillNeeded = new HashSet(StringComparer.OrdinalIgnoreCase); + // for (int i = currentIndex + 1; i < allPrefabs.Length; i++) + // { + // string path = AssetManager.ToPath(allPrefabs[i].id); + // if (!string.IsNullOrEmpty(path) && PrefabToSceneLookup.TryGetValue(path, out string sceneName)) + // { + // scenesStillNeeded.Add(sceneName); + // } + // } + + // // Find scenes that can be unloaded + // List scenesToUnload = new List(); + // foreach (var kvp in LoadedScenes) + // { + // string sceneName = kvp.Key; + // if (!scenesStillNeeded.Contains(sceneName) && + // SceneEntryLookup.TryGetValue(sceneName, out SceneEntry entry) && + // entry.CanUnload) + // { + // scenesToUnload.Add(sceneName); + // } + // } + + // // Unload the scenes + // foreach (string sceneName in scenesToUnload) + // { + // yield return UnloadScene(sceneName); + // } } private static IEnumerator UnloadScene(string sceneName)