Skip to content

Commit

Permalink
Add EyeCandy scripting support
Browse files Browse the repository at this point in the history
  • Loading branch information
zbx1425 committed Aug 1, 2023
1 parent 35cb9d4 commit 6a598b8
Show file tree
Hide file tree
Showing 14 changed files with 287 additions and 89 deletions.
11 changes: 11 additions & 0 deletions common/src/main/java/cn/zbx1425/mtrsteamloco/Debug.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package cn.zbx1425.mtrsteamloco;

import cn.zbx1425.mtrsteamloco.data.EyeCandyProperties;
import cn.zbx1425.mtrsteamloco.data.EyeCandyRegistry;
import cn.zbx1425.mtrsteamloco.render.integration.TrainModelCapture;
import cn.zbx1425.sowcerext.model.ModelCluster;
import cn.zbx1425.sowcerext.model.RawModel;
import cn.zbx1425.sowcerext.model.loader.NmbModelLoader;
import cn.zbx1425.sowcerext.model.loader.ObjModelLoader;
import mtr.data.TransportMode;
import mtr.mappings.Text;
import mtr.mappings.UtilitiesClient;
import mtr.render.JonModelTrainRenderer;
import net.minecraft.client.Minecraft;
Expand Down Expand Up @@ -88,6 +92,13 @@ public static void saveAllLoadedModels(Path outputDir) {
}
}

public static void registerAllModelsAsEyeCandy() {
for (Map.Entry<ResourceLocation, ModelCluster> entry : MainClient.modelManager.uploadedVertArrays.entrySet()) {
String key = FilenameUtils.getBaseName(entry.getKey().getPath());
EyeCandyRegistry.register(key, new EyeCandyProperties(Text.literal(key), entry.getValue()));
}
}

