Phase 13: forge-1_12_2 ships blockstate/model JSON for non-cube models
BlockAssetExtractor#extractModels walks every active mod's own jar/directory (Loader#getActiveModList's ModContainer#getSource, not the classloader, since directory listing isn't a classloader operation) for every blockstates/*.json and models/block/**/*.json file, shipping all of them over a new batched block_models WS message alongside the existing Phase 11 block_registry/block_textures dump. Resolution of this data into real non-cube geometry is entirely backend-side (see MCMapper-Backend's worker/src/models.rs). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015tKdPZt78zbPUZMXWzKEKt
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.octoturge.mcmapper.common;
|
||||
|
||||
import com.octoturge.mcmapper.common.protocol.BlockModelFile;
|
||||
import com.octoturge.mcmapper.common.protocol.BlockRegistryEntry;
|
||||
import com.octoturge.mcmapper.common.protocol.BlockTexture;
|
||||
import com.octoturge.mcmapper.common.protocol.DeltaEvent;
|
||||
@@ -54,6 +55,13 @@ public interface BackendConnection {
|
||||
*/
|
||||
void sendBlockTextures(List<BlockTexture> textures);
|
||||
|
||||
/**
|
||||
* Sends this leaf's raw blockstate/model JSON dump (Phase 13) — see {@link
|
||||
* BlockModelFile}'s javadoc. Implementations should batch calls the same way {@link
|
||||
* #sendBlockTextures} does, for the same heavily-modded-pack reason.
|
||||
*/
|
||||
void sendBlockModels(List<BlockModelFile> files);
|
||||
|
||||
/**
|
||||
* Registers a callback fired every time the connection successfully authenticates (including
|
||||
* after an automatic reconnect) — {@code connect()} itself is async (the real handshake
|
||||
@@ -112,6 +120,10 @@ public interface BackendConnection {
|
||||
public void sendBlockTextures(List<BlockTexture> textures) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBlockModels(List<BlockModelFile> files) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadyListener(Runnable onReady) {
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.octoturge.mcmapper.common;
|
||||
|
||||
import com.octoturge.mcmapper.common.json.MiniJson;
|
||||
import com.octoturge.mcmapper.common.protocol.BlockModelFile;
|
||||
import com.octoturge.mcmapper.common.protocol.BlockRegistryEntry;
|
||||
import com.octoturge.mcmapper.common.protocol.BlockTexture;
|
||||
import com.octoturge.mcmapper.common.protocol.DeltaEvent;
|
||||
@@ -40,6 +41,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* mod -> api {"type":"block_registry","entries":[{"id":4000,"name":"botania:manapool"}]}
|
||||
* mod -> api {"type":"block_textures","textures":[{"name":"botania:manapool","dataBase64":"..."}]}
|
||||
* mod -> api {"type":"block_models","entries":[{"kind":"blockstate","name":"botania:manapool","json":"..."},{"kind":"model","name":"botania:block/manapool","json":"..."}]}
|
||||
* </pre>
|
||||
*
|
||||
* Phase 3: {@code link_request} is sent by {@code /mcmapper link}; {@code chat} both directions
|
||||
@@ -83,6 +85,13 @@ import java.util.function.Consumer;
|
||||
* {@link #sendBlockTextures} batches into multiple messages (see {@code BLOCK_TEXTURE_BATCH_SIZE})
|
||||
* rather than one huge frame, since a heavily-modded server can have thousands of block textures.
|
||||
*
|
||||
* Phase 13: {@code block_models} is sent the same way, once, alongside {@code block_registry}/
|
||||
* {@code block_textures} — see {@link BlockModelFile}'s javadoc for why the mod ships every model
|
||||
* file it finds rather than trying to resolve blockstate-to-model references itself.
|
||||
* {@link #sendBlockModels} batches the same way {@link #sendBlockTextures} does, for the same
|
||||
* reason (blockstate/model JSON files, while individually small, can number in the thousands on
|
||||
* a heavily-modded pack).
|
||||
*
|
||||
* This class avoids a third-party JSON/WS library entirely (see {@link SimpleWebSocketClient}
|
||||
* and {@link MiniJson}'s javadoc) to keep the mod's classpath free of anything that would need
|
||||
* shading through legacy ForgeGradle.
|
||||
@@ -352,6 +361,28 @@ public class DefaultBackendConnection implements BackendConnection {
|
||||
}
|
||||
}
|
||||
|
||||
private static final int BLOCK_MODEL_BATCH_SIZE = 50;
|
||||
|
||||
@Override
|
||||
public void sendBlockModels(List<BlockModelFile> files) {
|
||||
if (files.isEmpty() || !serverReady) return;
|
||||
for (int start = 0; start < files.size(); start += BLOCK_MODEL_BATCH_SIZE) {
|
||||
int end = Math.min(start + BLOCK_MODEL_BATCH_SIZE, files.size());
|
||||
List<Object> entryList = new ArrayList<>();
|
||||
for (BlockModelFile f : files.subList(start, end)) {
|
||||
Map<String, Object> obj = new LinkedHashMap<>();
|
||||
obj.put("kind", f.kind);
|
||||
obj.put("name", f.name);
|
||||
obj.put("json", f.json);
|
||||
entryList.add(obj);
|
||||
}
|
||||
Map<String, Object> msg = new LinkedHashMap<>();
|
||||
msg.put("type", "block_models");
|
||||
msg.put("entries", entryList);
|
||||
sendRaw("block_models", msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadyListener(Runnable onReady) {
|
||||
this.readyListener = onReady;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.octoturge.mcmapper.common.protocol;
|
||||
|
||||
/**
|
||||
* One raw blockstate or model JSON file, extracted by a leaf off its own classloader (Phase 13) —
|
||||
* same classloader-is-already-there rationale as {@link BlockTexture}. {@code kind} is either
|
||||
* {@code "blockstate"} (a {@code assets/<modid>/blockstates/<path>.json} file, keyed by the
|
||||
* block's own registry name) or {@code "model"} (a {@code assets/<modid>/models/block/<path>.json}
|
||||
* file, keyed by {@code "<modid>:block/<path>"} — the same reference shape a blockstate's
|
||||
* {@code "model"} field or another model's {@code "parent"} field uses to point at it). The mod
|
||||
* ships every model file it finds under a mod's {@code models/block/} tree rather than trying to
|
||||
* pick out just the ones a given blockstate needs — a blockstate can reference a model at a path
|
||||
* that doesn't match the block's own registry path 1:1 (e.g. a shared base model reused by several
|
||||
* blocks), and the mod has no JSON parser to work that out itself; that resolution is the
|
||||
* backend's job (see MCMapper-Backend's {@code worker/src/models.rs}).
|
||||
*/
|
||||
public final class BlockModelFile {
|
||||
public final String kind;
|
||||
public final String name;
|
||||
public final String json;
|
||||
|
||||
public BlockModelFile(String kind, String name, String json) {
|
||||
this.kind = kind;
|
||||
this.name = name;
|
||||
this.json = json;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user