# SkyCraft notes (for the Fabric kit)

How SkyCraft 0.1.2 actually works, read from its code (`third_party/skycraft`, commit `bfcaf17`)
on 2026-10-03, and what that means for Fusion. Its `docs/DESIGN.md` is a v0.1 draft and is
**out of date in one big way: rendering** (see §4).

## 1. The two halves

| Side | What it does |
|---|---|
| **Skyrim** (SKSE plugin, C++) | Creates the shared memory `Local\SkyCraft_v1` (~196 MB). Streams collision, NPCs, water and input to Minecraft. Draws *everything* on screen, including Minecraft's blocks and body. |
| **Minecraft** (Fabric mod, Java, `dev.skycraft`) | Runs a hidden "mirror world" (a void world). The player's physics, inventory, combat and blocks are vanilla Minecraft. Sends the player state, events, geometry to draw and the hand/HUD picture. |

`tools/fake_skyrim.py` plays the Skyrim side for testing. It streams a flat floor and stairs, holds W and Space, prints the player state, and saves the overlay to a PNG. **Fusion can act as the "Skyrim" side the same way.**

## 2. Shared memory (protocol v11, `protocol/skycraft_protocol.h`, mirrored in `link/Proto.java`)

| Region | Direction | How | Notes |
|---|---|---|---|
| Header @0x0 | both | plain | magic `SKYC`, version, both pids, heartbeats (GetTickCount64 per frame) |
| `SkyState` @0x100 | host → MC | seqlock | in-game/menu/loading flags, world id, **collision epoch**, teleport request, viewport size, game hour |
| `McState` @0x200 | MC → host | seqlock | feet + **eye position**, yaw/pitch, **vertical FOV**, view-bob, raw 20 Hz tick positions + QPC time for interpolation, camera mode (F5) and distance |
| `WaterGrid` @0x400 | host → MC | seqlock | 16×16 water surface heights around the player |
| Input ring @0x1000 | host → MC | SPSC ring, 4096 × 16 B | key/mouse/cursor events replayed into Minecraft |
| Actor table @0x12000 | host → MC | table | nearby NPCs: id, position, box, health fraction, flags |
| Event ring @0x17000 | MC → host | ring | hits on NPCs (damage, crit, weapon), use, etc. |
| World entities @0x1C000 | MC → host | table | arrows, items and so on |
| Collision ring @0x20000 | host → MC | byte ring, 32 MB | `ColClear(epoch)`, `ColTris` (exact triangles), `ColRegion` (8×8×8 sub-voxel mask per block); each region **replaces** all collision in its box |
| Overlay pixels | MC → host | triple buffer, 3 × 4K RGBA | hand + HUD + open screens on a transparent background |
| Render ring | MC → host | byte ring, 64 MB | meshes, atlas, textures, avatar triangles, lights (§4) |

It's the same ideas as Fusion's protocol (seqlocks, SPSC rings, heartbeats) with different
layouts. Coordinates are **Minecraft space**: blocks, Y up, Z south. That's right-handed with
1 block ≈ 1 m, so **it maps to Fusion units (meters, Y-up, right-handed) without conversion**.

## 3. Player, camera, input

- **Minecraft is authoritative** for the player: physics, health, inventory.
  - `McState` carries the interpolated eye position, yaw, pitch, FOV and bob, and Skyrim's camera copies it.
  - For Fusion this is exactly **possessing `minecraft.player`** (1.6): Godot's camera follows `McState`.
- **Frame pacing:** `SkyClient.paceFrame()` locks Minecraft to the host's frame rate. `FramerateLimitTrackerMixin` stops Minecraft throttling itself, which also covers the `inactivityFpsLimit` issue from 1.1.
- **Hidden window and focus:** `WindowMixin` makes Minecraft think it has focus, and `InputConstantsMixin` takes the keyboard state from the host. `-Dskycraft.startHidden=true` keeps the window hidden from the start. `ScreenMixin` keeps the world running while a Minecraft screen is open.
- **Input:** the host owns the OS focus and forwards raw keys and mouse through the input ring. `InputBridge` replays them into Minecraft's own handlers and keeps a virtual keyboard.