private static Map<String, RawModel> nameModels(RawModel[] capturedModels) {
return Map.of(
"body", capturedModels[0],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cn.zbx1425.mtrsteamloco.Main;
import cn.zbx1425.mtrsteamloco.network.PacketScreen;
import cn.zbx1425.mtrsteamloco.render.scripting.eyecandy.EyeCandyScriptContext;
import mtr.mappings.BlockDirectionalMapper;
import mtr.mappings.BlockEntityClientSerializableMapper;
import mtr.mappings.BlockEntityMapper;
Expand Down Expand Up @@ -82,6 +83,8 @@ public static class BlockEntityEyeCandy extends BlockEntityClientSerializableMap

public boolean fullLight = false;

public final EyeCandyScriptContext scriptContext = new EyeCandyScriptContext(this);

public BlockEntityEyeCandy(BlockPos pos, BlockState state) {
super(Main.BLOCK_ENTITY_TYPE_EYE_CANDY.get(), pos, state);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cn.zbx1425.mtrsteamloco.data;

import cn.zbx1425.mtrsteamloco.render.scripting.ScriptHolder;
import cn.zbx1425.sowcerext.model.ModelCluster;
import net.minecraft.network.chat.Component;

Expand All @@ -11,14 +12,20 @@ public class EyeCandyProperties implements Closeable {
public Component name;

public ModelCluster model;
public ScriptHolder script;

public EyeCandyProperties(Component name, ModelCluster model) {
this.name = name;
this.model = model;
}

public EyeCandyProperties(Component name, ScriptHolder script) {
this.name = name;
this.script = script;
}

@Override
public void close() throws IOException {
model.close();
if (model != null) model.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@
import cn.zbx1425.mtrsteamloco.Main;
import cn.zbx1425.mtrsteamloco.MainClient;
import cn.zbx1425.mtrsteamloco.render.integration.MtrModelRegistryUtil;
import cn.zbx1425.mtrsteamloco.render.scripting.ScriptHolder;
import cn.zbx1425.sowcer.math.Vector3f;
import cn.zbx1425.sowcerext.model.ModelCluster;
import cn.zbx1425.sowcerext.model.RawModel;
import cn.zbx1425.sowcerext.util.ResourceUtil;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import mtr.mappings.Text;
import mtr.mappings.Utilities;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -35,12 +37,6 @@ public static void register(String key, EyeCandyProperties properties) {

public static void reload(ResourceManager resourceManager) {
elements.clear();
/*
for (Map.Entry<ResourceLocation, ModelCluster> entry : MainClient.modelManager.uploadedVertArrays.entrySet()) {
String key = FilenameUtils.getBaseName(entry.getKey().getPath());
register(key, new EyeCandyProperties(Text.literal(key), entry.getValue()));
}
*/
List<Pair<ResourceLocation, Resource>> resources =
MtrModelRegistryUtil.listResources(resourceManager, "mtrsteamloco", "eyecandies", ".json");
for (Pair<ResourceLocation, Resource> pair : resources) {
Expand All @@ -65,12 +61,8 @@ public static void reload(ResourceManager resourceManager) {
}
}

public static ModelCluster getModel(String key) {
if (elements.containsKey(key)) {
return elements.get(key).model;
} else {
return null;
}
public static EyeCandyProperties getProperty(String key) {
return elements.getOrDefault(key, null);
}

private static EyeCandyProperties loadFromJson(ResourceManager resourceManager, String key, JsonObject obj) throws IOException {
Expand All @@ -80,39 +72,61 @@ MtrModelRegistryUtil.resourceManager, new ResourceLocation(obj.get("atlasIndex"
);
}

RawModel rawModel = MainClient.modelManager.loadRawModel(resourceManager,
new ResourceLocation(obj.get("model").getAsString()), MainClient.atlasManager).copy();
if (obj.has("model")) {
RawModel rawModel = MainClient.modelManager.loadRawModel(resourceManager,
new ResourceLocation(obj.get("model").getAsString()), MainClient.atlasManager).copy();

if (obj.has("textureId")) {
rawModel.replaceAllTexture("default.png", new ResourceLocation(obj.get("textureId").getAsString()));
}
if (obj.has("textureId")) {
rawModel.replaceAllTexture("default.png", new ResourceLocation(obj.get("textureId").getAsString()));
}

if (obj.has("translation")) {
JsonArray vec = obj.get("translation").getAsJsonArray();
rawModel.applyTranslation(vec.get(0).getAsFloat(), vec.get(1).getAsFloat(), vec.get(2).getAsFloat());
}
if (obj.has("rotation")) {
JsonArray vec = obj.get("rotation").getAsJsonArray();
rawModel.applyRotation(new Vector3f(1, 0, 0), vec.get(0).getAsFloat());
rawModel.applyRotation(new Vector3f(0, 1, 0), vec.get(1).getAsFloat());
rawModel.applyRotation(new Vector3f(0, 0, 1), vec.get(2).getAsFloat());
}
if (obj.has("scale")) {
JsonArray vec = obj.get("scale").getAsJsonArray();
rawModel.applyScale(vec.get(0).getAsFloat(), vec.get(1).getAsFloat(), vec.get(2).getAsFloat());
}
if (obj.has("mirror")) {
JsonArray vec = obj.get("mirror").getAsJsonArray();
rawModel.applyMirror(
vec.get(0).getAsBoolean(), vec.get(1).getAsBoolean(), vec.get(2).getAsBoolean(),
vec.get(0).getAsBoolean(), vec.get(1).getAsBoolean(), vec.get(2).getAsBoolean()
);
}
if (obj.has("translation")) {
JsonArray vec = obj.get("translation").getAsJsonArray();
rawModel.applyTranslation(vec.get(0).getAsFloat(), vec.get(1).getAsFloat(), vec.get(2).getAsFloat());
}
if (obj.has("rotation")) {
JsonArray vec = obj.get("rotation").getAsJsonArray();
rawModel.applyRotation(new Vector3f(1, 0, 0), vec.get(0).getAsFloat());
rawModel.applyRotation(new Vector3f(0, 1, 0), vec.get(1).getAsFloat());
rawModel.applyRotation(new Vector3f(0, 0, 1), vec.get(2).getAsFloat());
}
if (obj.has("scale")) {
JsonArray vec = obj.get("scale").getAsJsonArray();
rawModel.applyScale(vec.get(0).getAsFloat(), vec.get(1).getAsFloat(), vec.get(2).getAsFloat());
}
if (obj.has("mirror")) {
JsonArray vec = obj.get("mirror").getAsJsonArray();
rawModel.applyMirror(
vec.get(0).getAsBoolean(), vec.get(1).getAsBoolean(), vec.get(2).getAsBoolean(),
vec.get(0).getAsBoolean(), vec.get(1).getAsBoolean(), vec.get(2).getAsBoolean()
);
}

rawModel.sourceLocation = new ResourceLocation(rawModel.sourceLocation.toString() + "/" + key);

rawModel.sourceLocation = new ResourceLocation(rawModel.sourceLocation.toString() + "/" + key);
ModelCluster cluster = MainClient.modelManager.uploadVertArrays(rawModel);

ModelCluster cluster = MainClient.modelManager.uploadVertArrays(rawModel);
return new EyeCandyProperties(Text.translatable(obj.get("name").getAsString()), cluster);
} else if (obj.has("scriptFiles")) {
ScriptHolder scriptContext = new ScriptHolder();
Map<ResourceLocation, String> scripts = new Object2ObjectArrayMap<>();
if (obj.has("scriptTexts")) {
JsonArray scriptTexts = obj.get("script_texts").getAsJsonArray();
for (int i = 0; i < scriptTexts.size(); i++) {
scripts.put(new ResourceLocation("mtrsteamloco", "script_texts/" + key + "/" + i),
scriptTexts.get(i).getAsString());
}
}
JsonArray scriptFiles = obj.get("scriptFiles").getAsJsonArray();
for (int i = 0; i < scriptFiles.size(); i++) {
ResourceLocation scriptLocation = new ResourceLocation(scriptFiles.get(i).getAsString());
scripts.put(scriptLocation, ResourceUtil.readResource(resourceManager, scriptLocation));
}
scriptContext.load(scripts);

return new EyeCandyProperties(Text.translatable(obj.get("name").getAsString()), cluster);
return new EyeCandyProperties(Text.translatable(obj.get("name").getAsString()), scriptContext);
} else {
throw new IllegalArgumentException("Invalid eye-candy json: " + key);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import cn.zbx1425.mtrsteamloco.Main;
import cn.zbx1425.mtrsteamloco.render.integration.MtrModelRegistryUtil;
import cn.zbx1425.mtrsteamloco.render.scripting.RenderTrainScripted;
import cn.zbx1425.mtrsteamloco.render.scripting.TrainTypeScriptContext;
import cn.zbx1425.mtrsteamloco.render.scripting.train.RenderTrainScripted;
import cn.zbx1425.mtrsteamloco.render.scripting.ScriptHolder;
import cn.zbx1425.mtrsteamloco.sound.BveTrainSoundFix;
import cn.zbx1425.sowcerext.util.ResourceUtil;
import com.google.gson.JsonArray;
Expand Down Expand Up @@ -81,7 +81,7 @@ public static void init(ResourceManager resourceManager) {
? new BveTrainSoundFix(new BveTrainSoundConfig(resourceManager, bveSoundBaseId))
: new JonTrainSound(speedSoundBaseId, new JonTrainSound.JonTrainSoundConfig(doorSoundBaseId, speedSoundCount, doorCloseSoundTime, accelSoundAtCoast, constPlaybackSpeed));

TrainTypeScriptContext scriptContext = new TrainTypeScriptContext();
ScriptHolder scriptContext = new ScriptHolder();
Map<ResourceLocation, String> scripts = new Object2ObjectArrayMap<>();
if (jsonObject.has("script_texts")) {
JsonArray scriptTexts = jsonObject.get("script_texts").getAsJsonArray();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
package cn.zbx1425.mtrsteamloco.render.block;

import cn.zbx1425.mtrsteamloco.ClientConfig;
import cn.zbx1425.mtrsteamloco.MainClient;
import cn.zbx1425.mtrsteamloco.block.BlockEyeCandy;
import cn.zbx1425.mtrsteamloco.data.EyeCandyProperties;
import cn.zbx1425.mtrsteamloco.data.EyeCandyRegistry;
import cn.zbx1425.mtrsteamloco.render.RenderUtil;
import cn.zbx1425.mtrsteamloco.render.integration.MtrModelRegistryUtil;
import cn.zbx1425.mtrsteamloco.render.rail.RailRenderDispatcher;
import cn.zbx1425.sowcer.math.Matrix4f;
import cn.zbx1425.sowcer.math.PoseStackUtil;
import cn.zbx1425.sowcerext.model.ModelCluster;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import mtr.RegistryObject;
import mtr.block.IBlock;
import mtr.mappings.BlockEntityRendererMapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
#if MC_VERSION >= "11904"
import net.minecraft.world.item.ItemDisplayContext;
#else
Expand Down Expand Up @@ -52,15 +45,15 @@ public void render(BlockEyeCandy.BlockEntityEyeCandy blockEntity, float f, @NotN
if (world == null) return;

int lightToUse = blockEntity.fullLight ? LightTexture.pack(15, 15) : light;
Matrix4f candyPos = new Matrix4f(matrices.last().pose());
Matrix4f candyPose = new Matrix4f(matrices.last().pose());

ModelCluster model = EyeCandyRegistry.getModel(blockEntity.prefabId);
if (model == null || RailRenderDispatcher.isHoldingBrush) {
EyeCandyProperties prop = EyeCandyRegistry.getProperty(blockEntity.prefabId);
if (prop == null || RailRenderDispatcher.isHoldingBrush) {
matrices.pushPose();
matrices.translate(0.5f, 0.5f, 0.5f);
PoseStackUtil.rotY(matrices, (float) ((System.currentTimeMillis() % 1000) * (Math.PI * 2 / 1000)));
#if MC_VERSION >= "11904"
if (blockEntity.prefabId != null && model == null) {
if (blockEntity.prefabId != null && prop == null) {
Minecraft.getInstance().getItemRenderer().renderStatic(BARRIER_ITEM_STACK.get(), ItemDisplayContext.GROUND, lightToUse, 0, matrices, vertexConsumers, world, 0);
} else {
Minecraft.getInstance().getItemRenderer().renderStatic(BRUSH_ITEM_STACK.get(), ItemDisplayContext.GROUND, lightToUse, 0, matrices, vertexConsumers, world, 0);
Expand All @@ -74,17 +67,25 @@ public void render(BlockEyeCandy.BlockEntityEyeCandy blockEntity, float f, @NotN
#endif
matrices.popPose();
}
if (model == null) return;
if (prop == null) return;

final BlockPos pos = blockEntity.getBlockPos();
final Direction facing = IBlock.getStatePropertySafe(world, pos, BlockEyeCandy.FACING);
candyPos.translate(0.5f, 0f, 0.5f);
candyPos.translate(blockEntity.translateX, blockEntity.translateY, blockEntity.translateZ);
candyPos.rotateX(blockEntity.rotateX);
candyPos.rotateY(blockEntity.rotateY);
candyPos.rotateZ(blockEntity.rotateZ);
candyPos.rotateY(-(float)Math.toRadians(facing.toYRot()) + (float)(Math.PI));
MainClient.drawScheduler.enqueue(model, candyPos, lightToUse);
candyPose.translate(0.5f, 0f, 0.5f);
candyPose.translate(blockEntity.translateX, blockEntity.translateY, blockEntity.translateZ);
candyPose.rotateY(-(float)Math.toRadians(facing.toYRot()) + (float)(Math.PI));
candyPose.rotateX(blockEntity.rotateX);
candyPose.rotateY(blockEntity.rotateY);
candyPose.rotateZ(blockEntity.rotateZ);
if (prop.model != null) {
MainClient.drawScheduler.enqueue(prop.model, candyPose, lightToUse);
}
if (prop.script != null) {
synchronized (blockEntity.scriptContext) {
blockEntity.scriptContext.scriptResult.commit(MainClient.drawScheduler, candyPose, lightToUse);
}
blockEntity.scriptContext.tryCallRender(prop.script);
}
}

@Override
Expand Down
Loading

0 comments on commit 6a598b8

Please sign in to comment.