Skip to content

Releases: CDS-SP/minecraft-citygen

CityGen 0.4.1 (Windows)

Choose a tag to compare

@chengmarc chengmarc released this 20 Aug 18:43

CityGen 0.4.1 Release Notes

Released on August 20, 2026.

This is a patch release for the extracted-asset ground offset refactor. Building
placement already read the authored ground_offset; this release extends that
same offset path to roads and fill props so every marker-authored asset seats
from extracted metadata instead of assuming a hard-coded flush origin.

Highlights

  • Roads and trees now seat from extracted asset metadata. The city
    constructor no longer treats them as implicitly flush assets with a baked-in
    0 Y offset.
  • Road/fill schematics now persist their authored ground offset. The
    extraction stage writes the asset ground seat into the Sponge Offset field,
    and the loader preserves it through rotation and composition.

What Changed

Unified offset plumbing

  • pipeline/01_roads_extract.py now writes each extracted road or fill asset's
    ground offset into the schematic Offset field.
  • engine/schematic_reader.py now reads the Sponge Offset field, and
    engine/road_schematic.py attaches that value to loaded tiles as
    ground_offset.
  • engine/schematic_transform.py now preserves ground_offset when rotating a
    tile, so randomized fill-prop rotation does not lose the authored seat.

City construction

  • pipeline/04_city_construct.py now seats the road grid from the shared road
    offset returned by the road schematic builder.
  • Fill props are now seated from each tile's extracted ground_offset instead
    of from a hard-coded flush assumption.
  • pipeline/03_grid_construct.py now preserves the road-grid offset when
    exporting the combined grid schematic.

Upgrade notes

  • Re-extract road assets before rebuilding outputs. Existing road and fill
    schematics exported before 0.4.1 do not carry the new offset metadata, so
    they will still read as zero-offset assets until regenerated.
  • After re-extraction, re-run the grid and city construction stages to pick up
    the corrected seating.

Verification

  • python -m compileall src/engine/schematic_reader.py src/engine/schematic_transform.py src/engine/road_schematic.py src/pipeline/01_roads_extract.py src/pipeline/03_grid_construct.py src/pipeline/04_city_construct.py
  • python src/pipeline/03_grid_construct.py --seed 1 --fine 8 --out .codex/grid_offset_smoke.schem
  • python src/pipeline/04_city_construct.py --seed 1 --fine 8 --out .codex/city_offset_smoke.schem

CityGen 0.4.0 (Windows)

Choose a tag to compare

@chengmarc chengmarc released this 20 Aug 16:39

CityGen 0.4.0 Release Notes

Released on August 21, 2026.

This release fills the empty space in a generated city. The gaps between roads and
buildings are now populated with fill props — self-contained one-cell assets
that carry their own ground — and the bundled world ships three of them as trees.
Along the way, road extraction was unified with the building marker convention, so
there is no longer any road-specific detection logic.

Highlights

  • Empty lot cells are filled with a randomly chosen, randomly rotated fill
    prop
    . The bundled world ships three trees (spruce, birch, oak), so open ground
    reads as landscaped space instead of a flat plate.
  • Road extraction now shares the building marker convention. Road tiles and
    fill props are authored exactly like a type-1 build (wool boundary +
    gold/diamond/emerald markers + a name sign) and run through the same extraction.
  • The top-down simulation preview places matching tree tiles in the same
    cells with the same seed, so the preview lines up with the built city.

What Changed

Fill props (empty-space filling)

  • A new asset class — fill props — is authored in the road region alongside
    the road tiles (15_fill_1x1_A, 16_fill_1x1_B, 17_fill_1x1_C). Each is a
    self-contained 9x9 (one fine cell) asset that carries its own ground.
  • pipeline/04_city_construct.py drops a random, randomly rotated prop into every
    fully-empty non-road lot cell, seated on the lot ground plane. Cells occupied by
    a building are skipped, and prop cells are excluded from the flat ground fill so
    nothing pokes up through a prop's own ground.
  • pipeline/01_roads_simulation.py draws top-down tile PNGs for the props, and
    pipeline/04_city_simulation.py scatters them into the preview with the same
    seed used by the build.

Shared marker extraction

  • engine/marker_extract.py is a new module holding the wool-boundary +
    gold/diamond/emerald cuboid extraction. Both 02_builds_extract and
    01_roads_extract now call into it.
  • The old road detector (top-down surface components, yellow_wool/white_wool
    edge trimming, per-column Y-extent) is removed. Author road tiles the same way
    you author a type-1 build.

