using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System.Xml; using System.Globalization; using System.Linq; using System.Text; public static class SaveXML { static int SN = 0; public static byte[] BuildXmlBytes() { using (var ms = new MemoryStream()) { var settings = new XmlWriterSettings { Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), Indent = false, NewLineHandling = NewLineHandling.None, CloseOutput = false }; using (var xw = XmlWriter.Create(ms, settings)) { SetGlobal(); xw.WriteStartDocument(); xw.WriteStartElement("Room"); WriteElem(xw, "CLIENT", "free"); WriteElem(xw, "VERSION", _G.VER.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "FILENAME", _G.FileName); // Murs/sections choisis pour les armoires, ex: "4_1,2;6_1" (separateur ";"). WriteElem(xw, "WallCabs", _G.WallsCabs != null ? string.Join(";", _G.WallsCabs) : string.Empty); //if (SaveCompatibility.Replace_RoomID_with_RefID) WriteElem(xw, "REPLACE_ROOMID", "true"); // GLOBAL xw.WriteStartElement("GLOBAL"); WriteElem(xw, "HEIGHT", _G.HEIGHT.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "WIDE", _G.WIDE.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "DEPTH", _G.DEPTH.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "ROOM", "RDRAW"); WriteElem(xw, "WMKs", _G.WMKs); WriteElem(xw, "WMOs", _G.WMOs); WriteElem(xw, "SUN", _G.SUN); WriteElem(xw, "OBJnum", _G.OBJnum.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "NW", _G.NW.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "LightSetting", GetLightSettingSafe()); //Preferences WriteElem(xw, "Countertop", _G.CounterTop); WriteElem(xw, "Island", _G.Island); WriteElem(xw, "Global1", GetGlobalSettingSafe(1)); WriteElem(xw, "Global2", GetGlobalSettingSafe(2)); WriteElem(xw, "Global3", GetGlobalSettingSafe(3)); WriteElem(xw, "Global4", GetGlobalSettingSafe(4)); WriteElem(xw, "Global5", GetGlobalSettingSafe(5)); WriteElem(xw, "Global6", GetGlobalSettingSafe(6)); WriteElem(xw, "ClientInfo", GetClientInfoSafe()); WriteElem(xw, "storezone", _G.StoreZone); WriteElem(xw, "Options", _G.Options != null ? string.Join(";", _G.Options) : string.Empty); WriteElem(xw, "Preferences",GetPreferencesSafe()); if (_G.PATH == "free" || _G.PATH == "laminam") { WriteElem(xw, "CabtextureList", GetYourLibrarySafe()); } xw.WriteEndElement(); // GLOBAL BuildWallsData_NonClosedButLoopLastToFirst(); // Walls for (int i = 1; i < _G.NW + 1; i++) { xw.WriteStartElement($"W{i}"); WriteElem(xw, "w", _G.WallsWidth[i - 1].ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "px", _G.WallsPointCenter[i - 1].x.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "pz", _G.WallsPointCenter[i - 1].y.ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "wa", _G.WallsAngle[i - 1].ToString(CultureInfo.InvariantCulture)); WriteElem(xw, "texturecode", GetTextureCode("w" + i.ToString())); xw.WriteEndElement(); } // WallPointPositions (robust, no LINQ, null-safe) { var sb = new StringBuilder(); foreach (var node in WallCreationManager.GetWallPointContainer()) { RectTransform rt = null; if (node is RectTransform rtx) rt = rtx; else if (node is Transform tf) rt = tf as RectTransform; else if (node is GameObject go) rt = go.transform as RectTransform; else if (node is Component comp) rt = comp.transform as RectTransform; if (rt == null) continue; Vector2 pos; var wp = rt.GetComponent(); if (wp != null) pos = wp.GetAnchoredPosition(); else pos = rt.anchoredPosition; if (sb.Length > 0) sb.Append(';'); sb.Append(pos.x.ToString(CultureInfo.InvariantCulture)) .Append(',') .Append(pos.y.ToString(CultureInfo.InvariantCulture)); } WriteElem(xw, "WallPointPositions", sb.ToString()); } // WallPointPairings (robust, no LINQ, null-safe) { var sb = new StringBuilder(); foreach (var node in WallCreationManager.GetWallLineContainer()) { // Normalize to a Component to access transform + GetComponent Component comp = null; if (node is Component c) comp = c; else if (node is GameObject go) comp = go.transform; else if (node is Transform tf) comp = tf; if (comp == null) continue; var wall = comp.GetComponent(); if (wall == null || wall._pointStart == null || wall._pointEnd == null) continue; int a = wall._pointStart.transform.GetSiblingIndex(); int b = wall._pointEnd.transform.GetSiblingIndex(); if (sb.Length > 0) sb.Append(';'); sb.Append(a.ToString(CultureInfo.InvariantCulture)) .Append(',') .Append(b.ToString(CultureInfo.InvariantCulture)); } WriteElem(xw, "WallPointPairings", sb.ToString()); } // CEIL xw.WriteStartElement("CEIL"); WriteElem(xw, "texturecode", "none,#ffffff,#A6A6A6,#ffffff,0.25-0.25,0,1,0,0,0"); xw.WriteEndElement(); // FLOOR xw.WriteStartElement("FLOOR"); WriteElem(xw, "code", _G.FLCs ?? string.Empty); xw.WriteEndElement(); xw.WriteRaw(ObjectsXmlSafe()); xw.WriteComment(" END "); // footer marker xw.WriteEndElement(); // Room xw.WriteEndDocument(); xw.Flush(); } // return AFTER disposing XmlWriter, inside the MemoryStream using return ms.ToArray(); } } //-----------Object Save----------------- static string ObjectsXmlSafe() { var sb = new StringBuilder(); for (int i = 0; i <= _G.OBJnum; i++) { var obj = _G.OBJs[i]; if (obj == null) continue; if (obj.Length == 0) continue; if (obj[2] != "Cabinet" && obj[0] != "null" && IsInsideRoom(obj)) { var tag = $"OBJECT{SN}"; sb.Append('<').Append(tag).Append('>'); var idPrefix = (obj[0]?.Length ?? 0) >= 4 ? obj[0].Substring(0, 4) : obj[0]; AppendTag(sb, "O0", $"{idPrefix}{SN}"); for (int n = 1; n < Math.Min(100, obj.Length); n++) { var v = obj[n]; if (string.IsNullOrEmpty(v) || v == "none") continue; AppendTag(sb, $"O{n}", v); } sb.Append("'); SN++; } } return sb.ToString(); } static bool IsInsideRoom(string[] ADN) { float px = DOIT.ConvertStringToNumber(ADN[15]); float py = DOIT.ConvertStringToNumber(ADN[16]); float pz = DOIT.ConvertStringToNumber(ADN[17]); // Etendue reelle de la piece. Pour une piece dessinee, WIDE/DEPTH ne refletent pas // toujours la vraie taille (un mur peut depasser 192), ce qui rejetait a tort les objets // places loin du centre. On borne donc sur la boite englobante des points de mur. // px/pz sont dans l'espace scene (= WallPoints2D / 2). float minX = -_G.WIDE * 0.5f, maxX = _G.WIDE * 0.5f; float minZ = -_G.DEPTH * 0.5f, maxZ = _G.DEPTH * 0.5f; if (_G.WallPoints2D != null && _G.WallPoints2D.Count > 0) { minX = maxX = _G.WallPoints2D[0].x * 0.5f; minZ = maxZ = _G.WallPoints2D[0].y * 0.5f; foreach (Vector2 p in _G.WallPoints2D) { float x = p.x * 0.5f, z = p.y * 0.5f; if (x < minX) minX = x; else if (x > maxX) maxX = x; if (z < minZ) minZ = z; else if (z > maxZ) maxZ = z; } } if (px > maxX + 12 || px < minX - 12) return false; if (pz > maxZ + 12 || pz < minZ - 12) return false; if (py > _G.HEIGHT * 0.5f + 12 || py < -_G.HEIGHT * 0.5f - 12) return false; return true; } static void AppendTag(StringBuilder sb, string name, string value) { sb.Append('<').Append(name).Append('>'); XmlEscape(sb, value ?? string.Empty); sb.Append("'); } static void XmlEscape(StringBuilder sb, string s) { foreach (var ch in s) { switch (ch) { case '&': sb.Append("&"); break; case '<': sb.Append("<"); break; case '>': sb.Append(">"); break; case '"': sb.Append("""); break; case '\'': sb.Append("'"); break; default: sb.Append(ch); break; } } } // ---------- helpers ---------- static void SetGlobal() { _G.WallsWidth = [.. _G.WallsWidth]; _G.WallsPointCenter= [.. _G.WallsPointCenter]; //G.wCP _G.WallsAngle= [.. _G.wa]; } static void WriteElem(XmlWriter xw, string name, string value) { xw.WriteStartElement(name); xw.WriteString(value ?? string.Empty); // XmlWriter escapes automatically xw.WriteEndElement(); } static string GetLightSettingSafe() { if (_G.LightSetting == null || _G.LightSetting.Count == 0) return string.Empty; return string.Join("?", _G.LightSetting.Select(kv => $"{kv.Key}:{kv.Value.ToString()}")); } static string GetPreferencesSafe() { if (_G.PreferencesList == null || _G.PreferencesList.Count == 0) return string.Empty; return string.Join("?", _G.PreferencesList.Select(kv => $"{kv.Key}:{kv.Value.ToString()}")); } static string GetGlobalSettingSafe(int number) { if (_G.UIT_LibraryGlobalStart != null && number >= 0 && number < _G.UIT_LibraryGlobalStart.Count) { var val = _G.UIT_LibraryGlobalStart[number]; return string.IsNullOrWhiteSpace(val) ? "none" : val; } return "none"; } static string GetClientInfoSafe() { if (_G.ClientInfo == null || _G.ClientInfo.Count == 0) return string.Empty; return string.Join("?", _G.ClientInfo.Select(kv => $"{kv.Key}:{(kv.Value ?? string.Empty)}")); } static string GetYourLibrarySafe() { if (_G.UIT_LibraryCabTextures == null || _G.UIT_LibraryCabTextures.Count == 0) return string.Empty; var cleaned = _G.UIT_LibraryCabTextures .Select(line => (line ?? string.Empty).Replace("Unique_Name", "UniqueName")) .ToArray(); return string.Join("_", cleaned); } static string GetTextureCode(string W) { string Color = _G.Wallcolor; return "none," + Color + ",#A6A6A6,#ffffff,0.25-0.25,0,1,0,0,0"; } public static void BuildWallsData_NonClosedButLoopLastToFirst() { string WALLSPOINTS= string.Join(" / ", _G.WallPoints2D); Debug.Log("Oname===========================================_G.WallSELECTED=="+WALLSPOINTS); var pts = _G.WallPoints2D; // List if (pts == null || pts.Count < 2) return; int nPts = pts.Count; // Nombre de murs = nombre de points (car on ferme dernier->premier) _G.NW = nPts-1; EnsureSize(ref _G.WallsWidth, _G.NW); EnsureSize(ref _G.WallsPointCenter, _G.NW); EnsureSize(ref _G.WallsAngle, _G.NW); for (int i = 0; i < _G.NW; i++) { Vector2 a = pts[i]; Vector2 b = (i == nPts - 1) ? pts[0] : pts[i + 1]; // ferme le dernier mur Vector2 ab = b - a; // Largeur (longueur) du mur _G.WallsWidth[i] = ab.magnitude*0.5f; // Centre du mur _G.WallsPointCenter[i] = (a + b) * 0.5f; // Angle 0..360 (0 = +X, 90 = +Y) float ang = -Mathf.Atan2(ab.y, ab.x) * Mathf.Rad2Deg; if (ang < 0f) ang += 360f; _G.WallsAngle[i] = ang; } } private static void EnsureSize(ref List list, int size) { if (list == null) list = new List(size); if (list.Count > size) list.RemoveRange(size, list.Count - size); while (list.Count < size) list.Add(default); } }