Data model ice (#1279)
Some checks are pending
Deploy static content to Pages / deploy (push) Waiting to run

* prototype for ice seperation

* feat: migrate ice data to new data model and update version to 1.110.0

* refactor: update ice data handling and rendering for improved performance

* feat: integrate ice generation and recalculation in heightmap editing

* fix ice selection(hopefully)

* fix ice selection better(pls)

* refactor: remove redundant element selection in ice editing functions

* fix: clear ice data before generating glaciers and icebergs

* sparse array implementation with reduced updates

* fix logic chech in modules/dynamic/auto-update.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: migrate ice data to new data model structure

* refactor: streamline ice generation process and clean up rendering functions

* refactor: simplify ice rendering logic by removing redundant clearing of old SVG

* fix: update editIce function to accept element parameter and improve logic for glacier handling

* ice drawing with only type on less occuring glaciers

* feat: add compactPackData function to filter out undefined glaciers and icebergs

* fix: clear existing ice elements before redrawing in editHeightmap function

* fix compact problems on autosave

* refactor: unify ice data structure and streamline ice element handling

* refactor: improve getNextId function to fill gaps in ice element IDs(optional commit)

* just to be sure

* bump version in html

* fix index.html script import

* feat: add ice module script to index.html

* fix migration check

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
kruschen 2026-01-22 22:24:34 +01:00 committed by GitHub
parent 81c1ba2963
commit 4b341a6590
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 403 additions and 118 deletions

View file

@ -253,8 +253,8 @@ export function resolveVersionConflicts(mapVersion) {
const source = findCell(s.x, s.y);
const mouth = findCell(e.x, e.y);
const name = Rivers.getName(mouth);
const type = length < 25 ? rw({Creek: 9, River: 3, Brook: 3, Stream: 1}) : "River";
pack.rivers.push({i, parent: 0, length, source, mouth, basin: i, name, type});
const type = length < 25 ? rw({ Creek: 9, River: 3, Brook: 3, Stream: 1 }) : "River";
pack.rivers.push({ i, parent: 0, length, source, mouth, basin: i, name, type });
});
}
@ -270,7 +270,7 @@ export function resolveVersionConflicts(mapVersion) {
const era = Names.getBaseShort(P(0.7) ? 1 : rand(nameBases.length)) + " Era";
const eraShort = era[0] + "E";
const military = Military.getDefaultOptions();
options = {winds, year, era, eraShort, military};
options = { winds, year, era, eraShort, military };
// v1.3 added campaings data for all states
States.generateCampaigns();
@ -481,7 +481,7 @@ export function resolveVersionConflicts(mapVersion) {
if (isOlderThan("1.65.0")) {
// v1.65 changed rivers data
d3.select("#rivers").attr("style", null); // remove style to unhide layer
const {cells, rivers} = pack;
const { cells, rivers } = pack;
const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2);
for (const river of rivers) {
@ -497,8 +497,8 @@ export function resolveVersionConflicts(mapVersion) {
for (let i = 0; i <= segments; i++) {
const shift = increment * i;
const {x: x1, y: y1} = node.getPointAtLength(length + shift);
const {x: x2, y: y2} = node.getPointAtLength(length - shift);
const { x: x1, y: y1 } = node.getPointAtLength(length + shift);
const { x: x2, y: y2 } = node.getPointAtLength(length - shift);
const x = rn((x1 + x2) / 2, 1);
const y = rn((y1 + y2) / 2, 1);
@ -565,7 +565,7 @@ export function resolveVersionConflicts(mapVersion) {
const fill = circle && circle.getAttribute("fill");
const stroke = circle && circle.getAttribute("stroke");
const marker = {i, icon, type, x, y, size, cell};
const marker = { i, icon, type, x, y, size, cell };
if (size && size !== 30) marker.size = size;
if (!isNaN(px) && px !== 12) marker.px = px;
if (!isNaN(dx) && dx !== 50) marker.dx = dx;
@ -631,7 +631,7 @@ export function resolveVersionConflicts(mapVersion) {
if (isOlderThan("1.88.0")) {
// v1.87 may have incorrect shield for some reason
pack.states.forEach(({coa}) => {
pack.states.forEach(({ coa }) => {
if (coa?.shield === "state") delete coa.shield;
});
}
@ -639,13 +639,13 @@ export function resolveVersionConflicts(mapVersion) {
if (isOlderThan("1.91.0")) {
// from 1.91.00 custom coa is moved to coa object
pack.states.forEach(state => {
if (state.coa === "custom") state.coa = {custom: true};
if (state.coa === "custom") state.coa = { custom: true };
});
pack.provinces.forEach(province => {
if (province.coa === "custom") province.coa = {custom: true};
if (province.coa === "custom") province.coa = { custom: true };
});
pack.burgs.forEach(burg => {
if (burg.coa === "custom") burg.coa = {custom: true};
if (burg.coa === "custom") burg.coa = { custom: true };
});
// from 1.91.00 emblems don't have transform attribute
@ -747,7 +747,7 @@ export function resolveVersionConflicts(mapVersion) {
const skip = terrs.attr("skip");
const relax = terrs.attr("relax");
const curveTypes = {0: "curveBasisClosed", 1: "curveLinear", 2: "curveStep"};
const curveTypes = { 0: "curveBasisClosed", 1: "curveLinear", 2: "curveStep" };
const curve = curveTypes[terrs.attr("curve")] || "curveBasisClosed";
terrs
@ -882,7 +882,7 @@ export function resolveVersionConflicts(mapVersion) {
const secondCellId = points[1][2];
const feature = pack.cells.f[secondCellId];
pack.routes.push({i: pack.routes.length, group, feature, points});
pack.routes.push({ i: pack.routes.length, group, feature, points });
}
}
routes.selectAll("path").remove();
@ -914,7 +914,7 @@ export function resolveVersionConflicts(mapVersion) {
const type = this.dataset.type;
const color = this.getAttribute("fill");
const cells = this.dataset.cells.split(",").map(Number);
pack.zones.push({i, name, type, cells, color});
pack.zones.push({ i, name, type, cells, color });
});
zones.style("display", null).selectAll("*").remove();
if (layerIsOn("toggleZones")) drawZones();
@ -975,7 +975,7 @@ export function resolveVersionConflicts(mapVersion) {
if (isOlderThan("1.109.0")) {
// v1.109.0 added customizable burg groups and icons
options.burgs = {groups: []};
options.burgs = { groups: [] };
burgIcons.selectAll("circle, use").each(function () {
const group = this.parentNode.id;
@ -987,7 +987,7 @@ export function resolveVersionConflicts(mapVersion) {
burgIcons.selectAll("g").each(function (_el, index) {
const name = this.id;
const isDefault = name === "towns";
options.burgs.groups.push({name, active: true, order: index + 1, isDefault, preview: "watabou-city"});
options.burgs.groups.push({ name, active: true, order: index + 1, isDefault, preview: "watabou-city" });
if (!this.dataset.icon) this.dataset.icon = "#icon-circle";
const size = Number(this.getAttribute("size") || 2) * 2;
@ -1036,4 +1036,74 @@ export function resolveVersionConflicts(mapVersion) {
delete options.showMFCGMap;
delete options.villageMaxPopulation;
}
if (isOlderThan("1.111.0")) {
// v1.111.0 moved ice data from SVG to data model
// Migrate old ice SVG elements to new pack.ice structure
if (!pack.ice.length) {
pack.ice = [];
let iceId = 0;
const iceLayer = document.getElementById("ice");
if (iceLayer) {
// Migrate glaciers (type="iceShield")
iceLayer.querySelectorAll("polygon[type='iceShield']").forEach(polygon => {
// Parse points string "x1,y1 x2,y2 x3,y3 ..." into array [[x1,y1], [x2,y2], ...]
const points = [...polygon.points].map(svgPoint => [svgPoint.x, svgPoint.y]);
const transform = polygon.getAttribute("transform");
const iceElement = {
i: iceId++,
points,
type: "glacier"
};
if (transform) {
iceElement.offset = parseTransform(transform);
}
pack.ice.push(iceElement);
});
// Migrate icebergs
iceLayer.querySelectorAll("polygon:not([type])").forEach(polygon => {
const cellId = +polygon.getAttribute("cell");
const size = +polygon.getAttribute("size");
// points string must exist, cell attribute must be present, and size must be non-zero
if (polygon.getAttribute("cell") === null || !size) return;
// Parse points string "x1,y1 x2,y2 x3,y3 ..." into array [[x1,y1], [x2,y2], ...]
const points = [...polygon.points].map(svgPoint => [svgPoint.x, svgPoint.y]);
const transform = polygon.getAttribute("transform");
const iceElement = {
i: iceId++,
points,
type: "iceberg",
cellId,
size
};
if (transform) {
iceElement.offset = parseTransform(transform);
}
pack.ice.push(iceElement);
});
// Clear old SVG elements
iceLayer.querySelectorAll("*").forEach(el => el.remove());
} else {
// If ice layer element doesn't exist, create it
ice = viewbox.insert("g", "#coastline").attr("id", "ice");
ice
.attr("opacity", null)
.attr("fill", "#e8f0f6")
.attr("stroke", "#e8f0f6")
.attr("stroke-width", 1)
.attr("filter", "url(#dropShadow05)");
}
// Re-render ice from migrated data
if (layerIsOn("toggleIce")) drawIce();
}
}
}