From c6a994164e5062762fdfb2114e365aadfbd37f9f Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 12:19:26 +0100 Subject: [PATCH 01/15] add/data/other-types-of-export [1.2.3-add-data-other-types-of-.0] begin --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f61bee..7c9e3be 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "fantasy-maphub", "name_full": "Fantasy MapHub Generators", - "version": "1.2.2", + "version": "1.2.3-add-data-other-types-of-.0", "description": "An offline-first hub that bundles several Watabou map generators into one consistent web app: same UI patterns, local assets, and modern import/export. It adds OpenAPI docs, proto-first serialization (including pure protobuf files), and a PWA build so everything works without an internet connection.", "license": "MPL-2.0", "author": "mail@sunsung.fun", From 58deb12a9a0f08782ffc1ebda9115ddca2281a08 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 13:44:49 +0100 Subject: [PATCH 02/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.0]=20=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BD=D0=B0=D1=8F=20=D1=81=D1=82=D1=80=D1=83?= =?UTF-8?q?=D0=BA=D1=82=D1=83=D1=80=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=BC=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B5=D0=BA=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protobuf/data/dwellings/decor.proto | 23 +++++++++++++++++++ protobuf/data/dwellings/enum.proto | 21 ++++++++++++++++- .../data/dwellings/{lvl.proto => level.proto} | 21 +++++++++-------- protobuf/data/dwellings/obj.proto | 11 ++++++++- protobuf/data/dwellings/types.proto | 22 ++++++++++++++++++ src/js/Village.js | 8 ++----- 6 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 protobuf/data/dwellings/decor.proto rename protobuf/data/dwellings/{lvl.proto => level.proto} (54%) create mode 100644 protobuf/data/dwellings/types.proto diff --git a/protobuf/data/dwellings/decor.proto b/protobuf/data/dwellings/decor.proto new file mode 100644 index 0000000..11fd981 --- /dev/null +++ b/protobuf/data/dwellings/decor.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package data; + +import "data/dwellings/enum.proto"; +import "data/dwellings/types.proto"; + +// // // // + +message DwellingsLightObj { + DwellingsPointObj pos = 1; + float radius = 2; + float power = 3; + bool on = 4; +} + +message DwellingsPropObj { + DwellingsPropType kind = 1; + DwellingsPointObj pos = 2; + DwellingsEdgeObj wall = 3; + DwellingsEdgeObj from_edge = 4; + DwellingsEdgeObj to_edge = 5; +} diff --git a/protobuf/data/dwellings/enum.proto b/protobuf/data/dwellings/enum.proto index ca81403..a4fd59d 100644 --- a/protobuf/data/dwellings/enum.proto +++ b/protobuf/data/dwellings/enum.proto @@ -17,4 +17,23 @@ enum DwellingsDoorType { NULL = 1; DOORWAY = 2; REGULAR = 3; -} \ No newline at end of file +} + + +enum DwellingsPropType { + PROP_UNSPECIFIED = 0; + ALTAR = 1; + STATUE = 2; + CURTAIN = 3; + BED = 4; +} + +enum DwellingsArchitectureType { + ARCHITECTURE_UNSPECIFIED = 0; + + simple = 1; + castle = 2; + logs = 3; + modern = 4; + scifi = 5; +} diff --git a/protobuf/data/dwellings/lvl.proto b/protobuf/data/dwellings/level.proto similarity index 54% rename from protobuf/data/dwellings/lvl.proto rename to protobuf/data/dwellings/level.proto index 71d2762..94cca5a 100644 --- a/protobuf/data/dwellings/lvl.proto +++ b/protobuf/data/dwellings/level.proto @@ -3,22 +3,20 @@ syntax = "proto3"; package data; import "data/dwellings/enum.proto"; +import "data/dwellings/types.proto"; +import "data/dwellings/decor.proto"; // // // // -message DwellingsCellObj { - int32 i = 1; - int32 j = 2; -} - message DwellingsRoomObj { optional string name = 1; repeated DwellingsCellObj cells = 2; -} + reserved 3 to 9; -message DwellingsEdgeObj { - DwellingsCellObj cell = 1; - DwellingsDirectionType dir = 2; + optional string embed_type_id = 10; + optional DwellingsLightObj embed_light = 11; + repeated DwellingsPropObj embed_props = 12; + optional uint32 embed_decor_seed = 13; } message DwellingsDoorObj { @@ -30,4 +28,7 @@ message DwellingsStairObj { DwellingsCellObj cell = 1; DwellingsDirectionType dir = 2; bool up = 3; -} \ No newline at end of file + reserved 4 to 9; + + optional bool embed_trapdoor = 10; +} diff --git a/protobuf/data/dwellings/obj.proto b/protobuf/data/dwellings/obj.proto index 79eb6d5..bbd9365 100644 --- a/protobuf/data/dwellings/obj.proto +++ b/protobuf/data/dwellings/obj.proto @@ -2,7 +2,9 @@ syntax = "proto3"; package data; -import "data/dwellings/lvl.proto"; +import "data/dwellings/enum.proto"; +import "data/dwellings/types.proto"; +import "data/dwellings/level.proto"; // // // // @@ -12,6 +14,9 @@ message DwellingsPlanObj { repeated DwellingsDoorObj doors = 3; repeated DwellingsEdgeObj windows = 4; repeated DwellingsStairObj stairs = 5; + reserved 6 to 19; + + repeated DwellingsCellObj embed_chimneys = 20; } // @@ -20,4 +25,8 @@ message DwellingsObj { repeated DwellingsPlanObj floors = 1; DwellingsEdgeObj exit = 2; DwellingsEdgeObj spiral = 3; + reserved 4 to 19; + + optional string embed_name = 20; + optional DwellingsArchitectureType embed_architecture = 21; } diff --git a/protobuf/data/dwellings/types.proto b/protobuf/data/dwellings/types.proto new file mode 100644 index 0000000..566bf1a --- /dev/null +++ b/protobuf/data/dwellings/types.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package data; + +import "data/dwellings/enum.proto"; + +// // // // + +message DwellingsCellObj { + int32 i = 1; + int32 j = 2; +} + +message DwellingsPointObj { + float x = 1; + float y = 2; +} + +message DwellingsEdgeObj { + DwellingsCellObj cell = 1; + DwellingsDirectionType dir = 2; +} diff --git a/src/js/Village.js b/src/js/Village.js index 22bc638..0b36733 100644 --- a/src/js/Village.js +++ b/src/js/Village.js @@ -15899,12 +15899,8 @@ var $lime_init = function (E, u) { var d = new Qc; d.addItem("PNG", (G = this.view, r(G, G.exportPNG))); d.addItem("SVG", (G = this.view, r(G, G.exportSVG))); - d.addItem("JSON", function () { - Hh.export(a.village) - }); - d.addItem("PROTO", function () { - Hh.exportBinary(a.village) - }); + d.addItem("JSON", function () {Hh.export(a.village)}); + d.addItem("PROTO", function () {Hh.exportBinary(a.village)}); var f = new Qc, h = this.view; h = this.village.findBuilding(new I(h.map.get_mouseX(), h.map.get_mouseY())); From 430b01d282acfba60b0a15ef042e14f385e9c479 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 14:00:34 +0100 Subject: [PATCH 03/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.0]=20=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=80=D0=B5?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=20=D1=83=D1=85=D0=BE=D0=B4=D1=8F?= =?UTF-8?q?=D1=82=20=D0=B2=20=D0=B5=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/Dwellings.js | 52 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/js/Dwellings.js b/src/js/Dwellings.js index 58bde10..2472f13 100644 --- a/src/js/Dwellings.js +++ b/src/js/Dwellings.js @@ -6574,12 +6574,16 @@ var $lime_init = function (K, v) { return b }; sb.house2proto=function(a){ - for(var b=[],c=0,d=a.floors;c g.length && 0 < b.length + c.length;) 0 < b.length && g.unshift(b.shift()), 0 < c.length && g.push(c.shift()); - c = new di(g[0].a, g[g.length - 1].b); + c = new di(g[0], g[g.length - 1]); a.props.add(c); a.defaultLight(!1) }; var di = function (a, b) { X.call(this); - this.a = a; - this.b = b + this.a = a.a; + this.b = b.b; + this.fromEdge = a; + this.toEdge = b }; h["dwellings.model.props.Curtain"] = di; di.__name__ = "dwellings.model.props.Curtain"; From f280cc29f0d02cd4ec0c062cfd00cd495bf357cd Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 14:19:21 +0100 Subject: [PATCH 04/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.0]=20=20=D0=B4=D0=B0=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=B5=20=D0=BE=D1=82=20=D0=B1=D0=BE=D0=B3=D0=B0=20=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D0=B6=D0=B5=20=D0=BA=20=D0=B1=D0=BE=D0=B3=D0=BE=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=BE=D0=B1=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/Dwellings.js | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/src/js/Dwellings.js b/src/js/Dwellings.js index 2472f13..df6273d 100644 --- a/src/js/Dwellings.js +++ b/src/js/Dwellings.js @@ -6563,8 +6563,8 @@ var $lime_init = function (K, v) { return sb.house2proto(a) }; sb.export=function(a){ - var b=sb.exportProto(a),c=sb.proto2json(b),d=id.fixName(a.name); - id.saveJSON(c,d,!0); + var b=sb.exportProto(a),d=id.fixName(a.name); + id.saveJSON(b,d,!0); return b }; sb.exportAsProto=function(a){ @@ -6667,43 +6667,6 @@ var $lime_init = function (K, v) { }else return null; return b }; - sb.enum2json=function(a,b){ - var c=a[b]; - return c===void 0?b:c - }; - sb.proto2json=function(a){ - for(var b={floors:[],exit:sb.edgeProto2json(a.exit)},c=0,d=a.floors;c Date: Thu, 12 Feb 2026 14:33:43 +0100 Subject: [PATCH 05/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.0]=20=20=D0=B4=D0=BE=D0=BC=D0=B0=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BA=D1=80=D1=8B=D0=BB=D0=B8=20-=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B4=D0=B5=D0=BA=D0=BE=D1=80?= =?UTF-8?q?=20=D0=B2=20=D0=B5=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protobuf/data/dwellings/decor.proto | 8 ++++++++ protobuf/data/dwellings/level.proto | 2 +- src/js/Dwellings.js | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/protobuf/data/dwellings/decor.proto b/protobuf/data/dwellings/decor.proto index 11fd981..f010b0c 100644 --- a/protobuf/data/dwellings/decor.proto +++ b/protobuf/data/dwellings/decor.proto @@ -21,3 +21,11 @@ message DwellingsPropObj { DwellingsEdgeObj from_edge = 4; DwellingsEdgeObj to_edge = 5; } + +message DwellingsPolygonObj { + repeated DwellingsPointObj points = 1; +} + +message DwellingsDecorGroupObj { + repeated DwellingsPolygonObj polygons = 1; +} diff --git a/protobuf/data/dwellings/level.proto b/protobuf/data/dwellings/level.proto index 94cca5a..93c6397 100644 --- a/protobuf/data/dwellings/level.proto +++ b/protobuf/data/dwellings/level.proto @@ -16,7 +16,7 @@ message DwellingsRoomObj { optional string embed_type_id = 10; optional DwellingsLightObj embed_light = 11; repeated DwellingsPropObj embed_props = 12; - optional uint32 embed_decor_seed = 13; + repeated DwellingsDecorGroupObj embed_decor = 13; } message DwellingsDoorObj { diff --git a/src/js/Dwellings.js b/src/js/Dwellings.js index df6273d..77bc2d1 100644 --- a/src/js/Dwellings.js +++ b/src/js/Dwellings.js @@ -6606,6 +6606,7 @@ var $lime_init = function (K, v) { var d=sb.light2proto(a.light); d!=null&&(b.embedLight=d); if(a.props!=null&&a.props.set!=null&&0 Date: Thu, 12 Feb 2026 15:03:26 +0100 Subject: [PATCH 06/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D0=BF=D1=80=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- protobuf/data/geo/obj.proto | 68 ++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7c9e3be..b0dc8a2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "fantasy-maphub", "name_full": "Fantasy MapHub Generators", - "version": "1.2.3-add-data-other-types-of-.0", + "version": "1.2.3-add-data-other-types-of-.1", "description": "An offline-first hub that bundles several Watabou map generators into one consistent web app: same UI patterns, local assets, and modern import/export. It adds OpenAPI docs, proto-first serialization (including pure protobuf files), and a PWA build so everything works without an internet connection.", "license": "MPL-2.0", "author": "mail@sunsung.fun", diff --git a/protobuf/data/geo/obj.proto b/protobuf/data/geo/obj.proto index d6c6b4c..5f604b9 100644 --- a/protobuf/data/geo/obj.proto +++ b/protobuf/data/geo/obj.proto @@ -3,30 +3,90 @@ syntax = "proto3"; package data; import "google/protobuf/struct.proto"; +import "google/protobuf/any.proto"; import "data/geo/enum.proto"; -// // // // +// Метадані перетворення координат для round-trip: +// x_export = cx + x_world * scale +// y_export = cy - y_world * scale (якщо invert_y = true) +// precision_pow10 = 3 означає, що координати округлялись до 1e-3 +message GeoTransformObj { + double scale = 1; // ДОДАНО: масштаб експорту (SCALE) + double cx = 2; // ДОДАНО: зсув по X (CX) + double cy = 3; // ДОДАНО: зсув по Y (CY) + bool invert_y = 4; // ДОДАНО: інверсія осі Y (CY - y*scale) + uint32 precision_pow10 = 5; // ДОДАНО: десяткові знаки округлення (3 => 1e-3) +} + +// Bounding box для швидкого fit-to-view та хіт-тесту +message GeoBBoxObj { + double min_x = 1; // ДОДАНО: min X в експортних координатах + double min_y = 2; // ДОДАНО: min Y в експортних координатах + double max_x = 3; // ДОДАНО: max X в експортних координатах + double max_y = 4; // ДОДАНО: max Y в експортних координатах +} + +// Опис “частини” всередині Multi* геометрій (MultiPolygon/MultiPoint/MultiLineString). +// index відповідає порядку координат у Multi*. +message GeoPartObj { + uint32 index = 1; // ДОДАНО: індекс частини всередині Multi* + string uid = 2; // ДОДАНО: стабільний ID саме цього об’єкта (будинку/дерева/сегмента) + google.protobuf.Struct props = 3; // ДОДАНО: атрибути конкретної частини (тип, клас, висота, тощо) + string name = 4; // ДОДАНО: опціональна назва частини (для UI/дебагу) + GeoBBoxObj bbox = 5; // ДОДАНО: опціональний bbox частини для швидкого selection/hit-test +} message GeoObj { GeoType type = 1; GeoObj geometry = 2; google.protobuf.ListValue coordinates = 3; - reserved 4 to 9; + reserved 4 to 8; + + string embed_uid = 9; + // ДОДАНО: UID для “об’єкта як цілого”, якщо це НЕ Multi* (Polygon/LineString/Point), + // або якщо хочеш мати UID шару/feature. + // Для Multi* деталізація зазвичай іде через embed_parts[].uid. + repeated GeoObj features = 10; repeated GeoObj geometries = 11; - reserved 12 to 19; + + reserved 12 to 16; + + repeated GeoPartObj embed_parts = 17; + // ДОДАНО: метадані для редагування всередині Multi* геометрій. + // Ключове для “редагувати без болю”: можна виділити/пересунути 1 будинок, + // не розпаковуючи MultiPolygon в купу Feature-ів. + + GeoTransformObj embed_export_transform = 18; + // ДОДАНО: трансформація координат експорту. + // Рекомендація: заповнювати на корені FeatureCollection або у values-feature (id=values). + // Можна й локально на шарах, але краще 1 раз у корені. + + GeoBBoxObj embed_bbox = 19; + // ДОДАНО: bbox для об’єкта (корінь/шар/feature). + // Рекомендація: як мінімум — bbox всього файлу на корені або values-feature. optional GeoGeneratorType generator = 20; optional GeoFeatureType id = 21; optional string version = 22; optional string name = 23; optional double width = 24; - reserved 25 to 39; + + reserved 25 to 38; + + google.protobuf.Struct embed_props = 39; + // ДОДАНО: атрибути об’єкта/шару/feature (тип, клас дороги, параметри стилю, джерело, індекси тощо). + // Це замінює “евристики по геометрії” optional double road_width = 40; optional double river_width = 41; optional double tower_radius = 42; optional double wall_thickness = 43; + reserved 44 to 79; + + google.protobuf.Any embed_editor_payload = 80; + // ДОДАНО: опціональний “стан редактора/проєкту” для round-trip, + // якщо треба відновлювати не лише векторну геометрію, а й внутрішню модель (wards/cells/seed/graph). } From 1985c2aac74f7b40fd25a91c23fe923a5d864b67 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 15:21:12 +0100 Subject: [PATCH 07/15] =?UTF-8?q?(no=20branch,=20rebasing=20add/data/other?= =?UTF-8?q?-types-of-export)=20[1.2.3-add-data-other-types-of-.1]=20=20add?= =?UTF-8?q?/data/other-types-of-export=20[1.2.3-add-data-other-types-of-.1?= =?UTF-8?q?]=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=BE=20Sitemap=20=D1=84?= =?UTF-8?q?=D0=BE=D0=BD=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- scripts/generate-sitemap.mjs | 126 +++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 scripts/generate-sitemap.mjs diff --git a/package.json b/package.json index b0dc8a2..e7feb29 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "build:rewrite:tags": "node scripts/replace-tags-dist.mjs", "build:rewrite:minify": "node scripts/minify-static-js.mjs", "build:rewrite:hash-url": "node scripts/add-query-hash.mjs", - "build:list": "run-s build:gen:index-pages build:gen:icons build:gen:languages build:gen:openapi build:rewrite:tags build:rewrite:minify build:rewrite:hash-url", + "build:gen:sitemap": "node scripts/generate-sitemap.mjs", + "build:list": "run-s build:gen:index-pages build:gen:icons build:gen:languages build:gen:openapi build:rewrite:tags build:rewrite:minify build:rewrite:hash-url build:gen:sitemap", "build": "vite build && npm run build:list", "preview": "vite preview", "test": "vitest run", diff --git a/scripts/generate-sitemap.mjs b/scripts/generate-sitemap.mjs new file mode 100644 index 0000000..a8b0891 --- /dev/null +++ b/scripts/generate-sitemap.mjs @@ -0,0 +1,126 @@ +import fs from "node:fs"; +import path from "node:path"; +import * as process from "node:process"; +import { TAGS } from "../static.config.mjs"; + +const DIST_DIR_NAME = "dist"; +const DIST_DIR_PATH = path.resolve(DIST_DIR_NAME); +const OUTPUT_FILE = path.join(DIST_DIR_PATH, "sitemap.xml"); + +const SITE_ORIGIN = "https://"+TAGS.HOMEPAGE; + +const INDEX_BASENAME = "index.html"; +const HTML_EXTENSION = ".html"; + +const EXCLUDED_BASENAMES = new Set(["404.html"]); + +const XML_HEADER = ''; +const URLSET_OPEN = + ''; +const URLSET_CLOSE = ""; + +const ENCODING_UTF8 = "utf8"; +const URL_SEPARATOR = "/"; + +const ERROR_DIST_MISSING = 'dist directory not found. Run "vite build" first.'; +const LOG_DONE = (count) => `OK: sitemap.xml generated with ${count} URL(s).`; + +if (!fs.existsSync(DIST_DIR_PATH)) { + console.error(ERROR_DIST_MISSING); + process.exit(1); +} + +function collectHtmlFiles(rootDir) { + const result = []; + const stack = [rootDir]; + + while (stack.length) { + const dir = stack.pop(); + const entries = fs.readdirSync(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + stack.push(fullPath); + continue; + } + + if (!entry.isFile()) continue; + + const ext = path.extname(entry.name).toLowerCase(); + if (ext !== HTML_EXTENSION) continue; + if (EXCLUDED_BASENAMES.has(entry.name)) continue; + + result.push(fullPath); + } + } + + return result; +} + +function toUrlPath(rootDir, absPath) { + const relPath = path + .relative(rootDir, absPath) + .split(path.sep) + .join(URL_SEPARATOR); + + if (relPath === INDEX_BASENAME) return URL_SEPARATOR; + + if (relPath.endsWith(URL_SEPARATOR + INDEX_BASENAME)) { + return URL_SEPARATOR + relPath.slice(0, -INDEX_BASENAME.length); + } + + return URL_SEPARATOR + relPath; +} + +function lastModISO(absPath) { + const stat = fs.statSync(absPath); + return stat.mtime.toISOString().split("T")[0]; +} + +function escapeXml(value) { + return value + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function buildUrlEntry(loc, lastmod) { + const lines = []; + lines.push(" "); + lines.push(` ${escapeXml(loc)}`); + lines.push(` ${lastmod}`); + lines.push(" "); + return lines.join("\n"); +} + +function buildSitemap(rootDir) { + const htmlFiles = collectHtmlFiles(rootDir); + + const entries = htmlFiles + .map((absPath) => ({ + loc: SITE_ORIGIN + toUrlPath(rootDir, absPath), + lastmod: lastModISO(absPath), + })) + .sort((a, b) => a.loc.localeCompare(b.loc)); + + const parts = [XML_HEADER, URLSET_OPEN]; + + for (const entry of entries) { + parts.push(buildUrlEntry(entry.loc, entry.lastmod)); + } + + parts.push(URLSET_CLOSE); + parts.push(""); + + return { xml: parts.join("\n"), count: entries.length }; +} + +const { xml, count } = buildSitemap(DIST_DIR_PATH); + +fs.writeFileSync(OUTPUT_FILE, xml, ENCODING_UTF8); + +console.log(LOG_DONE(count)); From bbb9560876248cca87c31318dcfd259e3a4b33a5 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 15:26:38 +0100 Subject: [PATCH 08/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D0=BF=D1=80=D0=BE=D0=B4=D0=BE?= =?UTF-8?q?=D0=BB=D0=B6=D0=B0=D1=8E=20=D0=BA=D0=BE=D0=B2=D1=8B=D1=80=D1=8F?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B3=D0=B5=D0=BE=D0=BC=D0=B5=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protobuf/data/geo/obj.proto | 234 +++++++++++++++++++++++++++++------- 1 file changed, 190 insertions(+), 44 deletions(-) diff --git a/protobuf/data/geo/obj.proto b/protobuf/data/geo/obj.proto index 5f604b9..27cba8f 100644 --- a/protobuf/data/geo/obj.proto +++ b/protobuf/data/geo/obj.proto @@ -3,69 +3,219 @@ syntax = "proto3"; package data; import "google/protobuf/struct.proto"; -import "google/protobuf/any.proto"; import "data/geo/enum.proto"; -// Метадані перетворення координат для round-trip: +// // // // + +// Метадані перетворення координат для round-trip. // x_export = cx + x_world * scale // y_export = cy - y_world * scale (якщо invert_y = true) -// precision_pow10 = 3 означає, що координати округлялись до 1e-3 +// precision_pow10 = 3 => округлення до 1e-3 message GeoTransformObj { - double scale = 1; // ДОДАНО: масштаб експорту (SCALE) - double cx = 2; // ДОДАНО: зсув по X (CX) - double cy = 3; // ДОДАНО: зсув по Y (CY) - bool invert_y = 4; // ДОДАНО: інверсія осі Y (CY - y*scale) - uint32 precision_pow10 = 5; // ДОДАНО: десяткові знаки округлення (3 => 1e-3) + double scale = 1; // SCALE + double cx = 2; // CX + double cy = 3; // CY + bool invert_y = 4; // інверсія осі Y + uint32 precision_pow10 = 5; // 3 => 0.001 } -// Bounding box для швидкого fit-to-view та хіт-тесту +// Bounding box (у тій системі координат, в якій лежить geometry/coordinates) message GeoBBoxObj { - double min_x = 1; // ДОДАНО: min X в експортних координатах - double min_y = 2; // ДОДАНО: min Y в експортних координатах - double max_x = 3; // ДОДАНО: max X в експортних координатах - double max_y = 4; // ДОДАНО: max Y в експортних координатах + double min_x = 1; + double min_y = 2; + double max_x = 3; + double max_y = 4; } -// Опис “частини” всередині Multi* геометрій (MultiPolygon/MultiPoint/MultiLineString). -// index відповідає порядку координат у Multi*. +// “Частина” всередині Multi* геометрій. +// index відповідає порядку координат у MultiPolygon/MultiPoint/MultiLineString. message GeoPartObj { - uint32 index = 1; // ДОДАНО: індекс частини всередині Multi* - string uid = 2; // ДОДАНО: стабільний ID саме цього об’єкта (будинку/дерева/сегмента) - google.protobuf.Struct props = 3; // ДОДАНО: атрибути конкретної частини (тип, клас, висота, тощо) - string name = 4; // ДОДАНО: опціональна назва частини (для UI/дебагу) - GeoBBoxObj bbox = 5; // ДОДАНО: опціональний bbox частини для швидкого selection/hit-test + uint32 index = 1; // індекс частини в Multi* + string uid = 2; // стабільний ID частини + google.protobuf.Struct props = 3; // атрибути частини (тип, клас, параметри редагування) + string name = 4; // опціональна назва (UI) + GeoBBoxObj bbox = 5; // опціонально: bbox частини для швидкого hit-test +} + + +// Уточнення: в якій системі координат лежать точки в EditorPayloadObj. +// Рекомендація: WORLD (до застосування export_transform), щоб редагувати “як у редакторі”. +enum EditorCoordSpaceType { + EDITOR_COORD_SPACE_UNSPECIFIED = 0; + + // Координати як у редакторі (world): +Y вгору, без SCALE/CX/CY (або ваша “внутрішня”). + EDITOR_COORD_SPACE_WORLD = 1; + + // Координати як у файлі (export): ті самі, що в GeoObj.coordinates. + EDITOR_COORD_SPACE_EXPORT = 2; +} + +// Проста 2D-точка для редакторських примітивів +message EditorPoint2DObj { + double x = 1; + double y = 2; +} + +// Полілінія (центрлайн, контур для редагування, тощо) +message EditorPolylineObj { + repeated EditorPoint2DObj points = 1; // контрольні/вузлові точки + bool closed = 2; // замкнено (для контурів) +} + +// Кубічний Bezier шлях (для випадків, коли геометрія в файлі вже “дискретизована”, +// а ти хочеш зберегти оригінальні контрольні точки) +message EditorBezierObj { + // Для cubic bezier зазвичай: (P0, C1, C2, P1) * N сегментів. + // Тобто кількість точок кратна 4 або 3+1 залежно від вашої конвенції. + repeated EditorPoint2DObj control_points = 1; + + bool closed = 2; // замкнено + uint32 segments = 3; // підказка: скільки сегментів у control_points +} + +// Дуга (якщо в редакторі є арки, а в експорті лише ламана) +message EditorArcObj { + EditorPoint2DObj center = 1; // центр + double radius = 2; // радіус + double start_angle_rad = 3; // початок (радіани) + double end_angle_rad = 4; // кінець (радіани) + bool ccw = 5; // напрям +} + +// Тип зв’язку між об’єктами (не відновлюється з геометрії) +enum EditorLinkType { + EDITOR_LINK_TYPE_UNSPECIFIED = 0; + + // Структурні + EDITOR_LINK_TYPE_PARENT_CHILD = 1; // b є “дочірній” для a + EDITOR_LINK_TYPE_GROUP_MEMBER = 2; // b входить у групу a (або навпаки — визначіть правило) + + // Геометричні/логічні + EDITOR_LINK_TYPE_ATTACH = 3; // прив’язка (building->plot, tree->district, тощо) + EDITOR_LINK_TYPE_OVER_UNDER = 4; // міст над річкою/дорогою, тунель, рівні + EDITOR_LINK_TYPE_ALONG = 5; // “уздовж” (наприклад, паркани вздовж дороги) +} + +// Опис зв’язку +message EditorLinkObj { + string a_uid = 1; // UID першого об’єкта + string b_uid = 2; // UID другого об’єкта + EditorLinkType type = 3; // тип зв’язку + google.protobuf.Struct props = 4; // опціональні параметри зв’язку (рівень, offset, тощо) +} + +// Стан шарів/видимість/блокування — не відновлюється з геометрії, +// але корисно для “проектного” round-trip (якщо тобі це треба). +message EditorLayerStateObj { + string layer_id = 1; // напр. "roads", "buildings" або enum-ім'я + bool visible = 2; // видимий + bool locked = 3; // заблокований для редагування + int32 z_index = 4; // порядок малювання (якщо є) } +// Групи (виділення “як один об’єкт”, пакетні операції) — теж не відновлюються з геометрії. +message EditorGroupObj { + string group_uid = 1; // UID групи + string name = 2; // назва групи + repeated string member_uids = 3; // члени групи + google.protobuf.Struct props = 4; // опціональні атрибути +} + +// Дороги часто рендеряться як полігони, але редагуються як центрлінія + ширина. +// З полігону центрлінію відновити однозначно не можна -> зберігаємо її явно. +message EditorRoadModelObj { + string target_uid = 1; // UID дороги (або UID частини, якщо Multi*) + EditorPolylineObj centerline = 2; // центрлайн для редагування + double width = 3; // ширина (якщо не хочеш шукати в props) + bool closed = 4; // для кільцевих доріг (опціонально) + google.protobuf.Struct props = 5; // клас дороги, обмеження, тощо +} + +// Узагальнена “редакторська форма” для об’єкта, коли експортна геометрія — вже результат, +// а редагувати хочеться “по контрольних точках/примітивах”. +message EditorShapeModelObj { + string target_uid = 1; // UID об’єкта/частини, до якого відноситься модель + + oneof model { + EditorPolylineObj polyline = 2; // редагувати як полілінію (напр. річка/паркан/дорога-ось) + EditorBezierObj bezier = 3; // редагувати як bezier + EditorArcObj arc = 4; // редагувати як арку + } + + google.protobuf.Struct props = 10; // параметри моделі (tessellation, snapping, тощо) +} + +// Снап-ноди (вузли) для стабільного графа/стикування. +// Перетини/вузли з полігонів/ламаниx відновлюються не завжди стабільно (особливо після ручних правок), +// тому якщо у редактора є “граф” — збережи його явно. +message EditorSnapNodeObj { + string node_uid = 1; // UID вузла + EditorPoint2DObj pos = 2; // позиція + repeated string incident_uids = 3; // які об’єкти/сегменти під’єднані (UID) + google.protobuf.Struct props = 4; // тип вузла, пріоритет, тощо +} + +// Обмеження/констрейнти (якщо у редакторі є): паралельність, фіксована довжина, тощо. +// Це 100% не відновлюється з геометрії. +enum EditorConstraintType { + EDITOR_CONSTRAINT_TYPE_UNSPECIFIED = 0; + EDITOR_CONSTRAINT_TYPE_SNAP = 1; + EDITOR_CONSTRAINT_TYPE_FIXED_LENGTH = 2; + EDITOR_CONSTRAINT_TYPE_PARALLEL = 3; + EDITOR_CONSTRAINT_TYPE_PERPENDICULAR = 4; +} + +message EditorConstraintObj { + string constraint_uid = 1; // UID обмеження + EditorConstraintType type = 2; // тип + repeated string target_uids = 3; // до чого прив’язано (UID об’єктів/частин/нод) + google.protobuf.Struct params = 4; // параметри (довжина, кут, допуск, тощо) +} + +// Головний payload для round-trip редагування без Any. +// УСЕ ТУТ — опціональне: імпортер має вміти працювати, навіть якщо payload порожній, +// використовуючи embed_uid/embed_parts/embed_props + geometry. +message EditorPayloadObj { + uint32 payload_rev = 1; // ревізія формату payload (для міграцій) + EditorCoordSpaceType coord_space = 2; // WORLD або EXPORT + + // Проектні/редакторські речі (не обов’язково) + repeated EditorLayerStateObj layers = 10; // стани шарів (visible/locked/z) + repeated EditorGroupObj groups = 11; // групи + repeated EditorLinkObj links = 12; // зв’язки між об’єктами + + // Редакторські моделі геометрії (те, що не відновиш з “готової” геометрії) + repeated EditorRoadModelObj road_models = 20; // центрлайни доріг + ширини + repeated EditorShapeModelObj shape_models = 21; // сплайни/арки/редакторські ламані + + // Граф/снапінг/констрейнти (за потреби) + repeated EditorSnapNodeObj snap_nodes = 30; + repeated EditorConstraintObj constraints = 31; + + // Глобальні параметри редактора/проекту (опційно): одиниці, дефолти стилю, тощо + google.protobuf.Struct props = 40; +} + +// =========================================================== + message GeoObj { GeoType type = 1; GeoObj geometry = 2; google.protobuf.ListValue coordinates = 3; - reserved 4 to 8; - string embed_uid = 9; - // ДОДАНО: UID для “об’єкта як цілого”, якщо це НЕ Multi* (Polygon/LineString/Point), - // або якщо хочеш мати UID шару/feature. - // Для Multi* деталізація зазвичай іде через embed_parts[].uid. + reserved 4 to 7; + string embed_uid = 8; // UID об’єкта (або шару/feature). Для Multi* зазвичай UID-и в embed_parts. + string embed_name = 9; // Додаткове ім'я (щоб не плутатись з існуючим `name`) repeated GeoObj features = 10; repeated GeoObj geometries = 11; reserved 12 to 16; - repeated GeoPartObj embed_parts = 17; - // ДОДАНО: метадані для редагування всередині Multi* геометрій. - // Ключове для “редагувати без болю”: можна виділити/пересунути 1 будинок, - // не розпаковуючи MultiPolygon в купу Feature-ів. - - GeoTransformObj embed_export_transform = 18; - // ДОДАНО: трансформація координат експорту. - // Рекомендація: заповнювати на корені FeatureCollection або у values-feature (id=values). - // Можна й локально на шарах, але краще 1 раз у корені. - - GeoBBoxObj embed_bbox = 19; - // ДОДАНО: bbox для об’єкта (корінь/шар/feature). - // Рекомендація: як мінімум — bbox всього файлу на корені або values-feature. + repeated GeoPartObj embed_parts = 17; // Метадані частин Multi* + GeoTransformObj embed_export_transform = 18; // Transform для round-trip + GeoBBoxObj embed_bbox = 19; // bbox (файл/шар/об’єкт) optional GeoGeneratorType generator = 20; optional GeoFeatureType id = 21; @@ -75,9 +225,7 @@ message GeoObj { reserved 25 to 38; - google.protobuf.Struct embed_props = 39; - // ДОДАНО: атрибути об’єкта/шару/feature (тип, клас дороги, параметри стилю, джерело, індекси тощо). - // Це замінює “евристики по геометрії” + google.protobuf.Struct embed_props = 39; // Атрибути об’єкта/шару/feature optional double road_width = 40; optional double river_width = 41; @@ -86,7 +234,5 @@ message GeoObj { reserved 44 to 79; - google.protobuf.Any embed_editor_payload = 80; - // ДОДАНО: опціональний “стан редактора/проєкту” для round-trip, - // якщо треба відновлювати не лише векторну геометрію, а й внутрішню модель (wards/cells/seed/graph). + EditorPayloadObj embed_editor_payload = 80; } From 29986637a4ccff38a31bb32d4c1c536f7fe3509d Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 17:43:58 +0100 Subject: [PATCH 09/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D0=BF=D0=BE=D0=BB=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=B5=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B3=D0=BE=D1=80=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/mfcg.js | 220 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 214 insertions(+), 6 deletions(-) diff --git a/src/js/mfcg.js b/src/js/mfcg.js index c981e59..fe26aa9 100644 --- a/src/js/mfcg.js +++ b/src/js/mfcg.js @@ -7892,18 +7892,52 @@ var $lime_init = function (A, t) { }; g.JsonExporter = lg, lg.__name__ = "JsonExporter", + lg.jsToValue = function (a) { + if (a === null || a === void 0) return new DataProto.default.google.protobuf.Value({nullValue: 0}); + if (a instanceof DataProto.default.google.protobuf.Value) return a; + if (Array.isArray(a)) return new DataProto.default.google.protobuf.Value({listValue: lg.toListValue(a)}); + switch (typeof a) { + case "number": + return new DataProto.default.google.protobuf.Value({numberValue: a}); + case "string": + return new DataProto.default.google.protobuf.Value({stringValue: a}); + case "boolean": + return new DataProto.default.google.protobuf.Value({boolValue: a}); + case "object": + return new DataProto.default.google.protobuf.Value({structValue: lg.toStruct(a)}); + default: + return new DataProto.default.google.protobuf.Value({stringValue: String(a)}) + } + }, lg.toValue = function (a) { - return a instanceof DataProto.default.google.protobuf.Value ? a : Array.isArray(a) ? new DataProto.default.google.protobuf.Value({listValue: lg.toListValue(a)}) : new DataProto.default.google.protobuf.Value({numberValue: a}) + return lg.jsToValue(a) }, lg.toListValue = function (a) { for (var b = [], c = 0; c < a.length;) { var d = a[c]; - ++c, b.push(lg.toValue(d)) + ++c, b.push(lg.jsToValue(d)) } return new DataProto.default.google.protobuf.ListValue({values: b}) }, + lg.toStruct = function (a) { + if (a == null || typeof a !== "object" || Array.isArray(a)) return new DataProto.default.google.protobuf.Struct({fields: {}}); + var b = {}, c = Object.keys(a), d = 0; + for (; d < c.length;) { + var f = c[d++], h = a[f]; + h === null || h === void 0 || (b[f] = lg.jsToValue(h)) + } + return new DataProto.default.google.protobuf.Struct({fields: b}) + }, + lg.structToJson = function (a) { + var b = {}; + if (a != null && a.fields != null) for (var c = Object.keys(a.fields), d = 0; d < c.length;) { + var f = c[d++]; + b[f] = lg.valueToJson(a.fields[f]) + } + return b + }, lg.valueToJson = function (a) { - return a == null ? null : a.listValue != null && Object.hasOwnProperty.call(a, "listValue") ? lg.listValueToJson(a.listValue) : a.numberValue != null && Object.hasOwnProperty.call(a, "numberValue") ? a.numberValue : a.stringValue != null && Object.hasOwnProperty.call(a, "stringValue") ? a.stringValue : a.boolValue != null && Object.hasOwnProperty.call(a, "boolValue") ? a.boolValue : null + return a == null ? null : a.listValue != null && Object.hasOwnProperty.call(a, "listValue") ? lg.listValueToJson(a.listValue) : a.structValue != null && Object.hasOwnProperty.call(a, "structValue") ? lg.structToJson(a.structValue) : a.numberValue != null && Object.hasOwnProperty.call(a, "numberValue") ? a.numberValue : a.stringValue != null && Object.hasOwnProperty.call(a, "stringValue") ? a.stringValue : a.boolValue != null && Object.hasOwnProperty.call(a, "boolValue") ? a.boolValue : a.nullValue != null && Object.hasOwnProperty.call(a, "nullValue") ? null : null }, lg.listValueToJson = function (a) { for (var b = [], c = 0, d = a.values; c < d.length;) { @@ -7912,6 +7946,132 @@ var $lime_init = function (A, t) { } return b }, + lg.makeTransform = function () { + var a = new DataProto.data.GeoTransformObj; + return a.scale = Wa.SCALE, a.cx = Wa.CX, a.cy = Wa.CY, a.invertY = !0, a.precisionPow10 = 3, a + }, + lg._bboxWalk = function (a, b) { + if (a == null) return; + if (Array.isArray(a)) { + if (2 <= a.length && typeof a[0] === "number" && typeof a[1] === "number") { + var c = a[0], d = a[1]; + c < b.minX && (b.minX = c); + d < b.minY && (b.minY = d); + c > b.maxX && (b.maxX = c); + d > b.maxY && (b.maxY = d); + return + } + for (c = 0; c < a.length;) d = a[c], ++c, lg._bboxWalk(d, b) + } + }, + lg.bboxFromCoords = function (a) { + var b = {minX: 1 / 0, minY: 1 / 0, maxX: -1 / 0, maxY: -1 / 0}; + lg._bboxWalk(a, b); + if (b.minX === 1 / 0) return null; + var c = new DataProto.data.GeoBBoxObj; + return c.minX = b.minX, c.minY = b.minY, c.maxX = b.maxX, c.maxY = b.maxY, c + }, + lg.mergeBbox = function (a, b) { + if (a == null) return b; + if (b == null) return a; + var c = new DataProto.data.GeoBBoxObj; + return c.minX = Math.min(a.minX, b.minX), c.minY = Math.min(a.minY, b.minY), c.maxX = Math.max(a.maxX, b.maxX), c.maxY = Math.max(a.maxY, b.maxY), c + }, + lg.computeBbox = function (a) { + if (a == null) return null; + var b = null; + if (a.coordinates != null && Object.hasOwnProperty.call(a, "coordinates")) { + var c = lg.listValueToJson(a.coordinates); + b = lg.bboxFromCoords(c) + } else if (a.geometry != null && Object.hasOwnProperty.call(a, "geometry")) b = lg.computeBbox(a.geometry); + else if (a.features != null && a.features.length) { + c = 0; + for (var d = a.features; c < d.length;) { + var f = d[c]; + ++c; + b = lg.mergeBbox(b, lg.computeBbox(f)) + } + } else if (a.geometries != null && a.geometries.length) { + c = 0; + for (d = a.geometries; c < d.length;) f = d[c], ++c, b = lg.mergeBbox(b, lg.computeBbox(f)) + } + return b + }, + lg.ensureParts = function (a) { + if (a == null) return; + if (!(a.type == DataProto.data.GeoType.MultiPolygon || a.type == DataProto.data.GeoType.MultiPoint || a.type == DataProto.data.GeoType.MultiLineString)) return; + if (a.coordinates == null || !Object.hasOwnProperty.call(a, "coordinates")) return; + if (a.embedParts != null && a.embedParts.length) return; + var b = lg.listValueToJson(a.coordinates); + if (!Array.isArray(b)) return; + a.embedParts = []; + for (var c = 0; c < b.length;) { + var d = c, f = b[c++]; + var h = new DataProto.data.GeoPartObj; + h.index = d; + h.uid = (a.embedUid != null && Object.hasOwnProperty.call(a, "embedUid") ? a.embedUid : "obj") + ":part:" + d; + a.name != null && Object.hasOwnProperty.call(a, "name") && (h.name = "" + a.name + " #" + (d + 1)); + var k = lg.bboxFromCoords(f); + k != null && (h.bbox = k); + h.props = lg.toStruct({parentUid: a.embedUid, index: d}); + a.embedParts.push(h) + } + }, + lg.buildPropsForObj = function (a) { + if (a == null) return null; + var b = {geoType: DataProto.data.GeoType[a.type]}; + a.id != null && Object.hasOwnProperty.call(a, "id") && (b.featureId = DataProto.data.GeoFeatureType[a.id]); + a.width != null && Object.hasOwnProperty.call(a, "width") && (b.width = a.width); + a.roadWidth != null && Object.hasOwnProperty.call(a, "roadWidth") && (b.roadWidth = a.roadWidth); + a.riverWidth != null && Object.hasOwnProperty.call(a, "riverWidth") && (b.riverWidth = a.riverWidth); + a.towerRadius != null && Object.hasOwnProperty.call(a, "towerRadius") && (b.towerRadius = a.towerRadius); + a.wallThickness != null && Object.hasOwnProperty.call(a, "wallThickness") && (b.wallThickness = a.wallThickness); + a.generator != null && Object.hasOwnProperty.call(a, "generator") && (b.generator = DataProto.data.GeoGeneratorType[a.generator]); + a.version != null && Object.hasOwnProperty.call(a, "version") && (b.version = a.version); + a.embedUid != null && Object.hasOwnProperty.call(a, "embedUid") && (b.uid = a.embedUid); + a.embedName != null && Object.hasOwnProperty.call(a, "embedName") && (b.displayName = a.embedName); + return b + }, + lg.enrichGeoObj = function (a, b) { + if (a == null) return; + a.embedExportTransform == null && b != null && b.transform != null && (a.embedExportTransform = b.transform); + (a.embedUid == null || "" === a.embedUid) && b != null && b.uid != null && (a.embedUid = b.uid); + a.embedName == null && (a.name != null && Object.hasOwnProperty.call(a, "name") ? a.embedName = a.name : a.id != null && Object.hasOwnProperty.call(a, "id") && (a.embedName = DataProto.data.GeoFeatureType[a.id])); + if (a.embedProps == null) { + var c = lg.buildPropsForObj(a); + c != null && (a.embedProps = lg.toStruct(c)) + } + lg.ensureParts(a); + a.embedBbox == null && (a.embedBbox = lg.computeBbox(a)); + if (a.geometry != null && Object.hasOwnProperty.call(a, "geometry")) lg.enrichGeoObj(a.geometry, {uid: a.embedUid + "/geometry", transform: a.embedExportTransform}); + if (a.features != null && a.features.length) for (c = 0; c < a.features.length;) { + var d = a.features[c], f = d != null && d.id != null && Object.hasOwnProperty.call(d, "id") ? DataProto.data.GeoFeatureType[d.id] : "" + c; + ++c; + lg.enrichGeoObj(d, {uid: a.embedUid + "/features/" + f, transform: a.embedExportTransform}) + } + if (a.geometries != null && a.geometries.length) for (c = 0; c < a.geometries.length;) d = a.geometries[c], f = "" + c, ++c, lg.enrichGeoObj(d, {uid: a.embedUid + "/geometries/" + f, transform: a.embedExportTransform}) + }, + lg.makeEditorPayload = function (a) { + ba.init(); + za.init(); + var b = new DataProto.data.EditorPayloadObj; + b.payloadRev = 1; + b.coordSpace = DataProto.data.EditorCoordSpaceType.EDITOR_COORD_SPACE_EXPORT; + var c = {state: ba.data, url: za.data}; + a != null && (c.blueprint = a.bp, c.name = a.name); + b.props = lg.toStruct(c); + return b + }, + lg.enrichRoot = function (a, b) { + if (a == null) return; + var c = lg.makeTransform(); + a.embedExportTransform = c; + a.embedUid = "root"; + b != null && b.name != null && (a.embedName = b.name); + a.embedEditorPayload = lg.makeEditorPayload(b); + a.embedProps == null && (a.embedProps = lg.toStruct({generator: "mfcg", version: A.current.meta.h.version, blueprint: b != null ? b.bp : null, state: ba.data, url: za.data})); + lg.enrichGeoObj(a, {uid: "root", transform: c}) + }, lg.toJsonObject = function (a) { var b = DataProto.data.GeoType[a.type], c = {type: b}; a.id != null && Object.hasOwnProperty.call(a, "id") && (c.id = DataProto.data.GeoFeatureType[a.id]); @@ -7923,6 +8083,52 @@ var $lime_init = function (A, t) { a.generator != null && Object.hasOwnProperty.call(a, "generator") && (c.generator = DataProto.data.GeoGeneratorType[a.generator]); a.version != null && Object.hasOwnProperty.call(a, "version") && (c.version = a.version); a.riverWidth != null && Object.hasOwnProperty.call(a, "riverWidth") && (c.riverWidth = a.riverWidth); + a.embedUid != null && Object.hasOwnProperty.call(a, "embedUid") && (c.embedUid = a.embedUid); + a.embedName != null && Object.hasOwnProperty.call(a, "embedName") && (c.embedName = a.embedName); + a.embedExportTransform != null && Object.hasOwnProperty.call(a, "embedExportTransform") && (c.embedExportTransform = {scale: a.embedExportTransform.scale, cx: a.embedExportTransform.cx, cy: a.embedExportTransform.cy, invertY: a.embedExportTransform.invertY, precisionPow10: a.embedExportTransform.precisionPow10}); + a.embedBbox != null && Object.hasOwnProperty.call(a, "embedBbox") && (c.embedBbox = {minX: a.embedBbox.minX, minY: a.embedBbox.minY, maxX: a.embedBbox.maxX, maxY: a.embedBbox.maxY}); + a.embedProps != null && Object.hasOwnProperty.call(a, "embedProps") && (c.embedProps = lg.structToJson(a.embedProps)); + if (a.embedParts != null && a.embedParts.length) { + c.embedParts = []; + for (var d2 = 0; d2 < a.embedParts.length;) { + var f2 = a.embedParts[d2++]; + c.embedParts.push({ + index: f2.index, + uid: f2.uid, + name: f2.name, + bbox: f2.bbox != null ? {minX: f2.bbox.minX, minY: f2.bbox.minY, maxX: f2.bbox.maxX, maxY: f2.bbox.maxY} : null, + props: f2.props != null ? lg.structToJson(f2.props) : null + }) + } + } + if (a.embedEditorPayload != null && Object.hasOwnProperty.call(a, "embedEditorPayload")) { + var h2 = a.embedEditorPayload, k2 = {}; + h2.payloadRev != null && Object.hasOwnProperty.call(h2, "payloadRev") && (k2.payloadRev = h2.payloadRev); + h2.coordSpace != null && Object.hasOwnProperty.call(h2, "coordSpace") && (k2.coordSpace = DataProto.data.EditorCoordSpaceType[h2.coordSpace]); + h2.layers != null && h2.layers.length && (k2.layers = h2.layers.map(function (a2) { + return {layerId: a2.layerId, visible: a2.visible, locked: a2.locked, zIndex: a2.zIndex} + })); + h2.groups != null && h2.groups.length && (k2.groups = h2.groups.map(function (a2) { + return {groupUid: a2.groupUid, name: a2.name, memberUids: a2.memberUids, props: a2.props != null ? lg.structToJson(a2.props) : null} + })); + h2.links != null && h2.links.length && (k2.links = h2.links.map(function (a2) { + return {aUid: a2.aUid, bUid: a2.bUid, type: DataProto.data.EditorLinkType[a2.type], props: a2.props != null ? lg.structToJson(a2.props) : null} + })); + h2.roadModels != null && h2.roadModels.length && (k2.roadModels = h2.roadModels.map(function (a2) { + return {targetUid: a2.targetUid, centerline: a2.centerline != null ? {closed: a2.centerline.closed, points: a2.centerline.points} : null, width: a2.width, closed: a2.closed, props: a2.props != null ? lg.structToJson(a2.props) : null} + })); + h2.shapeModels != null && h2.shapeModels.length && (k2.shapeModels = h2.shapeModels.map(function (a2) { + return {targetUid: a2.targetUid, polyline: a2.polyline, bezier: a2.bezier, arc: a2.arc, props: a2.props != null ? lg.structToJson(a2.props) : null} + })); + h2.snapNodes != null && h2.snapNodes.length && (k2.snapNodes = h2.snapNodes.map(function (a2) { + return {nodeUid: a2.nodeUid, pos: a2.pos, incidentUids: a2.incidentUids, props: a2.props != null ? lg.structToJson(a2.props) : null} + })); + h2.constraints != null && h2.constraints.length && (k2.constraints = h2.constraints.map(function (a2) { + return {constraintUid: a2.constraintUid, type: DataProto.data.EditorConstraintType[a2.type], targetUids: a2.targetUids, params: a2.params != null ? lg.structToJson(a2.params) : null} + })); + h2.props != null && Object.hasOwnProperty.call(h2, "props") && (k2.props = lg.structToJson(h2.props)); + c.embedEditorPayload = k2 + } switch (a.type) { case DataProto.data.GeoType.Feature: a.geometry != null && Object.hasOwnProperty.call(a, "geometry") && (c.geometry = lg.toJsonObject(a.geometry)); @@ -8071,11 +8277,14 @@ var $lime_init = function (A, t) { n = []; g2 = k.keys(); for (; g2.hasNext();) l2 = g2.next(), n.push(l2); - return b = lg.featureCollection([p, q2, u2, w2, r2, lg.multiThick(DataProto.data.GeoFeatureType.planks, n, null, function (a2) { + b = lg.featureCollection([p, q2, u2, w2, r2, lg.multiThick(DataProto.data.GeoFeatureType.planks, n, null, function (a2) { return a2 }, function (a2) { return k.h[a2.__id__] - }), lg.multiPolygon(DataProto.data.GeoFeatureType.buildings, b), lg.multiPolygon(DataProto.data.GeoFeatureType.prisms, c), lg.multiPolygon(DataProto.data.GeoFeatureType.squares, d), lg.multiPolygon(DataProto.data.GeoFeatureType.greens, f), lg.multiPolygon(DataProto.data.GeoFeatureType.fields, h), lg.multiPoint(DataProto.data.GeoFeatureType.trees, x2), m]), 0 < a.waterEdgeE.length && b.features.push(lg.multiPolygon(DataProto.data.GeoFeatureType.water, [Ua.toPoly(a.waterEdgeE)])), b + }), lg.multiPolygon(DataProto.data.GeoFeatureType.buildings, b), lg.multiPolygon(DataProto.data.GeoFeatureType.prisms, c), lg.multiPolygon(DataProto.data.GeoFeatureType.squares, d), lg.multiPolygon(DataProto.data.GeoFeatureType.greens, f), lg.multiPolygon(DataProto.data.GeoFeatureType.fields, h), lg.multiPoint(DataProto.data.GeoFeatureType.trees, x2), m]); + 0 < a.waterEdgeE.length && b.features.push(lg.multiPolygon(DataProto.data.GeoFeatureType.water, [Ua.toPoly(a.waterEdgeE)])); + lg.enrichRoot(b, a); + return b }, lg.multiThick = function (a, b, c, d, f) { c == null && (c = !1); @@ -8087,7 +8296,6 @@ var $lime_init = function (A, t) { } return lg.geometryCollection(a, h) }; - var Rd = function () { }; g["SvgExporter"] = Rd; From e0f032010899511601b2b1206e7be20930449004 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 18:07:13 +0100 Subject: [PATCH 10/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D0=BF=D0=BE=D0=BB=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=B5=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=81=D0=B5=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/Village.js | 668 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 551 insertions(+), 117 deletions(-) diff --git a/src/js/Village.js b/src/js/Village.js index 0b36733..f1bd731 100644 --- a/src/js/Village.js +++ b/src/js/Village.js @@ -9451,7 +9451,8 @@ var $lime_init = function (E, u) { f.items.push(Ua.multiPolygon(DataProto.data.GeoFeatureType[DataProto.data.GeoFeatureType.fields], b)) } return f - }, Hh.getProto = function (a) { + }; + Hh.getProto = function (a) { Ua.CX = 0, Ua.CY = 0, Ua.SCALE = .7; var b = [], c = { @@ -9460,197 +9461,521 @@ var $lime_init = function (E, u) { roadWidth: a.bp.maxRoad * Ua.SCALE, generator: DataProto.data.GeoGeneratorType.vg, version: params.meta.ver_app, - wallThickness: Ua.SCALE + wallThickness: Ua.SCALE, + embedUid: "meta", + embedName: "meta", + embedProps: Hh._structFromJs({ + name: a.name, + pop: a.pop, + seed: a.bp.seed, + numbered: a.bp.numbered, + realW: a.realW, + realH: a.realH + }) + }, + d = Fc.rect(a.realW, a.realH), + f = { + scale: Ua.SCALE, + cx: Ua.CX, + cy: Ua.CY, + invertY: !0, + precisionPow10: 3 }, - d = Fc.rect(a.realW, a.realH); + h = [], + k = [], + p = 0, + l = null; + b.push(c); + + var m = [Ua.arrPoly(d)], + n = Hh._bboxFromNested(m); + b.push({ type: DataProto.data.GeoType.Polygon, id: DataProto.data.GeoFeatureType.earth, - coordinates: Hh._listValueFromNested([Ua.arrPoly(d)]) + coordinates: Hh._listValueFromNested(m), + embedUid: "earth", + embedName: "earth", + embedBbox: Hh._bboxToProto(n), + embedProps: Hh._structFromJs({kind: "earth"}) }); - var f = a.network.roads, h = f, k = [], p, l; - for (f = f.keys(); f.hasNext();) { - var m = f.next(), n = h.get(m), q = m; - n.type != wb.SQUARE && (m = n.type == wb.HIGHWAY ? 0 < x.widthLargeRoad ? x.widthLargeRoad : x.strokeNormal : 0 < x.widthSmallRoad ? x.widthSmallRoad : x.strokeNormal, k.push({ - type: DataProto.data.GeoType.LineString, - width: m * Ua.SCALE, - coordinates: Hh._listValueFromNested(Ua.arrPoly(q)) - })); + + l = Hh._bboxMerge(l, n); + + var q = a.network.roads, z = q, A = [], B = null, C = 0, D; + + for (q = q.keys(); q.hasNext();) { + var E = q.next(), F = z.get(E), G = E; + if (F.type != wb.SQUARE) { + D = F.type == wb.HIGHWAY ? 0 < x.widthLargeRoad ? x.widthLargeRoad : x.strokeNormal : 0 < x.widthSmallRoad ? x.widthSmallRoad : x.strokeNormal; + var H = Ua.arrPoly(G), I = Hh._bboxFromNested(H), J = "roads:" + C++; + A.push({ + type: DataProto.data.GeoType.LineString, + width: D * Ua.SCALE, + coordinates: Hh._listValueFromNested(H), + embedUid: J, + embedName: J, + embedBbox: Hh._bboxToProto(I), + embedProps: Hh._structFromJs({kind: "road", roadType: F.type, widthWorld: D}) + }); + B = Hh._bboxMerge(B, I); + l = Hh._bboxMerge(l, I); + h.push({ + targetUid: J, + centerline: Hh._editorPolylineFromWorld(G, !1), + width: D, + closed: !1, + props: Hh._structFromJs({roadType: F.type}) + }); + } } - var g2 = { + + var K = { type: DataProto.data.GeoType.GeometryCollection, id: DataProto.data.GeoFeatureType.roads, - geometries: k + geometries: A, + embedUid: "roads", + embedName: "roads", + embedBbox: Hh._bboxToProto(B), + embedProps: Hh._structFromJs({kind: "roads"}) }; - k = [], p = 0, l = a.piers; - for (; p < l.length;) { - var r = l[p]; - ++p; - k.push({ + + A = [], B = null, C = 0; + q = 0; + var L = a.piers; + + for (; q < L.length;) { + var M = L[q]; + ++q; + var N = Ua.arrPoly(M), O = Hh._bboxFromNested(N), P = "planks:" + C++; + A.push({ type: DataProto.data.GeoType.LineString, width: 5 * Ua.SCALE, - coordinates: Hh._listValueFromNested(Ua.arrPoly(r)) + coordinates: Hh._listValueFromNested(N), + embedUid: P, + embedName: P, + embedBbox: Hh._bboxToProto(O), + embedProps: Hh._structFromJs({kind: "plank", widthWorld: 5}) + }); + B = Hh._bboxMerge(B, O); + l = Hh._bboxMerge(l, O); + k.push({ + targetUid: P, + polyline: Hh._editorPolylineFromWorld(M, !1), + props: Hh._structFromJs({kind: "plank", widthWorld: 5}) }); } - var m2 = { + + var Q = { type: DataProto.data.GeoType.GeometryCollection, id: DataProto.data.GeoFeatureType.planks, - geometries: k + geometries: A, + embedUid: "planks", + embedName: "planks", + embedBbox: Hh._bboxToProto(B), + embedProps: Hh._structFromJs({kind: "planks"}) }; - k = [], p = 0, l = a.forest.trees; - for (; p < l.length;) { - var s = l[p]; - ++p; - k.push(s.data.center); + + A = [], q = 0, L = a.forest.trees; + for (; q < L.length;) { + M = L[q]; + ++q; + A.push(M.data.center); } + if (na.showOrchards) - for (p = 0, l = a.farmland.orchards; p < l.length;) { - var t = l[p]; - ++p; - var u = $b.getOrchardTrees(a, t); - for (var v = 0; v < u.length;) { - var w = u[v]; - ++v; - k.push(w.pos); - } - } - var n = [], q = [], z = [], A = [], B; - p = 0, l = a.buildings; - for (; p < l.length;) { - B = l[p]; - ++p; - q.push(B.rect); - } - p = 0, l = a.props; - for (; p < l.length;) { - var C = l[p]; - ++p; - C instanceof Sf ? k.push(Ka.__cast(C, Sf).pos) : C instanceof Tf && (B = Ka.__cast(C, Tf), C = Fc.regular(16, B.r), Eb.asTranslate(C, B.pos.x, B.pos.y), n.push(C)); - } - for (p = 0; p < q.length;) { - B = q[p]; - ++p; - z.push([Ua.arrPoly(B)]); - } - for (p = 0; p < n.length;) { - B = n[p]; - ++p; - A.push([Ua.arrPoly(B)]); + for (q = 0, L = a.farmland.orchards; q < L.length;) { + var R = L[q]; + ++q; + var S = $b.getOrchardTrees(a, R); + for (var T = 0; T < S.length;) { + var U = S[T]; + ++T; + A.push(U.pos); + } + } + + var V = [], W = [], X = [], Y = [], ca; + q = 0, L = a.buildings; + for (; q < L.length;) { + ca = L[q]; + ++q; + V.push(ca); + } + + var da = []; + q = 0, L = a.props; + for (; q < L.length;) { + var ea = L[q]; + ++q; + ea instanceof Sf ? A.push(Ka.__cast(ea, Sf).pos) : ea instanceof Tf && (ca = Ka.__cast(ea, Tf), ea = Fc.regular(16, ca.r), Eb.asTranslate(ea, ca.pos.x, ca.pos.y), W.push(ea), da.push({pos: ca.pos, r: ca.r})); } + + var fa = [], ga = null; + for (q = 0; q < V.length;) { + ca = V[q]; + var ha = q++, + ia = Ua.arrPoly(ca.rect), + ja = [ia], + ka = Hh._bboxFromNested(ja), + la = "buildings:" + ha; + X.push(ja); + fa.push({ + index: ha, + uid: la, + name: la, + bbox: Hh._bboxToProto(ka), + props: Hh._structFromJs({kind: "building", width: ca.width, depth: ca.depth, height: ca.height, large: ca.large}) + }); + ga = Hh._bboxMerge(ga, ka); + l = Hh._bboxMerge(l, ka); + k.push({ + targetUid: la, + polyline: Hh._editorPolylineFromWorld(ca.rect, !0), + props: Hh._structFromJs({kind: "building", width: ca.width, depth: ca.depth, height: ca.height, large: ca.large}) + }); + } + + var ma = []; + B = null; + for (q = 0; q < W.length;) { + ea = W[q]; + ha = q++; + ia = Ua.arrPoly(ea); + ja = [ia]; + ka = Hh._bboxFromNested(ja); + la = "prisms:" + ha; + Y.push(ja); + ma.push({ + index: ha, + uid: la, + name: la, + bbox: Hh._bboxToProto(ka), + props: Hh._structFromJs({kind: "prism", radius: da[ha] != null ? da[ha].r : null}) + }); + B = Hh._bboxMerge(B, ka); + l = Hh._bboxMerge(l, ka); + k.push({ + targetUid: la, + polyline: Hh._editorPolylineFromWorld(ea, !0), + props: Hh._structFromJs({kind: "prism", radius: da[ha] != null ? da[ha].r : null}) + }); + } + + var na2 = Ua.arrPoly(A), oa = Hh._bboxFromNested(na2), pa = [], qa = 0; + for (; qa < na2.length;) { + var ra = na2[qa], sa = qa++; + pa.push({ + index: sa, + uid: "trees:" + sa, + name: "trees:" + sa, + bbox: Hh._bboxToProto(Hh._bboxFromNested(ra)), + props: Hh._structFromJs({kind: "tree"}) + }); + } + + l = Hh._bboxMerge(l, oa); + b.push({ type: DataProto.data.GeoType.MultiPolygon, id: DataProto.data.GeoFeatureType.buildings, - coordinates: Hh._listValueFromNested(z) + coordinates: Hh._listValueFromNested(X), + embedUid: "buildings", + embedName: "buildings", + embedBbox: Hh._bboxToProto(ga), + embedParts: fa, + embedProps: Hh._structFromJs({kind: "buildings"}) }); + b.push({ type: DataProto.data.GeoType.MultiPolygon, id: DataProto.data.GeoFeatureType.prisms, - coordinates: Hh._listValueFromNested(A) + coordinates: Hh._listValueFromNested(Y), + embedUid: "prisms", + embedName: "prisms", + embedBbox: Hh._bboxToProto(B), + embedParts: ma, + embedProps: Hh._structFromJs({kind: "prisms"}) }); + b.push({ type: DataProto.data.GeoType.MultiPoint, id: DataProto.data.GeoFeatureType.trees, - coordinates: Hh._listValueFromNested(Ua.arrPoly(k)) + coordinates: Hh._listValueFromNested(na2), + embedUid: "trees", + embedName: "trees", + embedBbox: Hh._bboxToProto(oa), + embedParts: pa, + embedProps: Hh._structFromJs({kind: "trees"}) }); - b.push(g2); - b.push(m2); - var D = {type: DataProto.data.GeoType.FeatureCollection, features: b}; + + b.push(K); + b.push(Q); + + var ta = { + type: DataProto.data.GeoType.FeatureCollection, + features: b, + embedUid: "root", + embedName: a.name, + embedExportTransform: f, + embedBbox: Hh._bboxToProto(l), + embedEditorPayload: { + payloadRev: 1, + coordSpace: 1, + roadModels: h, + shapeModels: k, + props: Hh._structFromJs({generator: "vg", version: params.meta.ver_app}) + }, + embedProps: Hh._structFromJs({generator: "vg", version: params.meta.ver_app, name: a.name}) + }; + if (a.water != null) { - var E = [], F = 0, G = a.water.patches; - for (; F < G.length;) { - var H = G[F]; - ++F; - E.push([Ua.arrPoly(H)]); + var ua = [], va = [], wa = null, ya = 0, za2 = a.water.patches; + for (; ya < za2.length;) { + var Aa = za2[ya]; + ++ya; + var Ba = Ua.arrPoly(Aa), Ca = [Ba], Da = Hh._bboxFromNested(Ca), Ea = "water:" + (ya - 1); + ua.push(Ca); + va.push({ + index: ya - 1, + uid: Ea, + name: Ea, + bbox: Hh._bboxToProto(Da), + props: Hh._structFromJs({kind: "water"}) + }); + wa = Hh._bboxMerge(wa, Da); + l = Hh._bboxMerge(l, Da); + k.push({ + targetUid: Ea, + polyline: Hh._editorPolylineFromWorld(Aa, !0), + props: Hh._structFromJs({kind: "water"}) + }); } - D.features.push({ + + ta.features.push({ type: DataProto.data.GeoType.MultiPolygon, id: DataProto.data.GeoFeatureType.water, - coordinates: Hh._listValueFromNested(E) + coordinates: Hh._listValueFromNested(ua), + embedUid: "water", + embedName: "water", + embedBbox: Hh._bboxToProto(wa), + embedParts: va, + embedProps: Hh._structFromJs({kind: "water"}) }); - D.features.push({ + + var Fa = Ua.arrPoly(a.water.edgePoints), Ga = Hh._bboxFromNested(Fa), Ha = [], Ia = 0; + for (; Ia < Fa.length;) { + var Ja = Fa[Ia], Ka2 = Ia++; + Ha.push({ + index: Ka2, + uid: "extendable:" + Ka2, + name: "extendable:" + Ka2, + bbox: Hh._bboxToProto(Hh._bboxFromNested(Ja)), + props: Hh._structFromJs({kind: "extendable"}) + }); + } + + ta.features.push({ type: DataProto.data.GeoType.MultiPoint, id: DataProto.data.GeoFeatureType.extendable, - coordinates: Hh._listValueFromNested(Ua.arrPoly(a.water.edgePoints)) + coordinates: Hh._listValueFromNested(Fa), + embedUid: "extendable", + embedName: "extendable", + embedBbox: Hh._bboxToProto(Ga), + embedParts: Ha, + embedProps: Hh._structFromJs({kind: "extendable"}) }); + + l = Hh._bboxMerge(l, Ga); } + if (a.network.square != null) { - var I = a.network.square.slice(1), J; + var La2 = a.network.square.slice(1), Ma2; if (a.bp.waterType == "pond") - for (F = 0, G = a.water.patches; F < G.length && (J = G[F], ++F, J = ud.and(I, X.revert(J), !0), J = J != null ? J : I, J != null);) I = J; + for (p = 0, L = a.water.patches; p < L.length && (Ma2 = L[p], ++p, Ma2 = ud.and(La2, X.revert(Ma2), !0), Ma2 = Ma2 != null ? Ma2 : La2, Ma2 != null);) La2 = Ma2; else if (a.bp.waterType != null) - for (F = 0, G = a.water.getLand(); F < G.length;) - if (J = G[F], ++F, J = ud.and(I, J), J != null) { - I = J; + for (p = 0, L = a.water.getLand(); p < L.length;) + if (Ma2 = L[p], ++p, Ma2 = ud.and(La2, Ma2), Ma2 != null) { + La2 = Ma2; break } - D.features.push({ + + var Na2 = [Ua.arrPoly(La2)], Oa2 = Hh._bboxFromNested(Na2); + ta.features.push({ type: DataProto.data.GeoType.MultiPolygon, id: DataProto.data.GeoFeatureType.squares, - coordinates: Hh._listValueFromNested([[Ua.arrPoly(I)]]) + coordinates: Hh._listValueFromNested([Na2]), + embedUid: "squares", + embedName: "squares", + embedBbox: Hh._bboxToProto(Oa2), + embedParts: [{ + index: 0, + uid: "squares:0", + name: "squares:0", + bbox: Hh._bboxToProto(Oa2), + props: Hh._structFromJs({kind: "square"}) + }], + embedProps: Hh._structFromJs({kind: "squares"}) }); + + l = Hh._bboxMerge(l, Oa2); } + if (a.palisade != null) { - var K = [], L = 0, M = a.palisade.segments; - for (; L < M.length;) { - var N = M[L]; - ++L; - K.push(Ua.arrPoly(N)); + var Pa2 = [], Qa2 = [], Ra2 = null, Sa2 = 0, Ta2 = a.palisade.segments; + for (; Sa2 < Ta2.length;) { + var Ua2 = Ta2[Sa2]; + ++Sa2; + var Va2 = Ua.arrPoly(Ua2), Wa2 = Hh._bboxFromNested(Va2), Xa2 = "palisade:" + (Sa2 - 1); + Pa2.push(Va2); + Qa2.push({ + index: Sa2 - 1, + uid: Xa2, + name: Xa2, + bbox: Hh._bboxToProto(Wa2), + props: Hh._structFromJs({kind: "palisade"}) + }); + Ra2 = Hh._bboxMerge(Ra2, Wa2); + l = Hh._bboxMerge(l, Wa2); + k.push({ + targetUid: Xa2, + polyline: Hh._editorPolylineFromWorld(Ua2, !1), + props: Hh._structFromJs({kind: "palisade"}) + }); } - D.features.push({ + + ta.features.push({ type: DataProto.data.GeoType.MultiLineString, id: DataProto.data.GeoFeatureType.palisade, - coordinates: Hh._listValueFromNested(K) + coordinates: Hh._listValueFromNested(Pa2), + embedUid: "palisade", + embedName: "palisade", + embedBbox: Hh._bboxToProto(Ra2), + embedParts: Qa2, + embedProps: Hh._structFromJs({kind: "palisade"}) }); } + if (na.showFields) { - var O = [], P = 0, Q = a.farmland.getFields(); - for (; P < Q.length;) { - var R = Q[P]; - ++P; - O.push(db.resampleClosed(R, a.bp.minRoad)); - } - var S = []; - for (P = 0; P < O.length;) { - R = O[P]; - ++P; - S.push([Ua.arrPoly(R)]); - } - D.features.push({ + var Ya2 = [], Za2 = 0, aa2 = a.farmland.getFields(); + for (; Za2 < aa2.length;) { + var ba2 = aa2[Za2]; + ++Za2; + Ya2.push(db.resampleClosed(ba2, a.bp.minRoad)); + } + + var ca2 = 0, da2 = [], ea2, fa2, ga2 = null; + for (; ca2 < Ya2.length;) { + ea2 = Ya2[ca2]; + fa2 = ca2++; + var ha2 = [Ua.arrPoly(ea2)], ia2 = Hh._bboxFromNested(ha2), ja2 = "fields:" + fa2; + da2.push(ha2); + ga2 = Hh._bboxMerge(ga2, ia2); + l = Hh._bboxMerge(l, ia2); + k.push({ + targetUid: ja2, + polyline: Hh._editorPolylineFromWorld(ea2, !0), + props: Hh._structFromJs({kind: "field"}) + }); + } + + var ka2 = []; + for (ca2 = 0; ca2 < da2.length;) { + var la2 = da2[ca2], ma2 = ca2++; + var na3 = Hh._bboxFromNested(la2); + ka2.push({ + index: ma2, + uid: "fields:" + ma2, + name: "fields:" + ma2, + bbox: Hh._bboxToProto(na3), + props: Hh._structFromJs({kind: "field"}) + }); + } + + ta.features.push({ type: DataProto.data.GeoType.MultiPolygon, id: DataProto.data.GeoFeatureType.fields, - coordinates: Hh._listValueFromNested(S) + coordinates: Hh._listValueFromNested(da2), + embedUid: "fields", + embedName: "fields", + embedBbox: Hh._bboxToProto(ga2), + embedParts: ka2, + embedProps: Hh._structFromJs({kind: "fields"}) }); } - return DataProto.data.GeoObj.fromObject(D) - }, Hh.stringifyProto = function (a) { + + ta.embedBbox = Hh._bboxToProto(l); + ta.embedEditorPayload.roadModels = h; + ta.embedEditorPayload.shapeModels = k; + return DataProto.data.GeoObj.fromObject(ta) + }; + Hh.stringifyProto = function (a) { return JSON.stringify(Hh.protoToGeoJson(a), null, " ") - }, Hh.protoToGeoJson = function (a) { + }; + Hh.protoToGeoJson = function (a) { var b = {type: DataProto.data.GeoType[a.type]}; - a.id != null && (b.id = DataProto.data.GeoFeatureType[a.id]), a.width != null && (b.width = a.width), a.name != null && (b.name = a.name), a.roadWidth != null && (b.roadWidth = a.roadWidth), a.riverWidth != null && (b.riverWidth = a.riverWidth), a.towerRadius != null && (b.towerRadius = a.towerRadius), a.generator != null && (b.generator = DataProto.data.GeoGeneratorType[a.generator]), a.version != null && (b.version = a.version), a.wallThickness != null && (b.wallThickness = a.wallThickness); + a.id != null && (b.id = DataProto.data.GeoFeatureType[a.id]); + a.width != null && (b.width = a.width); + a.name != null && (b.name = a.name); + a.roadWidth != null && (b.roadWidth = a.roadWidth); + a.riverWidth != null && (b.riverWidth = a.riverWidth); + a.towerRadius != null && (b.towerRadius = a.towerRadius); + a.wallThickness != null && (b.wallThickness = a.wallThickness); + a.generator != null && (b.generator = DataProto.data.GeoGeneratorType[a.generator]); + a.version != null && (b.version = a.version); + + a.embedUid != null && (b.embedUid = a.embedUid); + a.embedName != null && (b.embedName = a.embedName); + + a.embedExportTransform != null && (b.embedExportTransform = { + scale: a.embedExportTransform.scale, + cx: a.embedExportTransform.cx, + cy: a.embedExportTransform.cy, + invertY: a.embedExportTransform.invertY, + precisionPow10: a.embedExportTransform.precisionPow10 + }); + + a.embedBbox != null && (b.embedBbox = { + minX: a.embedBbox.minX, + minY: a.embedBbox.minY, + maxX: a.embedBbox.maxX, + maxY: a.embedBbox.maxY + }); + + if (a.embedParts != null && a.embedParts.length) { + b.embedParts = []; + for (var c = 0; c < a.embedParts.length;) { + var d = a.embedParts[c++]; + var f = {index: d.index, uid: d.uid}; + d.name != null && (f.name = d.name); + d.bbox != null && (f.bbox = {minX: d.bbox.minX, minY: d.bbox.minY, maxX: d.bbox.maxX, maxY: d.bbox.maxY}); + d.props != null && (f.props = Hh._structToJson(d.props)); + b.embedParts.push(f); + } + } + + a.embedProps != null && (b.embedProps = Hh._structToJson(a.embedProps)); + a.embedEditorPayload != null && (b.embedEditorPayload = Hh._editorPayloadToJson(a.embedEditorPayload)); + switch (a.type) { case DataProto.data.GeoType.FeatureCollection: b.features = []; - for (var c = 0; c < a.features.length;) { - var d = a.features[c]; - ++c, b.features.push(Hh.protoToGeoJson(d)) - } + for (c = 0; c < a.features.length;) b.features.push(Hh.protoToGeoJson(a.features[c++])); break; case DataProto.data.GeoType.GeometryCollection: b.geometries = []; - for (c = 0; c < a.geometries.length;) { - d = a.geometries[c]; - ++c, b.geometries.push(Hh.protoToGeoJson(d)) - } + for (c = 0; c < a.geometries.length;) b.geometries.push(Hh.protoToGeoJson(a.geometries[c++])); break; case DataProto.data.GeoType.Feature: a.geometry != null && (b.geometry = Hh.protoToGeoJson(a.geometry)); break; default: - a.coordinates != null && (b.coordinates = Hh._listValueToJson(a.coordinates)) + a.coordinates != null && (b.coordinates = Hh._listValueToJson(a.coordinates)); } return b - }, Hh._listValueFromNested = function (a) { + }; + Hh._listValueFromNested = function (a) { for (var b = [], c = 0; c < a.length;) { var d = a[c]; ++c, Array.isArray(d) ? b.push({listValue: Hh._listValueFromNested(d)}) : b.push({numberValue: d}) @@ -9663,7 +9988,116 @@ var $lime_init = function (E, u) { } return b }, Hh._valueToJson = function (a) { - return a.listValue != null ? Hh._listValueToJson(a.listValue) : a.numberValue != null ? a.numberValue : a.stringValue != null ? a.stringValue : a.boolValue != null ? a.boolValue : null + return a.listValue != null ? Hh._listValueToJson(a.listValue) : a.structValue != null ? Hh._structToJson(a.structValue) : a.numberValue != null ? a.numberValue : a.stringValue != null ? a.stringValue : a.boolValue != null ? a.boolValue : a.nullValue != null ? null : null + }; + Hh._protoValueFromJs = function (a) { + if (a === null || a === undefined) return {nullValue: 0}; + if (Array.isArray(a)) return {listValue: {values: a.map(Hh._protoValueFromJs)}}; + if (typeof a === "number") return {numberValue: a}; + if (typeof a === "string") return {stringValue: a}; + if (typeof a === "boolean") return {boolValue: a}; + if (typeof a === "object") { + var b = {}, c; + for (c in a) Object.prototype.hasOwnProperty.call(a, c) && (b[c] = Hh._protoValueFromJs(a[c])); + return {structValue: {fields: b}}; + } + return {stringValue: String(a)} + }; + + Hh._structFromJs = function (a) { + var b = {}, c; + if (a != null && typeof a === "object") + for (c in a) Object.prototype.hasOwnProperty.call(a, c) && (b[c] = Hh._protoValueFromJs(a[c])); + return {fields: b} + }; + + Hh._structToJson = function (a) { + var b = {}, c = a.fields == null ? {} : a.fields, d; + for (d in c) Object.prototype.hasOwnProperty.call(c, d) && (b[d] = Hh._valueToJson(c[d])); + return b + }; + + Hh._bboxAcc = function (a, b) { + if (b == null) return; + if (Array.isArray(b)) { + if (b.length === 2 && typeof b[0] === "number" && typeof b[1] === "number") { + var c = b[0], d = b[1]; + a.minX = Math.min(a.minX, c); + a.minY = Math.min(a.minY, d); + a.maxX = Math.max(a.maxX, c); + a.maxY = Math.max(a.maxY, d); + } else { + for (var f = 0; f < b.length;) Hh._bboxAcc(a, b[f++]); + } + } + }; + + Hh._bboxFromNested = function (a) { + var b = {minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity}; + Hh._bboxAcc(b, a); + return isFinite(b.minX) ? b : null + }; + + Hh._bboxMerge = function (a, b) { + if (a == null) return b; + if (b == null) return a; + return { + minX: Math.min(a.minX, b.minX), + minY: Math.min(a.minY, b.minY), + maxX: Math.max(a.maxX, b.maxX), + maxY: Math.max(a.maxY, b.maxY) + } + }; + + Hh._bboxToProto = function (a) { + return a == null ? null : {minX: a.minX, minY: a.minY, maxX: a.maxX, maxY: a.maxY} + }; + + Hh._editorPointsFromWorld = function (a) { + for (var b = [], c = 0; c < a.length;) { + var d = a[c++]; + b.push({x: d.x, y: d.y}); + } + return b + }; + + Hh._editorPolylineFromWorld = function (a, b) { + null == b && (b = !1); + return {points: Hh._editorPointsFromWorld(a), closed: b} + }; + + Hh._editorPayloadToJson = function (a) { + var b = {}; + a.payloadRev != null && (b.payloadRev = a.payloadRev); + a.coordSpace != null && (b.coordSpace = a.coordSpace); + + if (a.roadModels != null && a.roadModels.length) { + b.roadModels = []; + for (var c = 0; c < a.roadModels.length;) { + var d = a.roadModels[c++], f = {targetUid: d.targetUid}; + d.centerline != null && (f.centerline = {points: d.centerline.points, closed: d.centerline.closed}); + d.width != null && (f.width = d.width); + d.closed != null && (f.closed = d.closed); + d.props != null && (f.props = Hh._structToJson(d.props)); + b.roadModels.push(f); + } + } + + if (a.shapeModels != null && a.shapeModels.length) { + b.shapeModels = []; + for (c = 0; c < a.shapeModels.length;) { + d = a.shapeModels[c++]; + f = {targetUid: d.targetUid}; + d.polyline != null && (f.polyline = {points: d.polyline.points, closed: d.polyline.closed}); + d.bezier != null && (f.bezier = d.bezier); + d.arc != null && (f.arc = d.arc); + d.props != null && (f.props = Hh._structToJson(d.props)); + b.shapeModels.push(f); + } + } + + a.props != null && (b.props = Hh._structToJson(a.props)); + return b }; var zc = function () { From 0a0fe0a35216580ab92dfe13e293f22227ba237e Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 18:29:51 +0100 Subject: [PATCH 11/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D1=83=D0=B1=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=B1=D1=8B=D1=82=D0=BE=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protobuf/data/geo/obj.proto | 197 +++++++++++++----------------------- src/js/Dwellings.js | 2 +- src/js/Village.js | 16 --- src/js/mfcg.js | 4 - 4 files changed, 69 insertions(+), 150 deletions(-) diff --git a/protobuf/data/geo/obj.proto b/protobuf/data/geo/obj.proto index 27cba8f..d26d37c 100644 --- a/protobuf/data/geo/obj.proto +++ b/protobuf/data/geo/obj.proto @@ -7,19 +7,14 @@ import "data/geo/enum.proto"; // // // // -// Метадані перетворення координат для round-trip. -// x_export = cx + x_world * scale -// y_export = cy - y_world * scale (якщо invert_y = true) -// precision_pow10 = 3 => округлення до 1e-3 message GeoTransformObj { - double scale = 1; // SCALE - double cx = 2; // CX - double cy = 3; // CY - bool invert_y = 4; // інверсія осі Y - uint32 precision_pow10 = 5; // 3 => 0.001 + double scale = 1; + double cx = 2; + double cy = 3; + bool invert_y = 4; + uint32 precision_pow10 = 5; } -// Bounding box (у тій системі координат, в якій лежить geometry/coordinates) message GeoBBoxObj { double min_x = 1; double min_y = 2; @@ -27,136 +22,101 @@ message GeoBBoxObj { double max_y = 4; } -// “Частина” всередині Multi* геометрій. -// index відповідає порядку координат у MultiPolygon/MultiPoint/MultiLineString. message GeoPartObj { - uint32 index = 1; // індекс частини в Multi* - string uid = 2; // стабільний ID частини - google.protobuf.Struct props = 3; // атрибути частини (тип, клас, параметри редагування) - string name = 4; // опціональна назва (UI) - GeoBBoxObj bbox = 5; // опціонально: bbox частини для швидкого hit-test + uint32 index = 1; + string uid = 2; + google.protobuf.Struct props = 3; + string name = 4; + GeoBBoxObj bbox = 5; } - -// Уточнення: в якій системі координат лежать точки в EditorPayloadObj. -// Рекомендація: WORLD (до застосування export_transform), щоб редагувати “як у редакторі”. enum EditorCoordSpaceType { EDITOR_COORD_SPACE_UNSPECIFIED = 0; - - // Координати як у редакторі (world): +Y вгору, без SCALE/CX/CY (або ваша “внутрішня”). EDITOR_COORD_SPACE_WORLD = 1; - - // Координати як у файлі (export): ті самі, що в GeoObj.coordinates. EDITOR_COORD_SPACE_EXPORT = 2; } -// Проста 2D-точка для редакторських примітивів message EditorPoint2DObj { double x = 1; double y = 2; } - -// Полілінія (центрлайн, контур для редагування, тощо) message EditorPolylineObj { - repeated EditorPoint2DObj points = 1; // контрольні/вузлові точки - bool closed = 2; // замкнено (для контурів) + repeated EditorPoint2DObj points = 1; + bool closed = 2; } - -// Кубічний Bezier шлях (для випадків, коли геометрія в файлі вже “дискретизована”, -// а ти хочеш зберегти оригінальні контрольні точки) message EditorBezierObj { - // Для cubic bezier зазвичай: (P0, C1, C2, P1) * N сегментів. - // Тобто кількість точок кратна 4 або 3+1 залежно від вашої конвенції. repeated EditorPoint2DObj control_points = 1; - bool closed = 2; // замкнено - uint32 segments = 3; // підказка: скільки сегментів у control_points + bool closed = 2; + uint32 segments = 3; } -// Дуга (якщо в редакторі є арки, а в експорті лише ламана) message EditorArcObj { - EditorPoint2DObj center = 1; // центр - double radius = 2; // радіус - double start_angle_rad = 3; // початок (радіани) - double end_angle_rad = 4; // кінець (радіани) - bool ccw = 5; // напрям + EditorPoint2DObj center = 1; + double radius = 2; + double start_angle_rad = 3; + double end_angle_rad = 4; + bool ccw = 5; } -// Тип зв’язку між об’єктами (не відновлюється з геометрії) enum EditorLinkType { EDITOR_LINK_TYPE_UNSPECIFIED = 0; - - // Структурні - EDITOR_LINK_TYPE_PARENT_CHILD = 1; // b є “дочірній” для a - EDITOR_LINK_TYPE_GROUP_MEMBER = 2; // b входить у групу a (або навпаки — визначіть правило) - - // Геометричні/логічні - EDITOR_LINK_TYPE_ATTACH = 3; // прив’язка (building->plot, tree->district, тощо) - EDITOR_LINK_TYPE_OVER_UNDER = 4; // міст над річкою/дорогою, тунель, рівні - EDITOR_LINK_TYPE_ALONG = 5; // “уздовж” (наприклад, паркани вздовж дороги) + EDITOR_LINK_TYPE_PARENT_CHILD = 1; + EDITOR_LINK_TYPE_GROUP_MEMBER = 2; + EDITOR_LINK_TYPE_ATTACH = 3; + EDITOR_LINK_TYPE_OVER_UNDER = 4; + EDITOR_LINK_TYPE_ALONG = 5; } -// Опис зв’язку message EditorLinkObj { - string a_uid = 1; // UID першого об’єкта - string b_uid = 2; // UID другого об’єкта - EditorLinkType type = 3; // тип зв’язку - google.protobuf.Struct props = 4; // опціональні параметри зв’язку (рівень, offset, тощо) + string a_uid = 1; + string b_uid = 2; + EditorLinkType type = 3; + google.protobuf.Struct props = 4; } -// Стан шарів/видимість/блокування — не відновлюється з геометрії, -// але корисно для “проектного” round-trip (якщо тобі це треба). message EditorLayerStateObj { - string layer_id = 1; // напр. "roads", "buildings" або enum-ім'я - bool visible = 2; // видимий - bool locked = 3; // заблокований для редагування - int32 z_index = 4; // порядок малювання (якщо є) + string layer_id = 1; + bool visible = 2; + bool locked = 3; + int32 z_index = 4; } -// Групи (виділення “як один об’єкт”, пакетні операції) — теж не відновлюються з геометрії. message EditorGroupObj { - string group_uid = 1; // UID групи - string name = 2; // назва групи - repeated string member_uids = 3; // члени групи - google.protobuf.Struct props = 4; // опціональні атрибути + string group_uid = 1; + string name = 2; + repeated string member_uids = 3; + google.protobuf.Struct props = 4; } -// Дороги часто рендеряться як полігони, але редагуються як центрлінія + ширина. -// З полігону центрлінію відновити однозначно не можна -> зберігаємо її явно. message EditorRoadModelObj { - string target_uid = 1; // UID дороги (або UID частини, якщо Multi*) - EditorPolylineObj centerline = 2; // центрлайн для редагування - double width = 3; // ширина (якщо не хочеш шукати в props) - bool closed = 4; // для кільцевих доріг (опціонально) - google.protobuf.Struct props = 5; // клас дороги, обмеження, тощо + string target_uid = 1; + EditorPolylineObj centerline = 2; + double width = 3; + bool closed = 4; + google.protobuf.Struct props = 5; } -// Узагальнена “редакторська форма” для об’єкта, коли експортна геометрія — вже результат, -// а редагувати хочеться “по контрольних точках/примітивах”. message EditorShapeModelObj { - string target_uid = 1; // UID об’єкта/частини, до якого відноситься модель + string target_uid = 1; oneof model { - EditorPolylineObj polyline = 2; // редагувати як полілінію (напр. річка/паркан/дорога-ось) - EditorBezierObj bezier = 3; // редагувати як bezier - EditorArcObj arc = 4; // редагувати як арку + EditorPolylineObj polyline = 2; + EditorBezierObj bezier = 3; + EditorArcObj arc = 4; } - google.protobuf.Struct props = 10; // параметри моделі (tessellation, snapping, тощо) + google.protobuf.Struct props = 10; } -// Снап-ноди (вузли) для стабільного графа/стикування. -// Перетини/вузли з полігонів/ламаниx відновлюються не завжди стабільно (особливо після ручних правок), -// тому якщо у редактора є “граф” — збережи його явно. + message EditorSnapNodeObj { - string node_uid = 1; // UID вузла - EditorPoint2DObj pos = 2; // позиція - repeated string incident_uids = 3; // які об’єкти/сегменти під’єднані (UID) - google.protobuf.Struct props = 4; // тип вузла, пріоритет, тощо + string node_uid = 1; + EditorPoint2DObj pos = 2; + repeated string incident_uids = 3; + google.protobuf.Struct props = 4; } -// Обмеження/констрейнти (якщо у редакторі є): паралельність, фіксована довжина, тощо. -// Це 100% не відновлюється з геометрії. enum EditorConstraintType { EDITOR_CONSTRAINT_TYPE_UNSPECIFIED = 0; EDITOR_CONSTRAINT_TYPE_SNAP = 1; @@ -166,73 +126,52 @@ enum EditorConstraintType { } message EditorConstraintObj { - string constraint_uid = 1; // UID обмеження - EditorConstraintType type = 2; // тип - repeated string target_uids = 3; // до чого прив’язано (UID об’єктів/частин/нод) - google.protobuf.Struct params = 4; // параметри (довжина, кут, допуск, тощо) + string constraint_uid = 1; + EditorConstraintType type = 2; + repeated string target_uids = 3; + google.protobuf.Struct params = 4; } -// Головний payload для round-trip редагування без Any. -// УСЕ ТУТ — опціональне: імпортер має вміти працювати, навіть якщо payload порожній, -// використовуючи embed_uid/embed_parts/embed_props + geometry. message EditorPayloadObj { - uint32 payload_rev = 1; // ревізія формату payload (для міграцій) - EditorCoordSpaceType coord_space = 2; // WORLD або EXPORT - - // Проектні/редакторські речі (не обов’язково) - repeated EditorLayerStateObj layers = 10; // стани шарів (visible/locked/z) - repeated EditorGroupObj groups = 11; // групи - repeated EditorLinkObj links = 12; // зв’язки між об’єктами - - // Редакторські моделі геометрії (те, що не відновиш з “готової” геометрії) - repeated EditorRoadModelObj road_models = 20; // центрлайни доріг + ширини - repeated EditorShapeModelObj shape_models = 21; // сплайни/арки/редакторські ламані - - // Граф/снапінг/констрейнти (за потреби) + uint32 payload_rev = 1; + EditorCoordSpaceType coord_space = 2; + repeated EditorLayerStateObj layers = 10; + repeated EditorGroupObj groups = 11; + repeated EditorLinkObj links = 12; + repeated EditorRoadModelObj road_models = 20; + repeated EditorShapeModelObj shape_models = 21; repeated EditorSnapNodeObj snap_nodes = 30; repeated EditorConstraintObj constraints = 31; - - // Глобальні параметри редактора/проекту (опційно): одиниці, дефолти стилю, тощо google.protobuf.Struct props = 40; } -// =========================================================== message GeoObj { GeoType type = 1; GeoObj geometry = 2; google.protobuf.ListValue coordinates = 3; - - reserved 4 to 7; - - string embed_uid = 8; // UID об’єкта (або шару/feature). Для Multi* зазвичай UID-и в embed_parts. - string embed_name = 9; // Додаткове ім'я (щоб не плутатись з існуючим `name`) + reserved 4 to 8; + string embed_uid = 9; repeated GeoObj features = 10; repeated GeoObj geometries = 11; - reserved 12 to 16; - - repeated GeoPartObj embed_parts = 17; // Метадані частин Multi* - GeoTransformObj embed_export_transform = 18; // Transform для round-trip - GeoBBoxObj embed_bbox = 19; // bbox (файл/шар/об’єкт) + repeated GeoPartObj embed_parts = 17; + GeoTransformObj embed_export_transform = 18; + GeoBBoxObj embed_bbox = 19; optional GeoGeneratorType generator = 20; optional GeoFeatureType id = 21; optional string version = 22; optional string name = 23; optional double width = 24; - reserved 25 to 38; - - google.protobuf.Struct embed_props = 39; // Атрибути об’єкта/шару/feature + google.protobuf.Struct embed_props = 39; optional double road_width = 40; optional double river_width = 41; optional double tower_radius = 42; optional double wall_thickness = 43; - reserved 44 to 79; - EditorPayloadObj embed_editor_payload = 80; } diff --git a/src/js/Dwellings.js b/src/js/Dwellings.js index 77bc2d1..2a4e488 100644 --- a/src/js/Dwellings.js +++ b/src/js/Dwellings.js @@ -6578,7 +6578,7 @@ var $lime_init = function (K, v) { a.basement!=null&&b.push(sb.plan2proto(a.basement,a.chimneys)); var c=new DataProto.data.DwellingsObj({floors:b,exit:sb.edge2proto(a.floors[0].entrance.door)}); a.floors[0].spiral!=null&&(c.spiral=sb.edge2proto(a.floors[0].spiral.entrance)); - a.name!=null&&a.name!=""&&(c.embedName=a.name); + a.name!=null&&a.name!=""; var e=ib.get("architecture"); if(e!=null){var f=DataProto.data.DwellingsArchitectureType[e];f!==void 0&&(c.embedArchitecture=f)} return c diff --git a/src/js/Village.js b/src/js/Village.js index f1bd731..e7e8f2d 100644 --- a/src/js/Village.js +++ b/src/js/Village.js @@ -9463,7 +9463,6 @@ var $lime_init = function (E, u) { version: params.meta.ver_app, wallThickness: Ua.SCALE, embedUid: "meta", - embedName: "meta", embedProps: Hh._structFromJs({ name: a.name, pop: a.pop, @@ -9496,7 +9495,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.earth, coordinates: Hh._listValueFromNested(m), embedUid: "earth", - embedName: "earth", embedBbox: Hh._bboxToProto(n), embedProps: Hh._structFromJs({kind: "earth"}) }); @@ -9515,7 +9513,6 @@ var $lime_init = function (E, u) { width: D * Ua.SCALE, coordinates: Hh._listValueFromNested(H), embedUid: J, - embedName: J, embedBbox: Hh._bboxToProto(I), embedProps: Hh._structFromJs({kind: "road", roadType: F.type, widthWorld: D}) }); @@ -9536,7 +9533,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.roads, geometries: A, embedUid: "roads", - embedName: "roads", embedBbox: Hh._bboxToProto(B), embedProps: Hh._structFromJs({kind: "roads"}) }; @@ -9554,7 +9550,6 @@ var $lime_init = function (E, u) { width: 5 * Ua.SCALE, coordinates: Hh._listValueFromNested(N), embedUid: P, - embedName: P, embedBbox: Hh._bboxToProto(O), embedProps: Hh._structFromJs({kind: "plank", widthWorld: 5}) }); @@ -9572,7 +9567,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.planks, geometries: A, embedUid: "planks", - embedName: "planks", embedBbox: Hh._bboxToProto(B), embedProps: Hh._structFromJs({kind: "planks"}) }; @@ -9682,7 +9676,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.buildings, coordinates: Hh._listValueFromNested(X), embedUid: "buildings", - embedName: "buildings", embedBbox: Hh._bboxToProto(ga), embedParts: fa, embedProps: Hh._structFromJs({kind: "buildings"}) @@ -9693,7 +9686,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.prisms, coordinates: Hh._listValueFromNested(Y), embedUid: "prisms", - embedName: "prisms", embedBbox: Hh._bboxToProto(B), embedParts: ma, embedProps: Hh._structFromJs({kind: "prisms"}) @@ -9704,7 +9696,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.trees, coordinates: Hh._listValueFromNested(na2), embedUid: "trees", - embedName: "trees", embedBbox: Hh._bboxToProto(oa), embedParts: pa, embedProps: Hh._structFromJs({kind: "trees"}) @@ -9717,7 +9708,6 @@ var $lime_init = function (E, u) { type: DataProto.data.GeoType.FeatureCollection, features: b, embedUid: "root", - embedName: a.name, embedExportTransform: f, embedBbox: Hh._bboxToProto(l), embedEditorPayload: { @@ -9758,7 +9748,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.water, coordinates: Hh._listValueFromNested(ua), embedUid: "water", - embedName: "water", embedBbox: Hh._bboxToProto(wa), embedParts: va, embedProps: Hh._structFromJs({kind: "water"}) @@ -9781,7 +9770,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.extendable, coordinates: Hh._listValueFromNested(Fa), embedUid: "extendable", - embedName: "extendable", embedBbox: Hh._bboxToProto(Ga), embedParts: Ha, embedProps: Hh._structFromJs({kind: "extendable"}) @@ -9807,7 +9795,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.squares, coordinates: Hh._listValueFromNested([Na2]), embedUid: "squares", - embedName: "squares", embedBbox: Hh._bboxToProto(Oa2), embedParts: [{ index: 0, @@ -9850,7 +9837,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.palisade, coordinates: Hh._listValueFromNested(Pa2), embedUid: "palisade", - embedName: "palisade", embedBbox: Hh._bboxToProto(Ra2), embedParts: Qa2, embedProps: Hh._structFromJs({kind: "palisade"}) @@ -9898,7 +9884,6 @@ var $lime_init = function (E, u) { id: DataProto.data.GeoFeatureType.fields, coordinates: Hh._listValueFromNested(da2), embedUid: "fields", - embedName: "fields", embedBbox: Hh._bboxToProto(ga2), embedParts: ka2, embedProps: Hh._structFromJs({kind: "fields"}) @@ -9926,7 +9911,6 @@ var $lime_init = function (E, u) { a.version != null && (b.version = a.version); a.embedUid != null && (b.embedUid = a.embedUid); - a.embedName != null && (b.embedName = a.embedName); a.embedExportTransform != null && (b.embedExportTransform = { scale: a.embedExportTransform.scale, diff --git a/src/js/mfcg.js b/src/js/mfcg.js index fe26aa9..acb8d6c 100644 --- a/src/js/mfcg.js +++ b/src/js/mfcg.js @@ -8029,14 +8029,12 @@ var $lime_init = function (A, t) { a.generator != null && Object.hasOwnProperty.call(a, "generator") && (b.generator = DataProto.data.GeoGeneratorType[a.generator]); a.version != null && Object.hasOwnProperty.call(a, "version") && (b.version = a.version); a.embedUid != null && Object.hasOwnProperty.call(a, "embedUid") && (b.uid = a.embedUid); - a.embedName != null && Object.hasOwnProperty.call(a, "embedName") && (b.displayName = a.embedName); return b }, lg.enrichGeoObj = function (a, b) { if (a == null) return; a.embedExportTransform == null && b != null && b.transform != null && (a.embedExportTransform = b.transform); (a.embedUid == null || "" === a.embedUid) && b != null && b.uid != null && (a.embedUid = b.uid); - a.embedName == null && (a.name != null && Object.hasOwnProperty.call(a, "name") ? a.embedName = a.name : a.id != null && Object.hasOwnProperty.call(a, "id") && (a.embedName = DataProto.data.GeoFeatureType[a.id])); if (a.embedProps == null) { var c = lg.buildPropsForObj(a); c != null && (a.embedProps = lg.toStruct(c)) @@ -8067,7 +8065,6 @@ var $lime_init = function (A, t) { var c = lg.makeTransform(); a.embedExportTransform = c; a.embedUid = "root"; - b != null && b.name != null && (a.embedName = b.name); a.embedEditorPayload = lg.makeEditorPayload(b); a.embedProps == null && (a.embedProps = lg.toStruct({generator: "mfcg", version: A.current.meta.h.version, blueprint: b != null ? b.bp : null, state: ba.data, url: za.data})); lg.enrichGeoObj(a, {uid: "root", transform: c}) @@ -8084,7 +8081,6 @@ var $lime_init = function (A, t) { a.version != null && Object.hasOwnProperty.call(a, "version") && (c.version = a.version); a.riverWidth != null && Object.hasOwnProperty.call(a, "riverWidth") && (c.riverWidth = a.riverWidth); a.embedUid != null && Object.hasOwnProperty.call(a, "embedUid") && (c.embedUid = a.embedUid); - a.embedName != null && Object.hasOwnProperty.call(a, "embedName") && (c.embedName = a.embedName); a.embedExportTransform != null && Object.hasOwnProperty.call(a, "embedExportTransform") && (c.embedExportTransform = {scale: a.embedExportTransform.scale, cx: a.embedExportTransform.cx, cy: a.embedExportTransform.cy, invertY: a.embedExportTransform.invertY, precisionPow10: a.embedExportTransform.precisionPow10}); a.embedBbox != null && Object.hasOwnProperty.call(a, "embedBbox") && (c.embedBbox = {minX: a.embedBbox.minX, minY: a.embedBbox.minY, maxX: a.embedBbox.maxX, maxY: a.embedBbox.maxY}); a.embedProps != null && Object.hasOwnProperty.call(a, "embedProps") && (c.embedProps = lg.structToJson(a.embedProps)); From 29a6e000aab0916c6d8f923aa88eb2848e49d326 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 18:46:02 +0100 Subject: [PATCH 12/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=BB=20=D0=BA=D0=BE=D1=81=D1=8F=D0=BA=20=D1=87?= =?UTF-8?q?=D1=82=D0=BE=20=D0=BD=D0=B5=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B6=D0=B0=D0=BB=D0=B8=D1=81=D1=8C=20=D0=B4=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/ToyTown2.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/js/ToyTown2.js b/src/js/ToyTown2.js index e019b01..e0bad77 100644 --- a/src/js/ToyTown2.js +++ b/src/js/ToyTown2.js @@ -18383,8 +18383,11 @@ if (params !== null) (function (S, u) { case DataProto.data.GeoType[DataProto.data.GeoType.GeometryCollection]: a = a.geometries; c = []; - if(typeof a === "array"){ - for (b = 0; b < a.length;) d = a[b], ++b, c.push(new lf(this.getLineString(d), d.width)); + if (Array.isArray(a)) { + for (var i = 0; i < a.length; i++) { + var d = a[i]; + c.push(new lf(this.getLineString(d), d.width)); + } } return c; default: From eb79201cbaa1ada489720e6098799a5da62d4175 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 18:54:58 +0100 Subject: [PATCH 13/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D1=80=D0=B0=D1=81=D0=BA=D0=B8?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=20=D0=BF=D1=80=D0=BE=D1=82=D0=BE,=20=D0=B2?= =?UTF-8?q?=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D1=87=D0=B0=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BB=D0=B8=D1=88=D0=BD=D1=8F=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protobuf/data/geo/common.proto | 30 +++++++ protobuf/data/geo/editor.proto | 105 ++++++++++++++++++++++++ protobuf/data/geo/enum.proto | 27 ++++++- protobuf/data/geo/obj.proto | 141 +-------------------------------- src/js/Village.js | 2 +- src/js/mfcg.js | 2 +- 6 files changed, 163 insertions(+), 144 deletions(-) create mode 100644 protobuf/data/geo/common.proto create mode 100644 protobuf/data/geo/editor.proto diff --git a/protobuf/data/geo/common.proto b/protobuf/data/geo/common.proto new file mode 100644 index 0000000..b4acd89 --- /dev/null +++ b/protobuf/data/geo/common.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package data; + +import "google/protobuf/struct.proto"; + +// // // // + +message GeoTransformObj { + double scale = 1; + double cx = 2; + double cy = 3; + bool invert_y = 4; + uint32 precision_pow10 = 5; +} + +message GeoBBoxObj { + double min_x = 1; + double min_y = 2; + double max_x = 3; + double max_y = 4; +} + +message GeoPartObj { + uint32 index = 1; + string uid = 2; + google.protobuf.Struct props = 3; + string name = 4; + GeoBBoxObj bbox = 5; +} diff --git a/protobuf/data/geo/editor.proto b/protobuf/data/geo/editor.proto new file mode 100644 index 0000000..5b31229 --- /dev/null +++ b/protobuf/data/geo/editor.proto @@ -0,0 +1,105 @@ +syntax = "proto3"; + +package data; + +import "google/protobuf/struct.proto"; +import "data/geo/enum.proto"; + +// // // // + +message EditorPoint2DObj { + double x = 1; + double y = 2; +} + +message EditorPolylineObj { + repeated EditorPoint2DObj points = 1; + bool closed = 2; +} + +message EditorBezierObj { + repeated EditorPoint2DObj control_points = 1; + + bool closed = 2; + uint32 segments = 3; +} + +message EditorArcObj { + EditorPoint2DObj center = 1; + double radius = 2; + double start_angle_rad = 3; + double end_angle_rad = 4; + bool ccw = 5; +} + +message EditorLinkObj { + string a_uid = 1; + string b_uid = 2; + EditorLinkType type = 3; + google.protobuf.Struct props = 4; +} + +message EditorLayerStateObj { + string layer_id = 1; + bool visible = 2; + bool locked = 3; + int32 z_index = 4; +} + +message EditorGroupObj { + string group_uid = 1; + string name = 2; + repeated string member_uids = 3; + google.protobuf.Struct props = 4; +} + +message EditorRoadModelObj { + string target_uid = 1; + EditorPolylineObj centerline = 2; + double width = 3; + bool closed = 4; + google.protobuf.Struct props = 5; +} + +message EditorShapeModelObj { + string target_uid = 1; + + oneof model { + EditorPolylineObj polyline = 2; + EditorBezierObj bezier = 3; + EditorArcObj arc = 4; + } + + google.protobuf.Struct props = 10; +} + +message EditorSnapNodeObj { + string node_uid = 1; + EditorPoint2DObj pos = 2; + repeated string incident_uids = 3; + google.protobuf.Struct props = 4; +} + +message EditorConstraintObj { + string constraint_uid = 1; + EditorConstraintType type = 2; + repeated string target_uids = 3; + google.protobuf.Struct params = 4; +} + +message EditorPayloadObj { + uint32 payload_rev = 1; + EditorCoordSpaceType coord_space = 2; + + repeated EditorLayerStateObj layers = 10; + repeated EditorGroupObj groups = 11; + repeated EditorLinkObj links = 12; + + repeated EditorRoadModelObj road_models = 20; + repeated EditorShapeModelObj shape_models = 21; + + repeated EditorSnapNodeObj snap_nodes = 30; + repeated EditorConstraintObj constraints = 31; + + google.protobuf.Struct props = 40; +} diff --git a/protobuf/data/geo/enum.proto b/protobuf/data/geo/enum.proto index 843e3cc..81aac73 100644 --- a/protobuf/data/geo/enum.proto +++ b/protobuf/data/geo/enum.proto @@ -2,8 +2,6 @@ syntax = "proto3"; package data; -import "google/protobuf/struct.proto"; - // // // // enum GeoFeatureType { @@ -58,4 +56,27 @@ enum GeoType { Polygon = 23; MultiPolygon = 24; reserved 25 to 50; -} \ No newline at end of file +} + +enum EditorCoordSpaceType { + EDITOR_COORD_SPACE_UNSPECIFIED = 0; + world = 1; + export = 2; +} + +enum EditorLinkType { + EDITOR_LINK_TYPE_UNSPECIFIED = 0; + EDITOR_LINK_TYPE_PARENT_CHILD = 1; + EDITOR_LINK_TYPE_GROUP_MEMBER = 2; + EDITOR_LINK_TYPE_ATTACH = 3; + EDITOR_LINK_TYPE_OVER_UNDER = 4; + EDITOR_LINK_TYPE_ALONG = 5; +} + +enum EditorConstraintType { + EDITOR_CONSTRAINT_TYPE_UNSPECIFIED = 0; + EDITOR_CONSTRAINT_TYPE_SNAP = 1; + EDITOR_CONSTRAINT_TYPE_FIXED_LENGTH = 2; + EDITOR_CONSTRAINT_TYPE_PARALLEL = 3; + EDITOR_CONSTRAINT_TYPE_PERPENDICULAR = 4; +} diff --git a/protobuf/data/geo/obj.proto b/protobuf/data/geo/obj.proto index d26d37c..e3de48d 100644 --- a/protobuf/data/geo/obj.proto +++ b/protobuf/data/geo/obj.proto @@ -4,148 +4,11 @@ package data; import "google/protobuf/struct.proto"; import "data/geo/enum.proto"; +import "data/geo/common.proto"; +import "data/geo/editor.proto"; // // // // -message GeoTransformObj { - double scale = 1; - double cx = 2; - double cy = 3; - bool invert_y = 4; - uint32 precision_pow10 = 5; -} - -message GeoBBoxObj { - double min_x = 1; - double min_y = 2; - double max_x = 3; - double max_y = 4; -} - -message GeoPartObj { - uint32 index = 1; - string uid = 2; - google.protobuf.Struct props = 3; - string name = 4; - GeoBBoxObj bbox = 5; -} - -enum EditorCoordSpaceType { - EDITOR_COORD_SPACE_UNSPECIFIED = 0; - EDITOR_COORD_SPACE_WORLD = 1; - EDITOR_COORD_SPACE_EXPORT = 2; -} - -message EditorPoint2DObj { - double x = 1; - double y = 2; -} -message EditorPolylineObj { - repeated EditorPoint2DObj points = 1; - bool closed = 2; -} -message EditorBezierObj { - repeated EditorPoint2DObj control_points = 1; - - bool closed = 2; - uint32 segments = 3; -} - -message EditorArcObj { - EditorPoint2DObj center = 1; - double radius = 2; - double start_angle_rad = 3; - double end_angle_rad = 4; - bool ccw = 5; -} - -enum EditorLinkType { - EDITOR_LINK_TYPE_UNSPECIFIED = 0; - EDITOR_LINK_TYPE_PARENT_CHILD = 1; - EDITOR_LINK_TYPE_GROUP_MEMBER = 2; - EDITOR_LINK_TYPE_ATTACH = 3; - EDITOR_LINK_TYPE_OVER_UNDER = 4; - EDITOR_LINK_TYPE_ALONG = 5; -} - -message EditorLinkObj { - string a_uid = 1; - string b_uid = 2; - EditorLinkType type = 3; - google.protobuf.Struct props = 4; -} - -message EditorLayerStateObj { - string layer_id = 1; - bool visible = 2; - bool locked = 3; - int32 z_index = 4; -} - -message EditorGroupObj { - string group_uid = 1; - string name = 2; - repeated string member_uids = 3; - google.protobuf.Struct props = 4; -} - -message EditorRoadModelObj { - string target_uid = 1; - EditorPolylineObj centerline = 2; - double width = 3; - bool closed = 4; - google.protobuf.Struct props = 5; -} - -message EditorShapeModelObj { - string target_uid = 1; - - oneof model { - EditorPolylineObj polyline = 2; - EditorBezierObj bezier = 3; - EditorArcObj arc = 4; - } - - google.protobuf.Struct props = 10; -} - - -message EditorSnapNodeObj { - string node_uid = 1; - EditorPoint2DObj pos = 2; - repeated string incident_uids = 3; - google.protobuf.Struct props = 4; -} - -enum EditorConstraintType { - EDITOR_CONSTRAINT_TYPE_UNSPECIFIED = 0; - EDITOR_CONSTRAINT_TYPE_SNAP = 1; - EDITOR_CONSTRAINT_TYPE_FIXED_LENGTH = 2; - EDITOR_CONSTRAINT_TYPE_PARALLEL = 3; - EDITOR_CONSTRAINT_TYPE_PERPENDICULAR = 4; -} - -message EditorConstraintObj { - string constraint_uid = 1; - EditorConstraintType type = 2; - repeated string target_uids = 3; - google.protobuf.Struct params = 4; -} - -message EditorPayloadObj { - uint32 payload_rev = 1; - EditorCoordSpaceType coord_space = 2; - repeated EditorLayerStateObj layers = 10; - repeated EditorGroupObj groups = 11; - repeated EditorLinkObj links = 12; - repeated EditorRoadModelObj road_models = 20; - repeated EditorShapeModelObj shape_models = 21; - repeated EditorSnapNodeObj snap_nodes = 30; - repeated EditorConstraintObj constraints = 31; - google.protobuf.Struct props = 40; -} - - message GeoObj { GeoType type = 1; GeoObj geometry = 2; diff --git a/src/js/Village.js b/src/js/Village.js index e7e8f2d..113eaab 100644 --- a/src/js/Village.js +++ b/src/js/Village.js @@ -9712,7 +9712,7 @@ var $lime_init = function (E, u) { embedBbox: Hh._bboxToProto(l), embedEditorPayload: { payloadRev: 1, - coordSpace: 1, + coordSpace: DataProto.data.EditorCoordSpaceType.world, roadModels: h, shapeModels: k, props: Hh._structFromJs({generator: "vg", version: params.meta.ver_app}) diff --git a/src/js/mfcg.js b/src/js/mfcg.js index acb8d6c..b5fc0d4 100644 --- a/src/js/mfcg.js +++ b/src/js/mfcg.js @@ -8054,7 +8054,7 @@ var $lime_init = function (A, t) { za.init(); var b = new DataProto.data.EditorPayloadObj; b.payloadRev = 1; - b.coordSpace = DataProto.data.EditorCoordSpaceType.EDITOR_COORD_SPACE_EXPORT; + b.coordSpace = DataProto.data.EditorCoordSpaceType.export; var c = {state: ba.data, url: za.data}; a != null && (c.blueprint = a.bp, c.name = a.name); b.props = lg.toStruct(c); From edc2f28ffb437bc840e049ec6c915ef7def868e4 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 19:02:57 +0100 Subject: [PATCH 14/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B0=D0=B9=D0=B4?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA=20=D0=B2=203=D0=B4=20=D1=80=D0=B5=D0=BD=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=20=D0=B5=D1=89=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/ToyTown2.js | 81 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 19 deletions(-) diff --git a/src/js/ToyTown2.js b/src/js/ToyTown2.js index e0bad77..d551237 100644 --- a/src/js/ToyTown2.js +++ b/src/js/ToyTown2.js @@ -17033,6 +17033,11 @@ if (params !== null) (function (S, u) { } d = kf.render(h, !1, 2); Cc.addStartCap(d, e); + + if (!f || f.length < 2) { + console.warn("Bad road poly:", d); + continue; + } this.addSubGeometry(new Cc(d, e)) } }; @@ -18367,31 +18372,69 @@ if (params !== null) (function (S, u) { DataProto.data.GeoGeneratorType[DataProto.data.GeoGeneratorType.mfcg] == this.generator && (7 > a[1] || 7 == a[1] && 5 > a[2]) && (this.scale = bc.LEGACY_SCALE) }, getThickMultiLineString: function (a, b) { - null == b && (b = 0); - var c = a.type; - if (null == c) return this.thicken(this.getMultiLineString(a), b); - switch (c) { + if (b == null) b = 0; + var defaultWidth = b; + + var t = a.type; + if (t == null) { + var lines = this.getMultiLineString(a) || []; + var out0 = []; + for (var i0 = 0; i0 < lines.length; i0++) { + var line0 = lines[i0]; + if (!line0 || line0.length < 2) { + console.warn("Skip bad line (need >=2 points):", line0); + continue; + } + out0.push(new lf(line0, defaultWidth)); + } + return out0; + } + + switch (t) { case DataProto.data.GeoType[DataProto.data.GeoType.FeatureCollection]: - a = a.features; - c = []; - for (b = 0; b < a.length;) { - var d = a[b]; - ++b; - c.push(new lf(this.getLineString(d.geometry), d.width)) + var features = a.features || []; + var out = []; + for (var i = 0; i < features.length; i++) { + var f = features[i]; + var poly = this.getLineString(f.geometry); + if (!poly || poly.length < 2) { + console.warn("Skip bad road feature (need >=2 points):", f); + continue; + } + var w = (f.width != null) ? f.width : defaultWidth; + out.push(new lf(poly, w)); } - return c; + return out; + case DataProto.data.GeoType[DataProto.data.GeoType.GeometryCollection]: - a = a.geometries; - c = []; - if (Array.isArray(a)) { - for (var i = 0; i < a.length; i++) { - var d = a[i]; - c.push(new lf(this.getLineString(d), d.width)); + var geoms = a.geometries || []; + var out2 = []; + if (Array.isArray(geoms)) { + for (var j = 0; j < geoms.length; j++) { + var g = geoms[j]; + var poly2 = this.getLineString(g); + if (!poly2 || poly2.length < 2) { + console.warn("Skip bad road geometry (need >=2 points):", g); + continue; + } + var w2 = (g.width != null) ? g.width : defaultWidth; + out2.push(new lf(poly2, w2)); } } - return c; + return out2; + default: - return this.thicken(this.getMultiLineString(a), b) + var lines2 = this.getMultiLineString(a) || []; + var out3 = []; + for (var k = 0; k < lines2.length; k++) { + var line = lines2[k]; + if (!line || line.length < 2) { + console.warn("Skip bad line (need >=2 points):", line); + continue; + } + out3.push(new lf(line, defaultWidth)); + } + return out3; } }, getThickMultiPolygon: function (a, b) { From a269cb8e9f48804dd82d4cee09eba7f53bd09743 Mon Sep 17 00:00:00 2001 From: SunSung-W541-2025 Date: Thu, 12 Feb 2026 19:14:30 +0100 Subject: [PATCH 15/15] =?UTF-8?q?add/data/other-types-of-export=20[1.2.3-a?= =?UTF-8?q?dd-data-other-types-of-.1]=20=20=D0=B2=D1=80=D0=BE=D0=B4=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=D0=B4=D0=BD=D0=B5=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B9=D0=BC=D0=B0=D0=BD=D0=BD=D0=BE=D0=B5=20=D0=B2?= =?UTF-8?q?=203=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/ToyTown2.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/js/ToyTown2.js b/src/js/ToyTown2.js index d551237..7c6c405 100644 --- a/src/js/ToyTown2.js +++ b/src/js/ToyTown2.js @@ -17637,8 +17637,12 @@ if (params !== null) (function (S, u) { }; ia.addWall = function (a, b, c, d, e, f) { var h = Q.distance(b, e), - r = Math.min(c.y, d.y) - ia.zero, - m = 1.8, + r = Math.min(c.y, d.y) - ia.zero; + if (!isFinite(h) || h <= 1e-6 || !isFinite(r) || r <= 0) { + ia.addWindowlessWall(a, b, c, d, e, f); + return; + } + var m = 1.8, C = 3, g = 2, k = 1.5; @@ -17646,6 +17650,10 @@ if (params !== null) (function (S, u) { 1)); var n = Math.floor((h - 2 * g + C) / (.8 + C)), l = Math.floor((r - k - q + m) / (1.2 + m)); + if (!isFinite(n) || !isFinite(l) || n < 1 || l < 1) { + ia.addWindowlessWall(a, b, c, d, e, f); + return; + } if (1 > n || 1 > l) ia.addWindowlessWall(a, b, c, d, e, f); else { var p = (r - 1.2 * l) / (k + (l - 1) * m + q); @@ -18075,6 +18083,10 @@ if (params !== null) (function (S, u) { d *= Math.pow(kd.area(b) / kd.rectArea(e), 2); var f = ba.distance(e[0], e[1]), h = ba.distance(e[2], e[1]); + if (!isFinite(q) || q <= 1e-6) { + Pf.add(a, b, c, true); + return; + } if (f < h) { var r = vc.lerp(e[0], e[1]); var m = vc.lerp(e[2], e[3]);