Phase 3: /mcmapper link command and two-way chat bridge
Test-first from here on (per request after Phase 2's backend commit): LinkCodeGenerator has a standalone test (common/src/test) written and confirmed failing before the implementation existed. common: LinkCodeGenerator produces a 6-character code from an unambiguous charset (excludes 0/O/1/I/L — it gets read off a chat line and typed back). BackendConnection grows sendLinkRequest (now actually implemented, was a Phase 1 stub), sendChatMessage, and setChatListener/ ChatListener for inbound web->game chat, all wired into DefaultBackendConnection's existing JSON wire protocol. forge-1_12_2: LinkCommand (/mcmapper link) generates a code, resolves online/offline from the server's actual auth mode (MinecraftServer#isServerInOnlineMode), and shows it to the player. Forge1122ChatBridge implements the inbound half (injects web chat into real in-game chat via the player list) — injectWaypointShare is a documented Phase 4 stub, same pattern as sendLinkRequest was in Phase 1. MCMapperMod hooks ServerChatEvent to forward in-game chat out and wires the chat listener to the bridge. Verified end-to-end against a live MCMapper-Backend instance through the real Java client (not a stand-in): a mod-generated link code correctly redeems via the backend's HTTP endpoint to an account with the mod- supplied username, and a browser chat message correctly round-trips all the way to the mod's live ChatListener callback.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package com.octoturge.mcmapper.forge1122;
|
||||
|
||||
import com.octoturge.mcmapper.common.ChatBridge;
|
||||
import com.octoturge.mcmapper.common.protocol.WaypointShare;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class Forge1122ChatBridge implements ChatBridge {
|
||||
private final MinecraftServer server;
|
||||
private final Logger logger;
|
||||
|
||||
public Forge1122ChatBridge(MinecraftServer server, Logger logger) {
|
||||
this.server = server;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectWebChatMessage(String displayName, String message) {
|
||||
server.getPlayerList().sendMessage(new TextComponentString("[Web] " + displayName + ": " + message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectWaypointShare(WaypointShare waypoint) {
|
||||
// Marker sharing lands in Phase 4 (needs the JourneyMap/Xaero wire-format research spike
|
||||
// the plan calls for) — nothing calls this yet.
|
||||
logger.warn("injectWaypointShare called before Phase 4's waypoint sharing is implemented — ignoring");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.octoturge.mcmapper.forge1122;
|
||||
|
||||
import com.octoturge.mcmapper.common.BackendConnection;
|
||||
import com.octoturge.mcmapper.common.LinkCodeGenerator;
|
||||
import com.octoturge.mcmapper.common.protocol.LinkRequest;
|
||||
import net.minecraft.command.CommandBase;
|
||||
import net.minecraft.command.CommandException;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
|
||||
/** {@code /mcmapper link} — see LinkRequest.java's javadoc and MCMapper-Backend's link.ts. */
|
||||
public class LinkCommand extends CommandBase {
|
||||
private final BackendConnection connection;
|
||||
|
||||
public LinkCommand(BackendConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "mcmapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage(ICommandSender sender) {
|
||||
return "/mcmapper link";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequiredPermissionLevel() {
|
||||
return 0; // any player may link their own account
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
|
||||
if (args.length == 0 || !"link".equals(args[0])) {
|
||||
sender.sendMessage(new TextComponentString("Usage: /mcmapper link"));
|
||||
return;
|
||||
}
|
||||
if (!(sender instanceof EntityPlayerMP)) {
|
||||
sender.sendMessage(new TextComponentString("Only players can link an account."));
|
||||
return;
|
||||
}
|
||||
|
||||
EntityPlayerMP player = (EntityPlayerMP) sender;
|
||||
String code = LinkCodeGenerator.generate();
|
||||
LinkRequest.AuthMode authMode =
|
||||
server.isServerInOnlineMode() ? LinkRequest.AuthMode.ONLINE : LinkRequest.AuthMode.OFFLINE;
|
||||
connection.sendLinkRequest(new LinkRequest(player.getUniqueID().toString(), player.getName(), code, authMode));
|
||||
player.sendMessage(new TextComponentString(
|
||||
"Your MCMapper link code: " + code + " — enter it on the map site within 10 minutes."));
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import com.octoturge.mcmapper.common.DefaultBackendConnection;
|
||||
import com.octoturge.mcmapper.common.config.MapperConfig;
|
||||
import com.octoturge.mcmapper.common.protocol.DeltaEvent;
|
||||
import com.octoturge.mcmapper.common.protocol.SectionData;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.event.ServerChatEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
|
||||
@@ -27,8 +29,8 @@ import java.util.Set;
|
||||
* Entry point for the 1.12.2 leaf — the primary/first-implemented target (Enigmatica 2).
|
||||
* Phase 1: connects to the backend over WS, backfills the overworld's loaded chunks, and
|
||||
* flushes event-driven column deltas on a timer (no periodic reconciliation sweep yet — see
|
||||
* plan's Phase 7). Phase 2 adds full-section backfill/flush for 3D mesh rendering. Chat bridge
|
||||
* and `/mcmapper link` land in Phase 3.
|
||||
* plan's Phase 7). Phase 2 adds full-section backfill/flush for 3D mesh rendering. Phase 3 adds
|
||||
* `/mcmapper link` and the two-way chat bridge (see LinkCommand, Forge1122ChatBridge).
|
||||
*/
|
||||
@Mod(modid = MCMapperMod.MOD_ID, name = "MCMapper", version = MCMapperMod.VERSION)
|
||||
public class MCMapperMod {
|
||||
@@ -88,9 +90,19 @@ public class MCMapperMod {
|
||||
}
|
||||
});
|
||||
|
||||
Forge1122ChatBridge chatBridge = new Forge1122ChatBridge(event.getServer(), LOGGER);
|
||||
connection.setChatListener(chatBridge::injectWebChatMessage);
|
||||
event.registerServerCommand(new LinkCommand(connection));
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerChat(ServerChatEvent event) {
|
||||
EntityPlayerMP player = event.getPlayer();
|
||||
connection.sendChatMessage(player.getUniqueID().toString(), player.getName(), event.getMessage());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.END) return;
|
||||
|
||||
Reference in New Issue
Block a user