SteonMod
View as Markdown

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

SideWhat 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)

RegionDirectionHowNotes
Header @0x0bothplainmagic SKYC, version, both pids, heartbeats (GetTickCount64 per frame)
SkyState @0x100host → MCseqlockin-game/menu/loading flags, world id, collision epoch, teleport request, viewport size, game hour
McState @0x200MC → hostseqlockfeet + eye position, yaw/pitch, vertical FOV, view-bob, raw 20 Hz tick positions + QPC time for interpolation, camera mode (F5) and distance
WaterGrid @0x400host → MCseqlock16×16 water surface heights around the player
Input ring @0x1000host → MCSPSC ring, 4096 × 16 Bkey/mouse/cursor events replayed into Minecraft
Actor table @0x12000host → MCtablenearby NPCs: id, position, box, health fraction, flags
Event ring @0x17000MC → hostringhits on NPCs (damage, crit, weapon), use, etc.
World entities @0x1C000MC → hosttablearrows, items and so on
Collision ring @0x20000host → MCbyte ring, 32 MBColClear(epoch), ColTris (exact triangles), ColRegion (8×8×8 sub-voxel mask per block); each region replaces all collision in its box
Overlay pixelsMC → hosttriple buffer, 3 × 4K RGBAhand + HUD + open screens on a transparent background
Render ringMC → hostbyte ring, 64 MBmeshes, 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 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.