Ground fill

  • The default empty-lot ground fill block changed from minecraft:smooth_stone
    to minecraft:smooth_stone_slab[type=bottom]. The origin anchor column keeps a
    solid block.

Fixes

  • Tall road and fill assets are no longer clipped to the ROAD_BOX Y span: the
    marker cuboid (gold→diamond) is captured in full, regardless of the box height.
  • Fill props seat flush with the lot surface instead of hovering one block above
    it, and the flat ground fill no longer leaks a block into a prop's cell.

Upgrade notes

  • Custom road worlds must be re-authored. Road extraction no longer keys off
    yellow_wool/white_wool surface markers. Each road tile now needs a wool
    boundary, a gold/diamond marker pair (opposite corners), a single emerald at
    ground level, and a name sign — the same convention as buildings. The bundled
    default world has already been updated.
  • Regenerate roads, then the city, to pick up the new fill props and slab ground:
    re-run the road extraction, grid, and city stages.

Verification

  • python -m pytest
  • python packaging/build_windows_release.py --clean
  • Generate a city and confirm the empty lots are filled with randomly rotated
    trees seated flush with the ground, and that the top-down preview matches.

CityGen 0.3.5 (Windows)

Choose a tag to compare

@chengmarc chengmarc released this 20 Aug 05:28

CityGen 0.3.5 Release Notes

Released on August 20, 2026.

This release overhauls the extraction region selector. Its world preview is
now a true top-down surface map, rendered block-by-block at full resolution and
kept fast the way dedicated map tools do it.

Highlights

  • The region-selector preview is a real top-down surface map — the topmost block
    of each column — instead of the old thin altitude slice that painted most of
    the world flat green.
  • It now renders one pixel per block (full resolution), yet stays fast by
    reading each chunk's precomputed surface heightmap rather than scanning columns.

What Changed

Region selector

  • render_topdown_preview now derives each column's surface from the chunk's
    WORLD_SURFACE heightmap — a single array read per chunk replaces the previous
    per-column vertical scan, and the result no longer depends on the selection's
    Y bounds.
  • Ungenerated columns render as a neutral background instead of fake grass fill.
  • Colours come from each column's highest non-air block, using the corrected
    0.3.0 palette (green foliage, blue water).

Performance

  • The world reader reads each .mca region file once and caches its bytes, so
    all chunks in a region share a single read instead of re-opening the file.
  • Per-chunk colour mapping is vectorized with NumPy (build a palette-to-RGB
    lookup once per section, gather all 256 columns at once).
  • Worlds larger than the full-resolution cap are point-sampled from the same
    heightmaps so the image stays bounded.