## 4. Rendering: geometry, not pictures (differs from DESIGN.md §9)

**Minecraft draws nothing of its world while linked** (`LevelRendererMixin`). Instead:

1. **World and avatar as geometry.** `WorldExporter` builds block and fluid meshes with Minecraft's own block renderer (models, tint, smooth lighting) per 16³ section, re-meshed on change through `LevelExtractorMixin`.
   - `SkyAtlas` sends the block + item atlas as one RGBA image.
   - `AvatarExporter` captures Minecraft's entity and particle rendering as posed triangles: the player's body in third person, mobs, items, arrows.
   - `BlockLightColors` gives emissive blocks a light color.
   - Skyrim draws all of it in its own frame, lit by its sun, shadows and fog, and depth-tested for free.
2. **Hand + HUD + screens as a picture.** `FrameExporter` copies Minecraft's main render target back from the GPU to the CPU (async, 3 staging buffers, about 1 frame late) into the overlay triple buffer. **There is no GPU texture sharing anywhere.**

Minecraft 26.3 has a graphics backend setting (`preferredGraphicsBackend`; default = OpenGL 3.3 on this PC) and a new render API (`com.mojang.renderpearl`). A Vulkan backend, if there is one, would make GPU sharing simpler later.

## 5. Collision (Skyrim → Minecraft)

- **Exact triangles** (`ColTri`: 9 floats + flags such as stair-ramp, diggable + material, terrain).
  - `TriCollider` collides the local player smoothly against them after vanilla's block collision (`EntityCollideMixin`).
  - `SkyRay`/`SkyClip` make arrows, the crosshair and placement hit them.
- **8×8×8 sub-voxel masks** per block (`ColBlock`) are merged into vanilla block-collision queries (`BlockCollisionsMixin`), so step-up, on-ground and fall damage are vanilla.
- A region message replaces everything inside its box, and an epoch bump clears everything. That's the same model as Fusion's planned collision chunks (§3.5), so **Fusion's hub can feed this directly**.
- About 20 small mixins make the rest of Minecraft accept that "Skyrim ground" isn't blocks:
  - torches on terrain, crouching at edges, pressure plates, falling sand, fluids;
  - explosions and digging (`SkyDig`, `SkyDigBlast`).

  All of it is generic, not Skyrim-specific.
- Tests: `SkyRayTest` and `TriColliderTest` (21 tests, all passing in our build).

## 6. NPCs and combat

- Every host NPC near the player gets an invisible `SkyrimActorEntity`, a real `LivingEntity` stand-in. All of vanilla Minecraft's weapons hit it.
  - Damage is collected once per tick and sent as an event; the stand-in's own health never drops.
  - `ProxySync` puts the client copies exactly where the host has the NPCs each frame.
- Host → Minecraft hits use custom damage types, and Minecraft's armor and shields apply.
- Damage scaling (DESIGN §13): Minecraft → Skyrim × (5 + 0.25 × level), Skyrim → Minecraft ÷ 5. **Fusion's units (`health_max`) replace these hand-tuned formulas.**

## 7. What it means for Fusion's Fabric kit (step 1.3)

**Reusable almost as-is** (generic, not Skyrim-specific):
- the mirror world;
- triangle and sub-voxel collision and their mixins;
- the actor stand-ins and combat;
- input replay, hidden window and fake focus, frame pacing;
- the geometry exporters and the overlay exporter;
- water.

**Skyrim-specific, to drop or generalize:**
- Skyrim skill training (`SmithingMixin` and the like) and damage formulas;
- digging *into* host geometry (keep it as an optional feature);
- Discord presence and e4mc multiplayer;
- names such as `SkyrimActorEntity`.

**Rendering choice for 1.3** (decided 2026-10-03: **(a)**, see BUILD.md 1.3):
- **(a) Geometry, SkyCraft's way: Godot draws Minecraft's exported meshes.** Proven code. Godot lights them and depth-tests them against the World game's layer and props. There's no OpenGL↔D3D12 interop and no frame lockstep. The hand + HUD stays a CPU-copied overlay. Minecraft-specific, but Minecraft is uniquely suited to it.
- **(b) Pictures, Fusion's generic way: color + depth into shared textures** (`WGL_NV_DX_interop2` or a Vulkan backend). Needs new interop code, and Minecraft must draw its own world.

