Phase 0: scaffold Gradle multi-project mod skeleton

common/ (shared source) plus three leaf modules: forge-1_12_2 (primary,
Enigmatica 2 target) and forge-1_7_10 both build via anatawa12's
Gradle-7-compatible ForgeGradle 1.2/2.3 forks (verified: both leaves build
clean on Gradle 7.6 / JDK 8). neoforge-26_1 is structurally scaffolded but
excluded from the default build pending its own toolchain in Phase 10.
This commit is contained in:
2026-08-08 14:10:01 +02:00
commit 621ea7c10d
26 changed files with 925 additions and 0 deletions
@@ -0,0 +1,42 @@
package com.octoturge.mcmapper.common;
import com.octoturge.mcmapper.common.protocol.DeltaEvent;
import com.octoturge.mcmapper.common.protocol.LinkRequest;
import java.util.List;
/**
* Outbound WS client to the backend `api` service. One implementation shared by all leaf
* modules (pure Java, no Minecraft API usage) — a docker-network hostname, LAN IP, or public
* domain in {@code MapperConfig#backendUrl} all work identically.
*
* Left as an interface with a no-op stub for Phase 0 scaffolding; the real WS client
* (handshake, reconnect/backoff, batching) lands in Phase 1.
*/
public interface BackendConnection {
void connect(String url, String serverToken);
void sendDeltas(List<DeltaEvent> deltas);
void sendLinkRequest(LinkRequest request);
void disconnect();
final class NoOp implements BackendConnection {
@Override
public void connect(String url, String serverToken) {
}
@Override
public void sendDeltas(List<DeltaEvent> deltas) {
}
@Override
public void sendLinkRequest(LinkRequest request) {
}
@Override
public void disconnect() {
}
}
}
@@ -0,0 +1,20 @@
package com.octoturge.mcmapper.common;
import com.octoturge.mcmapper.common.protocol.WaypointShare;
/**
* Loader-specific chat integration. Implementations inject web-originated chat into real
* in-game chat, and build the clickable waypoint chat component for whichever
* {@link WaypointShare.Format} is configured — that's text-component API and is different
* per Minecraft era, so it can't live in {@code common}.
*/
public interface ChatBridge {
void injectWebChatMessage(String displayName, String message);
void injectWaypointShare(WaypointShare waypoint);
/** Called by the loader's own chat event hook; forwards to the backend over the WS connection. */
interface OutboundSink {
void onInGameChatMessage(String uuid, String username, String message);
}
}
@@ -0,0 +1,23 @@
package com.octoturge.mcmapper.common;
import com.octoturge.mcmapper.common.protocol.DeltaEvent;
import java.util.List;
/**
* The seam between a specific Minecraft/Forge API generation and the shared delta-capture and
* networking logic. Each leaf module (forge-1_7_10, forge-1_12_2, neoforge-26_1) provides one
* implementation, adapting its own era's block-id/block-state representation into the
* {@code blockStateId} carried by {@link DeltaEvent}.
*/
public interface ChunkAdapter {
/** Bulk-read a chunk's current state for initial sync / reconciliation, as delta events. */
List<DeltaEvent> readChunk(String dimension, int chunkX, int chunkZ);
/** Register the loader-specific hooks (block place/break, chunk load/unload) that feed the dirty buffer. */
void registerEventHooks(DeltaSink sink);
interface DeltaSink {
void onDelta(DeltaEvent event);
}
}
@@ -0,0 +1,15 @@
package com.octoturge.mcmapper.common.config;
/**
* Loader-agnostic config model. Each leaf module owns loading/saving these values through
* its own loader's config system (Forge Config API for the legacy leaves, NeoForge's config
* system for neoforge-26_1) and constructs one of these to hand to the common connection code.
*/
public class MapperConfig {
public String backendUrl = "ws://localhost:3000/ws";
public String serverToken = "";
public boolean playerTrackingEnabled = true;
public int deltaFlushIntervalTicks = 20;
public int reconciliationIntervalTicks = 20 * 60 * 5;
}
@@ -0,0 +1,32 @@
package com.octoturge.mcmapper.common.protocol;
/**
* A single block change, produced by either the event-driven capture path or the periodic
* reconciliation sweep. {@code blockStateId} is a palette index into whatever block/state
* palette the leaf module's {@code ChunkAdapter} maintains — the common module never
* interprets it, it just carries it to the backend.
*/
public class DeltaEvent {
public final String dimension;
public final int x;
public final int y;
public final int z;
public final int blockStateId;
public final long timestamp;
public final Source source;
public DeltaEvent(String dimension, int x, int y, int z, int blockStateId, long timestamp, Source source) {
this.dimension = dimension;
this.x = x;
this.y = y;
this.z = z;
this.blockStateId = blockStateId;
this.timestamp = timestamp;
this.source = source;
}
public enum Source {
EVENT,
RECONCILIATION
}
}
@@ -0,0 +1,25 @@
package com.octoturge.mcmapper.common.protocol;
/**
* Sent when a player runs the link command in-game. {@code authMode} mirrors the MC server's
* own online-mode setting and tells the backend whether {@code uuid} is a real Mojang UUID
* (safe to merge across servers) or an offline-mode hash (scoped to this server only).
*/
public class LinkRequest {
public final String uuid;
public final String username;
public final String code;
public final AuthMode authMode;
public LinkRequest(String uuid, String username, String code, AuthMode authMode) {
this.uuid = uuid;
this.username = username;
this.code = code;
this.authMode = authMode;
}
public enum AuthMode {
ONLINE,
OFFLINE
}
}
@@ -0,0 +1,32 @@
package com.octoturge.mcmapper.common.protocol;
/**
* Structured payload pushed from the backend when a web visitor shares a marker to chat.
* {@code x, y, z} are all populated by the backend (y auto-derived from its heightmap at
* placement time) — the mod's only job is to render this as a clickable chat component in
* whichever {@link Format} the server admin configured.
*/
public class WaypointShare {
public final String name;
public final int x;
public final int y;
public final int z;
public final String dimension;
public final String color;
public final Format format;
public WaypointShare(String name, int x, int y, int z, String dimension, String color, Format format) {
this.name = name;
this.x = x;
this.y = y;
this.z = z;
this.dimension = dimension;
this.color = color;
this.format = format;
}
public enum Format {
JOURNEYMAP,
XAERO
}
}