UI

  • Removed the drop shadows from the region-selector dialog buttons ("Use
    Selection" / "Cancel"). The extraction "Pick" button keeps its shadow.

New internals

  • World.surface_heightmap(cx, cz) — decodes a chunk's WORLD_SURFACE heightmap
    to per-column surface heights.
  • World.top_solid_block(x, z) — highest non-air block in a column (used as a
    fallback and for verification).

Upgrade notes

  • No configuration or output changes to generated schematics or renders. Only the
    region-selector preview is affected.

Verification

  • python -m pytest
  • python packaging/build_windows_release.py --clean
  • Open the Extraction tab, click Pick, and confirm the preview shows a
    block-by-block top-down surface map.

CityGen 0.3.0 (Windows)

Choose a tag to compare

@chengmarc chengmarc released this 20 Aug 04:42

CityGen 0.3.0 Release Notes

Released on August 20, 2026.

This release follows the Tkinter-to-Qt migration with a structural cleanup of the
Qt GUI layer, a reduction of surrounding tooling debt, and a renderer palette fix.
Unlike 0.2.x, this release does change generated output: biome-tinted blocks
(leaves, grass, vines, water) now render in colour instead of gray, and the
WorldEdit auto-copy step has been removed.

Highlights

  • The 1,100-line gui/qt_app.py was split into focused modules, and the Qt image
    viewer gained a public overlay API so dialogs no longer reach into its internals.
  • The renderer palette now honours Minecraft's biome tinting, so leaves and grass
    are green and water is blue instead of gray.
  • clear_cache.py moved into tools/ and now also clears build, packaging, and
    test caches.
  • Dead code left over from the Tkinter era was removed, and the WorldEdit
    auto-copy step was retired.

What Changed

GUI structure

  • Split gui/qt_app.py into theme, workers, widgets, region_dialog,
    tabs, and app.
  • Flattened the Qt image-viewer factory into module-level classes with a direct
    PySide6 import, and gave QtImageViewer a public overlay API
    (image_rect, set_overlay_rect, clear_overlay) so the region-selector
    dialog no longer touches private members.
  • Replaced string-matched error handling with typed SeedError/ConfigError,
    and the hand-rolled argument loop with argparse (adds --help and a real
    --no-custom-theme flag).
  • Centralized the brand palette and the label-to-value selector mapping, made the
    button-icon helper idempotent, and switched to the static QFontDatabase API.
  • Added headless GUI unit tests covering argument parsing, style configuration,
    and widget value round-trips.

Renderer

  • The palette generator (tools/update_render_colors.py) now reads each model
    face's tintindex and multiplies grayscale colormap masks by a representative
    biome tint (plains foliage/grass, default water; birch and spruce use their
    fixed constants).
  • Tinting is gated on the source texture actually being grayscale and on an
    explicit allow-list, so pre-coloured blocks (cherry and azalea leaves) are left
    untouched.
  • src/engine/color_render.csv was regenerated from the 26.2 client jar.

Tooling and cleanup

  • Removed the WorldEdit auto-copy step and the MC_CITY_WORLDEDIT_SCHEM override.
    The final city schematic is still written to artifacts/city/production/ as a
    WorldEdit-ready .schem.
  • Moved clear_cache.py into tools/ and expanded it to also clear build/,
    dist/, *.egg-info/, .pytest_cache/, and the startup error log.
  • Deduplicated numba across the speed/build dependency extras.

Fixes

  • Replaced the deprecated QFontDatabase() instance call with the static form.
  • Corrected stale "Tkinter" references in entry-point docstrings and comments.

Upgrade notes

  • Renders will look different: foliage and water now show their in-game colours.
    Regenerate any previews or city renders to pick up the new palette.
  • The WorldEdit auto-copy is gone. If you relied on MC_CITY_WORLDEDIT_SCHEM,
    copy the schematic from artifacts/city/production/ yourself instead.
  • clear_cache.py now lives at tools/clear_cache.py; update any scripts that
    invoked it.
  • Local tooling that imported gui.qt_app should import from the new modules
    (gui.app, gui.tabs, gui.widgets, ...).
  • The --custom-qt-theme flag was removed (the theme is on by default); use
    --no-custom-theme to opt out.

Verification

  • python -m pytest
  • python packaging/build_windows_release.py --clean
  • Launch the built executable and confirm the GUI opens and renders show green
    foliage.

CityGen 0.2.1 (Windows)

Choose a tag to compare

@chengmarc chengmarc released this 20 Aug 00:09

CityGen 0.2.1 Release Notes

Released on August 20, 2026.

This is a hot-fix release for the Windows installer build. There are no changes
to application code or generated output — it exists solely to make the packaged
0.2.0 executable start.

The problem

The 0.2.0 Windows build failed immediately on launch with:

_tkinter.TclError: invalid command name "::msgcat::mcmset"

ttkbootstrap initializes localization at startup, which requires Tcl's
msgcat package (version 1.6+, for the ::msgcat::mcmset command). That
package was not bundled, so the interpreter had no such command.

The cause

The PyInstaller Tcl/Tk hook only collected the tcl8.6/ and tk8.6/ script
directories. The Tcl 8.x "module" packages — msgcat, http, tcltest, and
friends — ship as .tm files under a separate tcl8/ directory that sits
beside tcl8.6/, not inside it, so msgcat was never included.

The fix

The hook now also bundles the tcl8/ module tree to the bundle root, where Tcl
looks for it (the module path is resolved relative to the interpreter library,
i.e. [file dirname $tcl_library]/tcl8). package require msgcat now succeeds
and the application starts normally.

Upgrade notes

  • No configuration or output changes.
  • Rebuild the Windows installer to pick up the fix.

Verification

  • python -m pytest
  • python packaging/build_windows_release.py --clean
  • Launch the built executable and confirm the GUI opens.

CityGen 0.2.0 (Windows)

Choose a tag to compare

@chengmarc chengmarc released this 19 Aug 23:40

CityGen 0.2.0 Release Notes

Released on August 20, 2026.

This is an internal refactor and maintenance release. It focuses on structure,
readability, consistency, and cross-platform support. There are no intended
changes to the generated output — the city constructor was verified to produce
byte-identical results (decoded) against the previous implementation.

Highlights

  • The large GUI widgets module was split into focused submodules, and the two
    image viewers now share a common pan/zoom base instead of duplicating it.
  • The city constructor was decomposed into named stages and given readable
    identifiers.
  • Path handling, imports, type-annotation imports, and the logger contract were
    made consistent across the codebase.
  • The per-user data directory is now platform-aware instead of Windows-only.

What Changed

GUI

  • Split gui/widgets.py into viewers, region_dialog, controls, tooltip,
    progress, panels, config_frame, and a shared pan_zoom module.
  • Extracted a shared pan/zoom mixin, removing duplicated zoom, pan, and
    scroll-region logic across the two viewers.
  • Replaced the mutable theme module globals with a single theme object.

Pipeline and engine

  • Decomposed city_construct.run() into named helper stages.
  • Renamed terse identifiers, including the Tile dimension fields
    (W/H/L to width/height/length).
  • Promoted World._load_chunk to a public load_chunk method.
  • Collapsed redundant production-schematic path aliases.
  • Documented the environment-override and module-reload invariant.

Consistency

  • Standardized path construction on pathlib (public constants remain strings).
  • Applied from __future__ import annotations uniformly.
  • Replaced initial-only aliased imports with explicit names.
  • Unified the logger call contract to a single string argument.

Compatibility

  • Made the per-user data directory follow macOS and Linux conventions instead of
    assuming Windows.
  • Added upper version bounds to declared dependencies.

Fixes

  • Narrowed overly broad exception handlers that could hide real failures, while
    keeping the intended top-level and worker error boundaries.
  • Corrected stale file references and machine-specific absolute links in
    docs/TECHNICAL.md.

Upgrade notes

  • No configuration or output changes are expected.
  • Any local tooling that imported the internal gui.widgets module should import
    from the new focused modules instead, and the GUI theme palette is now read
    from gui.common.theme.

Verification

  • python -m pytest
  • python packaging/build_windows_release.py --clean

CityGen 0.1.0 (Windows)

Choose a tag to compare

@chengmarc chengmarc released this 19 Aug 04:28

CityGen 0.1.0 Release Notes

Released on August 19, 2026.

Highlights

  • The project now uses a src/ package layout, which makes packaging and installs cleaner.
  • CityGen can now be installed and launched with command entry points instead of relying on repo-local execution only.
  • Common Minecraft save folders and WorldEdit schematic folders are detected automatically.
  • Windows release packaging now has a defined installer flow built around PyInstaller and Inno Setup.
  • The isometric renderer now works even when numba is not installed, while still using CPU numba acceleration when available.

What Changed

Packaging and runtime

  • Added project metadata and dependencies in pyproject.toml.
  • Added citygen and citygen-doctor command entry points.
  • Moved application code under src/.
  • Added runtime path handling for source, installed, and frozen builds.
  • Added a first-run environment doctor for dependency and path checks.

Minecraft path handling

  • Replaced machine-specific defaults with discovery for common Minecraft launcher save locations.
  • Added WorldEdit schematic-folder discovery with a repo-local fallback.
  • Improved extraction failures when the configured world path is missing.

Windows distribution

  • Added a Windows installer build script.
  • Added PyInstaller hooks for Tcl/Tk so the GUI can start reliably in frozen builds.
  • Standardized release output under dist/release/.
  • Set CityGen-setup.exe as the primary release artifact.

Documentation

  • Reorganized screenshots and technical docs under docs/.
  • Added release process documentation and changelog support.
  • Kept README.md at repo root and moved the engineering reference to docs/TECHNICAL.md.

Tests

  • Added regression coverage for path discovery.
  • Added regression coverage for the isometric renderer fallback path.
  • Added test bootstrapping for the new src/ layout.

User-visible fixes

  • Fixed missing runtime dependency declarations in packaging metadata.
  • Replaced Windows-only folder-opening logic with a cross-platform helper.
  • Fixed frozen-app startup issues caused by missing tkinter packaging.

Upgrade notes

  • Direct imports now resolve from src/, so any local tooling that assumed top-level config/, engine/, gui, or pipeline paths should be updated.
  • Technical documentation now lives at docs/TECHNICAL.md.
  • Demo images now live under docs/.

Verification

  • python -m pytest
  • python src/config/doctor.py