Commit graph

384 commits

Author SHA1 Message Date
d3911d4ba8 ludic.compass: the marks' pools made with the state (512), compass_at's empty mark kept; ludic.base imap_clear in place; ludic.things' kept lists through kept_push; ludic.net's once-per-room and STUN log lines declared
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:22:48 +03:00
8dfcccad41 Merge branch 'lang/ecs' into lang/final2 2026-09-28 16:13:17 +03:00
4b533b5ff6 ludic.shop, ludic.net: nothing made per tick - the week's lists and dice reused, the net's facts from a ring, the room's watch address made once, pools and kept lists through kept_push; what runs once per host, join, room or guest says so in @alloc_ok
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:09:32 +03:00
0e2d2a6fab fix(ludic.wildlife): a newcomer takes the record of one of its species removed for good - its row, its key and so the game's drawing, every other field as new
Each morning's repopulation made a new WildAnimal (and the game a new drawing, actor and skeleton,
keyed by an ever-rising key) for every animal that had gone. A legend's record is never taken, nor
one still in a crowd. reuse_test: a hundred removes and makes are one record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:08:23 +03:00
2bed060d13 Merge branch 'lang/allocs-physics' into lang/foundations 2026-09-28 16:04:11 +03:00
14140e26cd Merge branch 'r3d/skin-own' into lang/foundations 2026-09-28 16:04:00 +03:00
34664e867f frame allocs (25.2): physics, npc, vehicles and wildlife's bounded growth declared - id tables to their most, a walker slot, a guest's copies, a player's own vehicle, a table at a load
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:02:42 +03:00
082fd26bf1 frame allocs (25.2): a fact record past the 64 made at the start is @alloc_ok, in its own function, in npc, character, physics, vehicles and wildlife
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:02:42 +03:00
c8c230449e fix(character, physics, vehicles, wildlife): fact records made at the start (64) with a free list of room for all, as ludic.npc's
A frame holding a new peak of facts made a record and grew the free list; now nothing is made until
64 are held at once. The two record-count tests hold the 64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:02:42 +03:00
7f973f9a4f fix(ludic.physics): buoyant bodies in a table made with the state (256), a sink taking the last row - floating and sinking push nothing
ludic deps --allocs (25.2) found phys_float's five pushes per drop reaching the water and
phys_sink's filtered copies per removal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:02:42 +03:00
58f0dbbc84 fix(ludic.npc): a name picked and a name let go build nothing - the body's names counted in place, the last eight who left in a ring made with the state
ludic deps --allocs (25.2) found npc_pick_name making a list of the body's names at every spawn and
np_left making a new list of the recent names at every retire.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:02:42 +03:00
f4e121ae94 render3d: actor_own_skin / skin_clone_free, and a frame's scratch and tables made with the device
actor_own_skin(a) gives an actor its own clone of its model's skeleton and actor_release frees it
(skin_clone_free: the pose, matrices, views and scratch the clone made; the rest data stays its
source's). gvk_startup_state, at the end of gvk_init, makes the scratch and tables a draw used to
make on first need (gvk_tmp_buf, the pipeline fast cache, the set key and per-program uniform
offsets pre-sized to 4096 programs, skip/seen/size words, spare and retired lists, the grass cull's
words), and those frame paths no longer start them. Compiled (steady).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:02:21 +03:00
f5834f8f63 Merge lang/foundations dec64e8 into lang/ecs 2026-09-28 16:01:40 +03:00
eb25f24c96 ludic.base: the growth paths push through kept_push, whose statement-level @alloc_ok says the bound
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:01:28 +03:00
3f32bfda7c ludic.wildlife: the table a guest draws the host's animals into is made once and emptied per join, not new each time
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:00:18 +03:00
07a6c35470 ludic.things: things_reserve sizes the rows, grid, kind index and uid map (tb_reserve, imap_reserve)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:59:41 +03:00
5d0f83b81c render3d: 671 frame-reachable allocation sites to 161 - declared, split, or made nothing
@alloc_ok with its reason on what is made once per resource and kept (textures, programs, samplers,
views, layouts, memory blocks, the pipeline cache in gvk_pipe_build), on resize and swapchain
remakes, on screenshots and dumps, on a world being set up (streams, layers, water, post, bakes), on
loads (gltf_load, skin_load, tex_load*, png_decode, fonts) and on R3D_PROF / drawstats.
gltf_cached's hit path is its own and makes nothing; the miss (gltf_cached_load) is declared.
m4_look_at (now over m4_look_at_xyz) and m4_inverse work on scalars, and cam_update makes no scratch.
Left: lazy first-use starts, error and debug prints, and scratch made and freed each call (churn,
plan 25.3). Compiled (steady, and ludic deps over the game).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:58:18 +03:00
2d1d06899e ludic.base: tb_reserve and imap_reserve size a table up front; HandlePool (a slot and a generation, nothing made after hd_pool_new, past its capacity a panic naming it); kept_push is the one declared grow, and every growth path left says its bound in @alloc_ok
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:58:11 +03:00
f2dd27f443 Merge branch 'r3d/vk-alloc' into lang/foundations 2026-09-28 15:52:51 +03:00
03a8ee443d render3d: the pipeline cache grows in gvk_pipe_build alone
gvk_pipeline_fast's miss (the build and the six cache pushes) is its own function, so the fence can
declare it: @alloc_ok("pipeline cache: one per variant the game draws") once lang/memory-fence's
compiler is merged (the annotation is not known on this base). Compiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:51:06 +03:00
a52fbc01a9 Merge branch 'lang/jolt-heap' into lang/foundations 2026-09-28 15:50:54 +03:00
e9de2b6f27 feat(ludic.physics): Jolt's heap counted in the shim (plan 25) - jph_heap_bytes/peak/allocs, phys_heap_bytes/peak/allocs
Jolt's Allocate/Reallocate/Free/AlignedAllocate/AlignedFree go to libc's malloc with the size in a
16-byte header, and atomic counters keep live bytes, the peak and the blocks asked for (its job
threads allocate too). The fence reads the three exports extern_weak to judge Jolt by its plateau.
jolt_heap_test: a ground in and out 1100 times holds 46,482,514 bytes after the first 100 and after
all of them, the peak does not move, and a closed world gives back every byte it took. The macOS
library is rebuilt; the Windows DLL still has to be rebuilt on the PC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:49:38 +03:00
f8358d117a Merge branch 'lang/npc-pool' into lang/leaks2 2026-09-28 15:49:07 +03:00
9ca357e109 Merge branch 'lang/ecs' into lang/leaks2 2026-09-28 15:47:08 +03:00
467c3f1bdd Merge branch 'r3d/vk-alloc' into lang/leaks2 2026-09-28 15:47:08 +03:00
665b689410 ludic.inventory: a change's record comes from a ring made once (512), not new per change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:46:31 +03:00
df6ea046c3 render3d: VkAllocationCallbacks counted (R3D_ALLOC_VK), pipeline create infos freed, actor pool at init
Plan 25.1c: vk_mac.ll's @lvk_ac (posix_memalign under a 16-byte header of scope/offset/size, atomic
counters) passed at every render3d create/destroy (49 sites; the caps probe keeps its own null pair);
lvk_ac_bytes/_peak/_allocs/_scope_bytes for the fence, Vk.alloc_bytes. vk_win.ll: null and 0.
MoltenVK 1.4.2 counted 0 live bytes through them in steady. Fence findings: gvk_pipeline freed its 17
create infos (and reuses one bufs list); actor_init fills ac_spare with 512 records (actor_fresh,
m4_new, v3_new at first placement in play). Compiled, not run (the user's call).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:46:19 +03:00
7fdd6582be fix(ludic.npc): the facts' records and the queue's lists made at their size at the start (64), so a frame with a new peak of facts makes nothing
The fence found np_fact_record making a record in five frames of every scenario: the pool grew to
each new peak of facts held at once, and q_unheld's free list and the queue's two lists grew with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:46:11 +03:00
21b828fe5c Merge branch 'lang/ecs' into lang/leaks2 2026-09-28 15:45:28 +03:00
1cf132cb87 Merge branch 'lang/telemetry-ring' into lang/leaks2 2026-09-28 15:42:59 +03:00
045ab0cdf6 ludic.save save_write_tree: a tree straight to disk through Json.write_file, the backup and read-back kept; ludic.telemetry writes its id file the same way
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:42:59 +03:00
ae044685e3 Merge branch 'lang/ecs' into lang/leaks2 2026-09-28 15:33:18 +03:00
6cdef20cc2 ludic.ui: an unmounted component is mounted again rather than made again - its record renewed (a generated renew), its props and model kept; an action's call answers into a ring
A prompt that comes and goes as a player walks (co-op's netleak: in_get, cmp_*_new, bd_class, value_slot/put)
made a new record, props and model on every mount, and an action's call answered into a new Val (ev_call_with).
examples/library/ui_remount: two thousand comings and goings hold the heap at 0, and the counter starts at 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:25:55 +03:00
f74738a4e0 ludic.telemetry: telemetry_str_open - a named string property the caller writes into the kept buffer (a look's numbers)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:22:26 +03:00
78a70765af feat(ludic.telemetry): objects and lists inside an event's properties, an item made of numbers, and a signature of what was written - all in the kept buffer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:17:20 +03:00
d1bea7f10e fix(ludic.telemetry): nothing made per event - properties and the line written into kept buffers, the queue a ring of bytes made at the start
An event was a tree of values encoded into a new string, a dropped line was never given back, and
every batch and save joined the queue into another. Now: telemetry_props / telemetry_str / _int /
_bool write the properties as JSON into a buffer the state keeps; the line is written beside it,
its time worked out from the clock's seconds (TelemetryWorld.clock_s, was stamp); its bytes go
into one ring (ring_bytes, at most queue_max lines), the oldest overwritten past either; a batch
and the file are written into a third kept buffer and go as bytes (TelemetryTransport.send takes
the bytes and their length; Http.body_bytes, Fs.write_bytes). The facts are pooled.
tests/ring_test: ten thousand events past the cap in lines and in bytes, 0 bytes of heap; the line
exact JSON, escaped, 2000-02-29 right; the batch puts the id in; the file round-trips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:15:12 +03:00
ae5df73e72 ludic.jobs jobs_posted_count, ludic.steps steps_my_shares_into - a count and a kept list for what a party asks every tick
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:12:24 +03:00
fc0f3d3790 Merge branch 'r3d/prime-fix2' into lang/leaks2 2026-09-28 14:24:42 +03:00
c736fd3b09 render3d: buffer primes in a command buffer of their own, submitted at once
A co-op guest loading its models segfaulted in copyBufferToBuffer under vkQueueSubmit (0x68, AGX
LegacyBlitContext): a buffer primed into the frame's command buffer was released later in that
frame, and gvk_buf_release destroys a buffer no draw has marked, so the copy read a freed one. The
copies now run in their own command buffer before the frame's begins, checked against the slot's
handle as they are recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:20:00 +03:00
62a703974d test(ludic.nav): an index loaded again twenty times, its tiles in each time, holds the heap (0 bytes), the open files and the tiles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:09:00 +03:00
364888bcc9 fix(ludic.physics): a hull owns its box, so a boat called and sent away takes its shape with it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:59:25 +03:00
5cd53d4024 feat(ludic.physics): phys_own - a body owns a shape made for it alone, and phys_remove frees it with the body
A chunk's trunks and boulders put in and taken out made a new shape each time and freed none. The
table is by the body's index, made once at the world's size. tests/reuse_test: 1000 owned bodies put
and removed hold no more shapes and 32 bytes of heap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:59:25 +03:00
404ee2ee3b Merge branch 'lang/ecs' into lang/leaks2 2026-09-28 13:46:18 +03:00
f8fe157352 Merge branch 'r3d/no-cmd-pool' into lang/leaks2 2026-09-28 13:41:23 +03:00
61a6f3c827 ludic.base: TextRing - a fixed ring of text buffers written in place, for a line made per event
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:35:34 +03:00
0141f99dd1 Os.platform/arch uname once; render3d primes a new buffer's Metal buffer
lp_os_platform and lp_os_arch malloc'd 8 KB per call (the uname buffer) and kept none of it:
string_temps now asks both every round, 327 MB over 20,000 before, 0 after. Reseeded. render3d:
MoltenVK made a mapped buffer's MTLBuffer at its first bind (fn_gvk_draw +4 blocks in the boat
window); gvk_buf_reserve queues it and the next frame's command buffer copies 4 bytes out of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:34:45 +03:00
67474a5cfe Merge branch 'lang/play-leaks' into lang/leaks2 2026-09-28 13:33:48 +03:00
7e9fa4473c render3d: a stream's cache is made with the stream - records and an arena - and evicts in place
stream_update made a Chunk and a words copy per new chunk (fn_stream_update +39 blocks / 13.2 KB a
window with the hiker in the drifting boat). The pool holds STREAM_MAX_CHUNKS records; the arena
is twice the layer's cap; eviction compacts it; a chunk that cannot be kept is gathered from the
scratch. stream_clear_all frees records, lists and streams. steady: 300 new cells, cap 256: 156 KB
before, 0 / -4.9 KB after, and every kept chunk's data checked against its cell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:26:59 +03:00
ca69a3f9ae ludic.net: a message's record, bytes and lists kept - queued ones back to a pool once sent or taken, the inbox's two drains on, a read text interned
np_queue made a NetMsg and a buffer per message, every flush a new keep list, and every message
that came in a NetMessage and a buffer; nr_text a new string per text read. A party plays at
dozens a second, so all of it is kept now: a pool of MTU-sized records for the queue (a peer's two
lists swapped by the flush), the inbox's records in two halves swapped when a message finds the
inbox empty, net_written's one record, a relay hello's and a STUN request's bytes in one scratch
buffer, and the texts read out interned. Tests: 6000 messages with the heap flat (Os.heap_bytes),
and an inbox record that holds still across a drain and comes back two drains on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:25:46 +03:00
317d63d822 fix(ludic.jobs): fact records pooled (the ludic.wildlife idiom) - a record per deed that moved a job was never given back
tests: 200 jobs taken and given up make 2 records.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:17:55 +03:00