**Protocol path:** either Fusion speaks SkyCraft's protocol v11 at first (an adapter, like `fake_skyrim.py`, getting the unmodified mod into Fusion quickly), or the kit moves to Fusion's protocol right away.
- The kit has to move eventually, because one protocol for all kits is a core decision.
- Geometry export would then become a new **mesh layer** kind in `schema/fusion.fidl`.

## 8. Fusion as the host (1.3a): what we learned

- **Empty regions must be sent.** Minecraft holds the player at the teleport point until the regions at its feet, the one below, and one region further down are "known". An empty region (0 triangles, 0 blocks) means "known air".
- **The host drives the look** (`SkyState.yaw/pitch`, every frame); Minecraft drives the position. Fusion's mouse look writes yaw/pitch, and Godot's camera sits at `McState.eye`.
  - F5 views: camera mode 1 = behind (`eye − dir × cameraDistance`, looking at the eye), 2 = in front.
- **Pacing:** Minecraft draws at most one frame per `SkyState` write. Write it exactly once per host frame.
- **Taking over a mapping:** a Minecraft that outlived the last host keeps `Local\SkyCraft_v1` open. A new host opens it and resets every control block, like `fake_skyrim.py`. Minecraft notices the new pid, the new collision epoch and the new teleport seq.
- **"Is Minecraft running?"** The mod holds the mutex `Local\SkyCraft_v1_minecraft` from start-up.
- **Winding:** the meshes are counter-clockwise front faces (OpenGL); Godot's front faces are clockwise. Reverse each triangle, or Godot flips the normals (dark tops).
- **Starting Minecraft:** go through the Windows shell (no inherited handles), like SkyCraft. JVM args `--enable-native-access=ALL-UNNAMED -Dskycraft.startHidden=true`.
  - `-Dskycraft.quitWithSkyrim=false` keeps Minecraft running after the host exits (handy while developing, but it keeps ~1.5 GB of RAM).
- **Minecraft's world persists** (`saves/SkyCraft` in the instance): tests must undo what they build.

## 9. The kit on the Fusion protocol (1.3b): what we learned

The kit now speaks the Fusion protocol; [`kits/fabric/README.md`](https://steonmod.com/docs/kit-fabric) maps each SkyCraft piece to the Fusion one. Section 8 still describes the mod's behavior, with these changes:
- **Pacing** now follows Fusion's camera slot: Minecraft draws at most one frame per Fusion frame.
- **Empty chunks:** Fusion's collision stream tells a guest once about each empty 16 m chunk in reach, so Minecraft still knows "known air". The kit turns each chunk into its eight 8-block regions (triangles clipped to each region, sub-voxels from `world/TriVoxels`).
- **Animated textures** arrive as small atlas regions every frame. Re-uploading the whole 2048x2576 atlas (21 MB) for each one froze Fusion for seconds, and Minecraft decided Fusion had gone away. Fusion now uploads gathered regions at most once a second.
- **Reconnecting:** the kit gives Fusion 10 s before it counts it as gone (Fusion may load something heavy); Fusion re-opens a lost game's discovery entry, and sends its collision again when it's back.
- **Minecraft's world is saved:** a mob a test spawned stays for the next run. The Minecraft check removes leftover pigs first, with the `remove` action.
- **Every SkyCraft port forks the protocol.** The catalog of passthrough projects (the user's site, `SteonModWeb`) lists about ten SkyCraft ports (ValCraft, SubCraft, OWCraft, PeakCraft, PortalCraft, GarryCraft...). ValCraft's header, for example, is SkyCraft's with "Skyrim" renamed "Valheim" plus a few host-specific bits (a "host paused" flag, item give/take for building costs). That's the N×M problem Fusion's one protocol avoids; the generic versions of those bits (pause = `Sleep`/`Wake`; items = the Items port) belong to later steps.
