Files
llamamod/notes/editor-tools-objects.md
T

10 KiB
Raw Blame History

Level editor – objects, scripts, paths, cameras (editor.tools.objects)

Plugin ObjectsEditorPlugin (phase 3, discovered automatically). Parameter decoding and the strat VM: notes/editor-object-schemas.md. Tests: ObjectToolsTest (needs -Dllamamod.cd), screenshot tour ObjectsTour (test classes).

camera zone

What it adds

Part Content
Objects panel (left dock) every placeable type of the base with rendered thumbnail, category filter, search (name + schema summary), favourites (right-click – it never selects or switches to the Place tool, nor does the click that closes the menu; ★ filter), "parameters decoded" marker; drag into the viewport or click → Place tool. Quick setups: Player start, Checkpoint, Exit, Secret, Coin line, Coin arc
Place tool (P) click = place on the collision floor under the cursor (snap to floor, grid snap), yaw = camera direction / facing the camera / 0° / type default; click + drag an object = move along the ground (its waypoints move along); drag the yellow knob = rotate (angle snap; a checkpoint's respawn node turns with it). Modes for the setups
Setups Player start moves the existing player (exactly one) or places a Llama with one start camera node 2 cells behind (moving keeps door nodes, carries the near nodes and the village fly-by trigger). Checkpoint = CheckPointPost + respawn node 0.4 ahead (floor height). Exit = LevelDoor in the cell centre + 1×1 FLOOR brush with collision material 16; target picked in the options bar (world/chapter names, "world finished 7,7,7"). Secret = Secret with a 3×3 box (2 nodes). Guards, alligators and spawners get one 4×4 box (and guards event bit 0) on every way of adding an object (Edits.placeStrat: Place tool, drag from Objects panel / Assets, double-click)
Coin tool (O) Line: two clicks, coins every spacing; Arc: centre + point on the circle, count coins over arc°; Coin/Coin5, height above floor, follow floor; live preview
Waypoint tool (N) select an object (or node): click = add node after the selected node / at the chain end (creates the chain if missing), Ctrl+click = insert before, drag = move (keeps height above floor), Backspace/Del = remove and relink; Reverse; orient new nodes along the path
Zones & triggers (J) handles: 4 corners of box zones (node pairs: Secret, CameraSide/Lift, ObjectDontDropInBox, FallOffNoHurt …), radius knob for RADIUS parameters (CutSceneTrigger, guards, CameraFocusPoint)
Inspector "Object parameters" named, typed fields (check boxes, choices, counts, seconds, distances) with doc/range/original-value tooltips, raw hex, inline validation, "Reset to defaults"; LevelDoor target picker with "Leads to: …"; waypoint row (role, node count, Create/Edit path, Unlink, Delete path, Link… to an existing chain, Look through). Undo-aware refresh
Inspector "Waypoint chain" node i of n, owner and role, ◀ ▶, select object, delete node, look through
Viewport layers Path directions (arrows, dashed wrap segment for patrol paths, node yaw ticks), Zone areas & trigger radii (boxes for all zone objects, fills for the selection), Camera frusta (CameraSide/Lift: computed game camera from height/distance/node yaw; cut-scene cameras: a frustum per node from node yaw/pitch)
Look through camera (Ctrl+Shift+L, View → Camera) viewport takes the camera of the selected node / cut-scene camera / camera zone; while active, flying writes back node position + yaw/pitch, or for CameraSide the height/distance params and node yaw (one undo step per pilot session)
Problems (Level → Check, Build) guards/alligators/spawners the game would remove (no start box / odd node count), alligators outside their boxes, spawners facing away from their first box, guards waiting for an event bit (and whether any object in the level sets it), a start camera inside the llama, chains not stored contiguously (error, Tools → Repair waypoint chains), param count, out-of-range values, missing required waypoints / odd box pairs, types whose originals always have a chain, LevelDoor without material-16 floor in its cell, impossible exit targets and (7,7,7) in TestLevel, far respawn nodes, several player starts
Copy / paste between levels Edit → Copy objects (Ctrl+Shift+C) puts JSON (objects + chains + brushes, relative to their centre) on the system clipboard; Paste objects (Ctrl+Shift+V) at the view centre in any level – types are matched by name/variant in the target base (unknown types skipped with a message)
Prefabs Tools → Save selection as prefab… / asset browser tab "Prefabs": <data>/editor/prefabs/<name>.json + thumbnail; double-click = place at view centre, drag = place under the cursor
Delete edit.delete is re-registered: a selection of waypoints is removed with the chain relinked

Engine fact used throughout: the MAP loader links waypoint record i to i+1 when "next" ≠ 0, so a chain must be contiguous in the node list (ChainOps inserts at the right index and the check / repair action guard it).

Files

ObjectsEditorPlugin (registration, actions, waypoint inspector), Schemas/ParamSchema/ TypeStats (+ type-stats.tsv), ParamsSection, ObjectChecks, Guards, EventBits, PlaceTool, Setups, ExitTarget, CoinTool, PathTool, ChainOps, ZoneTool, ObjectOverlays, CameraView (zone camera + pilot), ObjectPalette, ObjectClipboard, Prefabs, LinkDialog, Ground (floor finder on the collision polygons of tiles + brush preview tiles), Session, Roles, Draw (all game↔render conversions in one place).

Shared changes: editor.ui.view.SceneRenderer.brushOutput() getter (brush preview tiles for the floor finder); editor.model.WaypointBoxes + box setup in Edits.placeStrat; editor.model.cmd.PlayerStart (also used by the shell's new-level templates); editor.ui.TypeMenus (object type context menu, used by Assets → Objects and the Objects panel; the objects plugin adds Edit type… / Delete type… for custom types through editor.tools.strats.CustomTypes).

Verified

UI (Xvfb, ObjectsTour): img/editor/obj_camera_zone.jpg, obj_cutscene_frusta.jpg, obj_pilot.jpg, obj_exit_inspector.jpg, obj_place.jpg, obj_zone_handles.jpg, obj_trigger_radius.jpg, obj_problems.jpg, obj_newlevel_path.jpg, obj_newlevel_camera.jpg, obj_coin_arc.jpg, obj_newlevel_saved.jpg (no problems), obj_beetle_path.jpg.

In game (apptest, display :7, new level on base t1l1m002 as TestLevel chapter 2; island of brushes, coin line + coin arc, checkpoint, exit to Village chapter 2, CameraSide zone at the exit, JumpingBeetleBlue with a 4-node patrol path, CityGuard with two boxes):

  • level loads, coins of line and arc stand where placed (obj_game_coins.jpg);

  • walking through the checkpoint shows "KONTROLLPUNKT"; falling into the sea respawns the llama at the post (obj_game_checkpoint.jpg);

  • entering the camera zone switches to the zone camera (high view, obj_game_camera_zone.jpg);

  • stepping on the exit floor shows the tally "TestLevel Kapitel 2"; Enter → "Dorf Kapitel 2" loads = the chosen chapter (obj_game_exit.jpg);

  • the beetle jumps back and forth along its path (obj_game_patrol.jpg);

  • (2026-11-07, display :25) a CityGuard placed with the Place tool (one box) appears and attacks the llama (obj_game_guard.jpg); one with a square path beside it never appears (editor: obj_guard_removed.jpg). Village 1 with the door tile swapped open: start on the pad 42.5/3.5/49.37 → tally "Dorf Kapitel 1" at once (obj_game_village_door.jpg); at the door's own position 42.5/3.5/49.8 or in the original (door closed) → nothing.

  • (2026-11-07, objs2, display :25, TestLevel on village 2 / village 1 / t1l4m002): old player setup on village 2 = camera in the llama's head until it moves, new setup = camera behind it from the start (obj_game_startcam_v2.jpg); a CityGuard added through the Add-object path walks in its box; an Alligator added the same way appears and snaps (obj_game_alligator.jpg); original village 1 with the start moved and turned (240°): the fly-by plays at the new start and ends behind the llama (obj_game_village1_moved_start.jpg). Editor: type menu in Assets → Objects / Objects panel (obj_type_menu.jpg, obj_palette_type_menu.jpg), event-bit info (obj_event_bit_info.jpg, obj_guard_event_inspector.jpg).

Known limits

  • Parameters are decoded for ~35 common types (confidence per type in the schema doc); the rest shows raw values with the statistics of the originals.
  • Solved 2026-11-07: the CityGuard "not showing up" was removed by its own script – guards need their start inside a waypoint box (node pairs), the tour had given it a 4-node square path (editor-object-schemas.md "Guards"). The exit check "no material 16 in the door cell" in originals came from the door floor being in the tile's swap model (RubyIdolDoor & co.); the pad at 43,48 next to the village door is a house entrance. Tile cells follow the engine's loader exactly (Tile.cellX/cellZ = ftol(x − 0.5), −ftol(z + 0.5)); ObjectChecks tests the door cell like the engine (tiles listed in the cell, any height, swap models), same as GeometryChecks. Tests: GuardsTest, OriginalExitsTest, OriginalStartsTest.
  • Snap-to-floor (Ground) follows the engine's floor test (FUN_004036d0, used for strats too): only tiles listed in the point's cell; then their swap models; a neighbour tile's polygon only where the cell has no floor at all (Hit.source). cellBelow is the strict engine test (own cell, death floors included) that the play-test FloorFinder and boot-to-level's crash check use (one implementation since 2026-11-07). GroundTest compares the fallbacks with it on three originals. The Place tool drag moves only a player start's nodes within 2.5 cells.
  • Zone heights are estimated (+1.2 above the lower node); the engine tests x/z only.
  • Camera preview of CameraSide assumes the player in the box centre and default distance 2 / height 1 when the parameters are 0; the game's FOV is approximated by 60°.
  • Look-through of the village cut-scene camera's first node looks into a wall (its first node may be a fly-in start); not compared with the game.
  • Pasting into another base matches types by name; object models/code are not imported (that is the job of editor.tools.catalog).