Document roadMaterialGroup ownership/lifetime and rename RoadLaneLink to
RoadLaneConnection so value-typed turn records are not treated as Links.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Rebuild makeInterchange so the ground hub reuses the makeCross fillet
sizing and axis arms, smooth the elevated ring/ramps, wire scene key 5
in the example, and cover bake with an interchange scene test.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Keep tip-disk removal, double-sided arc skirts, sidewalk top overhang,
shoulder tip caps, and exact jr trim — rectangular tip pads made more
salmon holes than they sealed.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Trim arms past jr so stub ears disappear, bridge with tip pads whose
outer skirts continue the curb-return tangent, and overhang the sidewalk
top past r2 so the gray arc edge no longer shows through.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Skip full U-caps on big trims still, but emit shoulder-only tip caps so
open arm ends stop showing through at the outer gray corner arcs.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Emit both windings for asphalt curb, curb riser, and outer sidewalk
skirts so overhead views cannot cull them, overlap curb/sidewalk tops
at r1, and densify the arc. Tip disk to (±jr,±jr) stays removed.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Overhead views were backface-culling property-facing skirt normals into
a thin silhouette; flip curb riser and outer gray skirts toward the hub.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Drop rectangular tip pads that reintroduced turn spikes. Trim arms at
full junctionRadius so outer edges stay G1 with the sidewalk arc, and
emit the curb-to-sidewalk riser plus outer gray skirt on each segment.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Cover the square curb/sidewalk stub left by jr-0.2 arm trim with tip
pads and close the open tip faces so turn corners lose the sharp spur
and the outer gray skirt no longer shows through.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Drop the sidewalk fan to (±jr,±jr) that made a sharp property-corner
spike, and emit a walk-height sidewalk vertical on the outer gray arc
so the skirt faces render instead of showing through.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Revert convex (ah,ah) arcs that flipped the curb returns again.
Keep concave corners with centers at (±jr,±jr), sidewalk disks toward
the property corner, plus exact trim tips, seal strips, and U-cap skip.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Full-profile end caps at the cross apron drew a dark tip bar that
read as a seam from above; the apron and tip pads already close the
opening.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Snap trim tips 20cm into the junction, add curb/sidewalk pads along
each arm tip face, and fill the shoulder between tip outers and the
arc so salmon gaps cannot show at the corner joints.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Outward-center (concave) returns left salmon seams at the corners.
Put circle centers back at asphaltHalf so the apron bulges convexly,
keep snapped trim endpoints plus tip seal strips, and retarget the
corner sidewalk test.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Uniform path samples skipped the true junctionRadius, leaving ~0.2m
salmon gaps. Snap loft endpoints to the trim distances and add thin
asphalt seal strips under each arm tip.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Orient apron and curb-return quads so geometric winding agrees with
the stored normal (object-space CCW). Drop the dual-winding hack that
left dark/flipped corner faces under lit shading.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Cap the leftover quarter-disk at each corner so the property-side
pad is solid instead of showing through to the ground tint.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Use corner centers at (asphaltHalf+R) so the asphalt edge is concave
and sidewalks wrap toward the property corner instead of bulging out.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Trim arms by the full junctionRadius so tips meet the fillet, build the
asphalt hub from simple rectangles plus quarter-disks, and emit both
face windings so Lavapipe keeps curb/sidewalk arc tops visible.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Trim the four arms past asphalt half-width so sidewalks no longer
stack at the hub, fill a filleted asphalt apron, and rebuild the
corners as quarter-circle curb/sidewalk returns.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Size the hub trim to driving-lane width so arms meet a square asphalt
apron without a gap. Add raised curb corner platforms and profile end
caps so jersey-barrier U-channels are not see-through at the hub.
Paint zebra stripes on every arm approach.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Piers now use a world-up orthonormal basis so columns stay vertical.
Axis-aligned crosses get a hub-fan square asphalt apron plus sidewalk
corner pads (single large strip-quads were dropping out under Lavapipe).
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Replace the all-in-one interchange demo with straight/curve/bridge/cross
scenes, fix junction baking to a degree-gated asphalt disc (no unsorted
fan), and let the example switch scenes with keys 1-4.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Prefer asphalt on horizontal loft strips so the driving surface is not
tagged as curb, and render each mesh group with Material.setTint plus
high-angle camera, red ground, and translucent water in the example.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Raise jersey-barrier profile defaults, add yellow center markings and
vertex colors, thicken nav overlays, and render each mesh group with
its own tint plus red ground/water and a high-angle camera.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Clamp nav arrow placement against non-finite/huge frame steps (seed 7 hang),
prefer same-lane turn links, fix the procedural-road example mesh upload path,
and cover seed-7 navigation termination in unit tests.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Stop multiplying fog by soft unlock (that made a muddy fade). Gate by
cloud cover instead so deep fog stays opaque cotton with valley peek-
through, and the unlock rim breaks into sparse islands. Cast puff
silhouette shadows from offset cover samples onto unlocked ground only,
and harden clearCore so the hole stays clean.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Hard clearCore from unwarped mask kills warp-pulled fog islands inside
the unlock hole. Shadow is rim-contact only (tiny offset) so soft
penumbra no longer paints a ghost of the hole onto the fog sheet.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Deep fog stays a dense lit cotton sheet. Across a wide soft unlock
band, hard-clear only deep inside the hole; the approach frontier
raises the cover gate so fog breaks from sheet → clumps → sparse
islands — without a global fogAlpha wash.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
User asked for partial luminous translucency (透亮) in soft valleys
between lit metaball puffs — not lowering fogAlpha / capping body
alpha, which muddied the whole sheet. Restore bright lit shading,
drive peek-through from height coverage alpha, keep fogAlpha high.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Drive coverage from puff luminance so valleys stay see-through, thin the
sheet toward the unlock rim, and keep peak alpha partial — closer to the
reference cotton FoW where terrain peeks between frontier blobs.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Match the reference FoW look: overlapping circular cotton blobs with
top-left lighting, bubbly unlock rim stamps, and a hole-cast shadow that
follows the puff silhouette instead of flat fBm wallpaper.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Reword the modifyPointBounds Doxygen note so the architecture POINTER_API
heuristic no longer treats the comment as a raw-pointer declaration, and
document borrow/lifetime for assignWeightedMeshAttribute's mesh/weight tables.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Wire sampleGridPoints and poissonDiskPoints into zero-input graph nodes
with origin offsets, validation, and point-budget checks so scripts no
longer need to leave the PointGraph for basic XZ sampling.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Close the deferred attribute gap from PCG node breadth: copy/rename/delete/
transfer, typed set/filter/compare/select, and a closed $Density-style
selector set for float channels—without UE multi-domain selector grammar.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
The mapping looked flat/skewed because rays were cast on the wrong side of
the facade, world directions were mixed with room-local origins, and
B/(B+d) UV crush / center mullions distorted the pre-projected atlas.
Use per-window object space (window at z=+1 into -Z), Joost far-hit slab
tests, bounded B/(B+d) sampling, outer sash only, and a matching
perspective atlas bake.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Replace slow runtime ImageData painting with a generated PNG atlas, and
lift the window wall so all rows clear the ground plane.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Replace the single left overlay panel with a Unity/Godot-style editor
layout (toolbar, outliner, embedded viewport, inspector, asset palette),
draw the transform gizmo, and route picks/camera through the viewport.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Drop heavy screen-blend that bleached lit cloud maps to flat white, keep
color-map structure via average+multiply, and draw the under-cloud shadow
inside the unlocked hole so the volume cue is actually visible.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
DevTool::attach(HSQUIRRELVM) enabled sq_notifyallexceptions, so with
break-on-error the error hook paused at the throw site before catch /
reportError ran. That left a second pause hanging after one DAP continue
and flaked as SEGFAULT on Linux CI teardown
(devtools.dap.caughtErrorPausesAtReportSite). Keep notify-all only on
Runtime-bound attach (hook already capture-only there) and force-resume
in the test if the script thread is still paused.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Source quality failed on undocumented setDepthOfField getters and on
api-lifetime for newLook/newMiniatureLook (and a Doxygen false positive).
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Lower cloud tiling/frequency so the sheet reads as soft dual-scroll
clouds instead of wallpaper noise, and stamp hard-core soft discs into
a hi-res mask so the starting unlock hole is contiguous with organic
edges under UV warp.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Rewrite the cloud generator for large seamless billows, retune the
shader toward a translucent dual-scroll sheet (not wallpaper noise or
swiss-cheese density), and stamp a soft hi-res mask in the example so
unlock holes read as cloudy edges instead of hard grid rectangles.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Satisfy api-lifetime architecture contracts on getCloudTexture,
getMaskTexture, and makeCloudTexture with @ownership/@lifetime tags.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Source quality requires every newly bound MapFog getter/setter to appear
in docs/usr/modules/graphics.md; fill the missing API names.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Graphics::print requires setFont; the fog demo only needs the overlay
and console usage hints, so remove the on-screen print calls.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Implement dual-scrolling cloud fog with RGBA mask bridge (R unlock,
G select blink, B dissolve) and a pre-pass shadow, plus example and
unit tests following the common SLG FoW presentation pattern.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Port the signature HD-2D miniature presentation from HD2DURP: Gaussian
depth-of-field on Camera3D/final HDR resolve, Hd2dLook presets, and
Sprite3D cutout depth-write controls so characters stay sharp in focus.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Face the Quaternius Superhero Female toward a fixed front 3/4 camera during
the auto capture pass, note the free-pack bald base mesh, and check in the
updated Lavapipe PNG sequence.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Load Superhero Female FullBody via model3d, sample albedo in the coverage
shader, and document the asset license under examples/venom-transform.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Exit via eve.bootBench so the Vulkan window is not destroyed mid-frame,
and check in the auto-demo PNG sequence as a visual reference.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Add SteerAvoidBody (front-cone shield bypass), CurveSway/CurveHelix
motion modifiers, and deterministic Fan/Ring spawnVolley so tracking,
multi-shot spreads, and curved flight compose on the same recipe.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Introduce CombatCarrierRuntime in the weapon module so ballistics
(motion ops), triggers, and attack impacts assemble as data recipes
instead of hardcoded projectile modes. Keeps ProjectileRuntime for
existing callers and bridges via carrierRecipeFromProjectile.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Eager binding contracts type-check enqueue duration as float. A
ternary of the form kind==\"tank\"?8.0:4.0 leaked that expected type
into the condition, so the string literal failed EVE2002 at load.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
The AI enqueued a new unit every second while living count lagged
behind the queue, then assaulted as soon as it tied Crown. Limit
in-flight work to factory slots, cap the army at four, and require
a numbers advantage after 15s before assault.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
choose() is deterministic, so a 0.60 assault score beat capture every
first tick and walked Frontier across the map. Gate assault on force
parity, garrison the east mine during raid, and picket Crown on the
bridge so the opening is an economic contest.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
`match` is a token in the Squirrel lexer, so a local of that name
failed to parse at load. Rename the nearest-point selector.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Owned OrderPayload.setNumber rejects a Squirrel float as the instance.
Use the same setJson path as the existing queue script test.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Check production/order Results, drive moves through Orders.replace,
stop Frontier from always assaulting, spawn enemy production, add
win/lose, and list the example in the catalog.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
OwnedOrderQueue documented append/replace/interrupt but only append was
exposed, so examples/commandery-rts threw on right-click move. Bind the
remaining CommandQueue mutations on the owned proxy and cover replace
from script.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Use the newest EVEngine/third-party commit (54725d0) as EVENGINE_THIRD_PARTY_PIN.
The tree matches the previous pin; this moves the documented aggregate onto
current main so configure verifies the latest checkout.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
PlacementWorld.cpp includes Poco JSON via JsonDocument.h, but the
building module did not declare THIRDPARTY poco, so those TUs compiled
without POCO_NO_AUTOMATIC_LIBS. MSVC then recorded a link of
PocoFoundationd.lib (the DLL debug name) instead of PocoFoundationmdd.lib.
Declare poco on building and apply the no-auto-link flags to every
native module, the host binary, and unit_test so a future JsonDocument
include cannot regress the Windows link.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Xray.cpp was the only suite that deleted Stylize after create(). The
pointer stays in ModuleManager, so the next case got a dangling
singleton and crashed on the second delete (xray.occludedSilhouette
after xray.shaderAndFlags). Other stylize tests never delete it.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
TileRenderSystem::collect walks the global ECS, so leftover TileLayer
entities from earlier cases made tilesContributeDepthY (and dual-grid
depth sort) see extra draw items. Hide other layers first, matching
the rest of the map suite.
drawMeshShader always runs inside an open 3D pass, so lazily calling
vkCreateGraphicsPipelines for the xray variant crashed Lavapipe.
Create that pipeline with the shader (and recreate it on MSAA/RP
change) instead, and skip the draw if it is still missing.
Also refresh module counts after rebasing onto grid / buildingfx.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Marks the architecture document as implemented, replaces the roadmap section
with what each step actually landed and the measured result, and regenerates
the module inventory against the post-change dependency graph (scene is L1 now,
gameplay modules no longer pull data, and each row names the first profile that
includes it).
Adds docs/usr/TRIMMING.md for the user-facing side: profiles, per-module
switches, how dependency closure and the configure-time conflict errors behave,
has_module() in scripts, what cannot be trimmed and why, and measured savings.
Linked from the user and developer indexes.
Headline numbers after S1-S6: dependency cycles 26 -> 0, layering back-edges
16 -> 3, JSON implementations 6 -> 1, modules using Poco 15 -> 9, boot scripts
2 -> 1, and any module trimmable on desktop where none were before.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
A scene link keeps an external object in step with the node it hangs off. The
kinds were a closed enum with a switch in TransformSystem, so scene had to
include graphics, physics and audio to do the casts, and no other module could
ever attach to the tree without editing SceneHost.h -- particles, voxel,
spritestack, avatar and weather all had to stay outside it.
Kinds are registered now (scene/SceneLink.h). The module owning the target type
supplies pushWorld / pullWorld / alive, keeps the casts on its own side where
the type is complete, and scene never learns what a Renderable3D is. Dispatch is
a function-pointer table rather than virtual calls, since link sync runs for
every dirty node every frame.
The six typed helpers (linkRenderable2D and friends) stay as conveniences and
now resolve their kind by name, so they return false rather than crash when the
module that registers it was trimmed out. The script API already named kinds
with strings, which is exactly the registry key, so it is unchanged.
Direction is now the right way round: graphics, physics and audio depend on
scene rather than scene on them, and scene drops from L5 to L1. What remains is
scene -> graphics from pickScreenAt / collectFrustumIdsAt, which take a Camera3D
and read its projection; that is recorded in the back-edge whitelist as the next
thing to move.
Each provider lives in a SceneLinks.cpp, sharing the basename so the three come
out of the build together when scene is disabled.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
load.nut constructed about thirty modules by name, so any build that trimmed
one crashed at bind time. That is the only reason the browser runtime needed a
second root script, load_web.nut, listing the WASM-surviving subset by hand:
two files to keep in step with the link list, and no way to express any other
subset.
The boot script now walks eve.moduleList, generated at configure time from the
same manifest that produces the link list, and guards optional modules with
has_module(). The two frame drivers share one eve_frame(): desktop runs the
while loop at the bottom of load.nut, the browser leaves it to
emscripten_set_main_loop through the new eve.hostDrivesFrames flag rather than
a separate script. load_web.nut is gone.
EVENGINE_WEBGPU_TRIM is gone as well. What was a special case is now the "web"
profile, and the two remaining uses that really meant "is this Emscripten" say
so directly. Third-party groups the WASM aggregate does not build resolve to
nothing there, matching the list it linked before.
graphics now treats font as an optional dependency rather than a hard one:
graphics/Font.cpp is its only user and was already excluded on WASM. Turning
font off excludes that file everywhere, so the rule no longer depends on the
platform.
Verified: full-profile link line still identical to before the manifest work;
web profile resolves to exactly the module set the old REMOVE_ITEM list left;
a 3d-profile binary boots and runs the basic example, reporting avatar and
dialogue absent and the rest present; example smoke suite unchanged at 19/9.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Which modules a build contains was spread over four places that had to be kept
in step by hand: the create_module() calls, the EVELIBS list, the per-platform
ThirdParty lists, and load.nut. Nothing tied them together, so the only trimming
that ever worked was the one hard-coded axis (Emscripten), and dropping a module
never dropped its libraries -- ThirdParty was a flat list unrelated to the
module set.
cmake/module_manifest.cmake now declares each module once with its dependencies,
third-party groups, script binding and profiles, and everything else is derived:
-DEVENGINE_PROFILE=minimal|2d|3d|full|web presets (default full)
-DEVENGINE_MODULE_<NAME>=ON|OFF per-module override, either casing
Dependencies close automatically, so enabling particles pulls in gpgpu,
animation and ik. Disabling something another enabled module needs is a
configure error naming both sides rather than a link failure. OPTIONAL_DEPS
covers 'integrate when present': each enabled module defines EVENGINE_HAS_<NAME>,
which is how scene picks up audio.
cmake/thirdparty_libs.cmake maps logical groups to per-platform link names and
emits them in EVE_TP_ORDER, since GNU ld needs dependents before providers.
The full profile is unchanged by construction: the generated link line is
identical to the previous one, same libraries in the same order and the same
object files. Trimmed builds work -- the 3d profile links and produces a 198 MB
debug binary against 233 MB for full, and -DEVENGINE_MODULE_DATABASE=OFF drops
PocoData and SQLite from the link.
DevTools becomes a declared module rather than a platform #ifdef, so it can be
switched off on desktop too. Its manifest DEPS record that McpServer and
SceneInspect still include scene / physics / procgen / particles / audio / ui
directly, so the resolver tells you to disable devtools before trimming those.
Step S5 of docs/dev/模块编排与裁剪架构.md. Boot scripts still name modules
directly, so a trimmed build links but needs S6 before it runs.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
The SDL pump did the translation itself, so it had to know about keyboard,
joystick, touch, window, graphics, audio and ui: eight upward dependencies from
one of the engine's lowest modules, and the source of every remaining
dependency cycle.
Each module now registers an IPlatformEventSink for the events it owns and the
pump only dispatches. Key and text events move to keyboard/sdl, joystick and
game-controller events (including the hotplug device table) to joystick/sdl,
finger events to touch/sdl, resize and the mobile background/foreground surface
watch to window/sdl, the ImGui observer to ui, and Audio::pump to an
end-of-pump hook in audio. The pump keeps only quit and window-close, which are
about the event loop rather than any one module.
Sinks run in priority order -- observer, then surface, then input -- so ImGui
still sees events first and the window is resized before anything reads its
size. The mobile surface teardown keeps using SDL_AddEventWatch rather than the
poll path, since by the time SDL_PollEvent returns the native surface is gone;
the watch is now installed by the window module on its first pump.
Also removes exceptionIfInRenderPass, whose body has been commented out since
it was written and whose only remaining effect was a graphics include.
The engine dependency graph now has zero cycles, down from 26, and the back-edge
whitelist is down to 2 (window -> graphics, window -> image). Layering is also
right way up: event sits at L0 with the input modules above it at L1/L2.
Verified: unit tests for event/input/ui/audio/thread pass, and the example
smoke suite gives the same 19 pass / 9 fail as the pre-change baseline (those 9
fail on main too, from script API drift in the examples themselves).
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
HotReload knew what lived at every watched path: it included graphics to
refresh textures, particles to reload emitter configs and map to reload tile
layers. That made the engine's lowest-level module depend on three of its
highest, and it was the only reason filesystem sat in a dependency cycle.
Each module now registers an eve::caps::IAssetReloader for the assets it owns
and HotReload only routes paths. Behaviour is unchanged: automatic dispatch
still matches by extension, an explicit bind() still targets one kind and
ignores the extension, and the texture reloader runs at kTexture priority so
the GPU upload happens before emitters and tile layers re-bind to it.
The reloadable set now follows the linked module set, so a build without
particles simply has no particle reloader rather than a dangling reference.
Reload kinds also become extensible: a module or plugin can add one without
touching filesystem.
Back-edge whitelist 14 -> 11; the dependency graph is now acyclic apart from
the event pump.
(map.render.tilesContributeDepthY fails when run after the hotreload cases both
before and after this change -- pre-existing test-order state, not from here.)
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Introduces eve::cap in common/Capability.h: a name-keyed registry where the
consumer owns the interface, the provider registers an implementation, and
neither includes the other. It generalises what common/RenderTrace.h already
does for the render tracer, and supports both a single provider (provide/query)
and many ordered ones (addListener/forEach), keyed by string so a provider
compiled into a plugin lands in the same slot as the host.
Two upward dependencies go away:
system -> graphics IGpuInfo. The Vulkan physical-device fields move into
graphics/vulkan/GpuInfoProvider.cpp, with a WebGPU
counterpart, so System.cpp loses both the graphics
include and its EVENGINE_WEBGPU branches.
thread -> event IMainThreadPost. postMain and submitPost now enqueue
through the capability. The interface makes explicit
what was previously only a comment in submitPost: the
submitting thread calls prepare() so the worker never
reaches the module registry.
Both now report an error when no provider is linked, rather than lazily
creating a module the build may not contain.
Step S3 of docs/dev/模块编排与裁剪架构.md; back-edge whitelist 16 -> 14.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
I18n.cpp carried the original copy of the recursive-descent parser that
common/Json.h now hosts. Drop the 228 local lines and flatten the parsed tree
through eve::json::Value instead.
Locale flattening keeps its behaviour: nested keys join with dots, an object
whose members are all plural categories becomes a plural table, and scalars
stringify. Arrays and nulls were already skipped and still are, now stated
directly rather than implied by the if/else chain.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
rpg, inventory and building each carried a byte-identical JsonHelpers.h (only
the namespace differed), card and voxel inlined a fourth and fifth copy, and
i18n hand-rolled a sixth parser because it needs to build without Poco.
Replace all of them with eve::json in common/Json.h. The backend is i18n's
recursive-descent parser, promoted and extended to track integral literals so
getInt() stays exact; picking that over Poco keeps EVCommon dependency-free and
drops Poco from six gameplay modules outright (15 modules -> 9, 136 include
sites -> 108), which is what lets those modules be trimmed independently later.
Accessors keep the lenient, never-throwing behaviour the per-module helpers
had: a missing key, wrong type or bad index yields the fallback. Two places
that relied on Poco throwing to reject incomplete input (housegen instance and
room records) now check required fields explicitly.
test/json.cpp covers the parser directly -- scalars, lenient conversion,
integer exactness and range, nesting, escapes, surrogate pairs, malformed
input and empty containers.
This is step S2 of docs/dev/模块编排与裁剪架构.md.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Runs scripts/module_depgraph.py --check on every push and PR. It fails when a
module gains an #include pointing up the layering, outside the 16 back-edges
already whitelisted in the script. No build or toolchain needed, so it reports
before the platform jobs finish.
This is step S1 of docs/dev/模块编排与裁剪架构.md.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Count by module directory (51) throughout, and state the directory-vs-script-
class discrepancy up front: filesystem also exposes HotReload, Cmdline lives in
engine/cmdline, and data/tensor bind under different class names.
Also align the layer diagram with the script's computed depths, add math and
audio to the functional-domain table, and correct the figures that were
estimated during drafting (97 soft lookups, 202 cross-module includes,
136 Poco include sites of which 79 are JSON).
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Analyse how the 53 modules currently collaborate and why none of them can be
trimmed outside the hardcoded WASM axis, then lay out a target architecture and
a six-step route to per-module build options.
Adds scripts/module_depgraph.py, which produces the dependency graph, the
7-layer topological ordering and the cycle list the document cites. Its --check
mode fails on any back-edge outside the 16 known ones, so it doubles as the CI
guardrail for step S1.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Load the four grass and two leaf masks from test/Texture instead of
painting a procedural strip. Pack them into one 2x2-per-variant atlas,
sample frames by instance id, and tint with the existing two-tone green.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
0.48s at 0.12s/frame is exactly 4 frames and can land on the same atlas
index after modulo. Use 0.36s (3 frames) so the CHECK is stable.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
zeroerr Expression copies the compared value, which is illegal for
std::unique_ptr. Compare raw pointers instead.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Bake alwaysDark into billboard normals so dense and sparse tufts can share
one mesh shader in the 3D pass, then add a windowed GPU test that draws a
field with a shadow-casting occluder and writes grass_field.png.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Clang rejects `BakeParams params = {}` on GrassField while the nested
struct still has in-class initializers. Callers pass BakeParams explicitly.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>