diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelCache.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelCache.java index 9cd66069e..2b99cde80 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelCache.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelCache.java @@ -1,40 +1,11 @@ package dev.engine_room.flywheel.lib.model; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import org.jetbrains.annotations.ApiStatus; - import dev.engine_room.flywheel.api.model.Model; -import dev.engine_room.flywheel.lib.util.FlwUtil; - -public final class ModelCache { - private static final Set> ALL = FlwUtil.createWeakHashSet(); - private final Function factory; - private final Map map = new ConcurrentHashMap<>(); +public final class ModelCache extends ResourceReloadCache { public ModelCache(Function factory) { - this.factory = factory; - - synchronized (ALL) { - ALL.add(this); - } - } - - public Model get(T key) { - return map.computeIfAbsent(key, factory); - } - - public void clear() { - map.clear(); - } - - @ApiStatus.Internal - public static void onEndClientResourceReload() { - for (ModelCache cache : ALL) { - cache.clear(); - } + super(factory); } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelHolder.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelHolder.java index 7ca5f5199..7e838bf70 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelHolder.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelHolder.java @@ -1,60 +1,11 @@ package dev.engine_room.flywheel.lib.model; -import java.util.Set; import java.util.function.Supplier; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - import dev.engine_room.flywheel.api.model.Model; -import dev.engine_room.flywheel.lib.util.FlwUtil; - -public final class ModelHolder { - private static final Set ALL = FlwUtil.createWeakHashSet(); - private final Supplier factory; - @Nullable - private volatile Model model; +public final class ModelHolder extends ResourceReloadHolder { public ModelHolder(Supplier factory) { - this.factory = factory; - - synchronized (ALL) { - ALL.add(this); - } - } - - public Model get() { - Model model = this.model; - - if (model == null) { - synchronized (this) { - model = this.model; - if (model == null) { - this.model = model = factory.get(); - } - } - } - - return model; - } - - public void clear() { - Model model = this.model; - - if (model != null) { - synchronized (this) { - model = this.model; - if (model != null) { - this.model = null; - } - } - } - } - - @ApiStatus.Internal - public static void onEndClientResourceReload() { - for (ModelHolder holder : ALL) { - holder.clear(); - } + super(factory); } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ResourceReloadCache.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ResourceReloadCache.java new file mode 100644 index 000000000..363cf61b2 --- /dev/null +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ResourceReloadCache.java @@ -0,0 +1,44 @@ +package dev.engine_room.flywheel.lib.model; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import org.jetbrains.annotations.ApiStatus; + +import dev.engine_room.flywheel.lib.util.FlwUtil; + +public class ResourceReloadCache implements Function { + private static final Set> ALL = FlwUtil.createWeakHashSet(); + private final Function factory; + private final Map map = new ConcurrentHashMap<>(); + + public ResourceReloadCache(Function factory) { + this.factory = factory; + + synchronized (ALL) { + ALL.add(this); + } + } + + public final U get(T key) { + return map.computeIfAbsent(key, factory); + } + + @Override + public final U apply(T t) { + return get(t); + } + + public final void clear() { + map.clear(); + } + + @ApiStatus.Internal + public static void onEndClientResourceReload() { + for (ResourceReloadCache cache : ALL) { + cache.clear(); + } + } +} diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ResourceReloadHolder.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ResourceReloadHolder.java new file mode 100644 index 000000000..dd00c5e2a --- /dev/null +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ResourceReloadHolder.java @@ -0,0 +1,60 @@ +package dev.engine_room.flywheel.lib.model; + +import java.util.Set; +import java.util.function.Supplier; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import dev.engine_room.flywheel.lib.util.FlwUtil; + +public class ResourceReloadHolder implements Supplier { + private static final Set> ALL = FlwUtil.createWeakHashSet(); + private final Supplier factory; + @Nullable + private volatile T obj; + + public ResourceReloadHolder(Supplier factory) { + this.factory = factory; + + synchronized (ALL) { + ALL.add(this); + } + } + + @Override + public final T get() { + T obj = this.obj; + + if (obj == null) { + synchronized (this) { + obj = this.obj; + if (obj == null) { + this.obj = obj = factory.get(); + } + } + } + + return obj; + } + + public final void clear() { + T obj = this.obj; + + if (obj != null) { + synchronized (this) { + obj = this.obj; + if (obj != null) { + this.obj = null; + } + } + } + } + + @ApiStatus.Internal + public static void onEndClientResourceReload() { + for (ResourceReloadHolder holder : ALL) { + holder.clear(); + } + } +} diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java index 48cb078bc..da3d64bd6 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java @@ -1,7 +1,6 @@ package dev.engine_room.flywheel.lib.model.part; import java.util.NoSuchElementException; -import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.ObjIntConsumer; @@ -15,23 +14,16 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.engine_room.flywheel.api.instance.InstancerProvider; -import dev.engine_room.flywheel.api.material.Material; -import dev.engine_room.flywheel.api.model.Mesh; import dev.engine_room.flywheel.api.model.Model; import dev.engine_room.flywheel.lib.instance.InstanceTypes; import dev.engine_room.flywheel.lib.instance.TransformedInstance; -import dev.engine_room.flywheel.lib.model.ModelCache; -import dev.engine_room.flywheel.lib.model.SingleMeshModel; import dev.engine_room.flywheel.lib.transform.Affine; import dev.engine_room.flywheel.lib.transform.TransformStack; -import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.PartPose; public final class InstanceTree { - private static final ModelCache MODEL_CACHE = new ModelCache<>(entry -> new SingleMeshModel(entry.mesh(), entry.material())); - - private final MeshTree source; + private final ModelTree source; @Nullable private final TransformedInstance instance; private final InstanceTree[] children; @@ -54,7 +46,7 @@ public final class InstanceTree { private boolean changed; - private InstanceTree(MeshTree source, @Nullable TransformedInstance instance, InstanceTree[] children) { + private InstanceTree(ModelTree source, @Nullable TransformedInstance instance, InstanceTree[] children) { this.source = source; this.instance = instance; this.children = children; @@ -68,21 +60,16 @@ private InstanceTree(MeshTree source, @Nullable TransformedInstance instance, In resetPose(); } - private static InstanceTree create(InstancerProvider provider, MeshTree meshTree, BiFunction meshFinalizerFunc, String path) { + public static InstanceTree create(InstancerProvider provider, ModelTree meshTree) { InstanceTree[] children = new InstanceTree[meshTree.childCount()]; - String pathSlash = path + "/"; - for (int i = 0; i < meshTree.childCount(); i++) { - var meshTreeChild = meshTree.child(i); - String name = meshTree.childName(i); - children[i] = create(provider, meshTreeChild, meshFinalizerFunc, pathSlash + name); + children[i] = create(provider, meshTree.child(i)); } - Mesh mesh = meshTree.mesh(); + Model model = meshTree.model(); TransformedInstance instance; - if (mesh != null) { - Model.ConfiguredMesh configuredMesh = meshFinalizerFunc.apply(path, mesh); - instance = provider.instancer(InstanceTypes.TRANSFORMED, MODEL_CACHE.get(configuredMesh)) + if (model != null) { + instance = provider.instancer(InstanceTypes.TRANSFORMED, model) .createInstance(); } else { instance = null; @@ -91,22 +78,6 @@ private static InstanceTree create(InstancerProvider provider, MeshTree meshTree return new InstanceTree(meshTree, instance, children); } - public static InstanceTree create(InstancerProvider provider, MeshTree meshTree, BiFunction meshFinalizerFunc) { - return create(provider, meshTree, meshFinalizerFunc, ""); - } - - public static InstanceTree create(InstancerProvider provider, ModelLayerLocation layer, BiFunction meshFinalizerFunc) { - return create(provider, MeshTree.of(layer), meshFinalizerFunc); - } - - public static InstanceTree create(InstancerProvider provider, MeshTree meshTree, Material material) { - return create(provider, meshTree, (path, mesh) -> new Model.ConfiguredMesh(material, mesh)); - } - - public static InstanceTree create(InstancerProvider provider, ModelLayerLocation layer, Material material) { - return create(provider, MeshTree.of(layer), material); - } - @Nullable public TransformedInstance instance() { return instance; diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/LoweringVisitor.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/LoweringVisitor.java new file mode 100644 index 000000000..8b5d30af1 --- /dev/null +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/LoweringVisitor.java @@ -0,0 +1,93 @@ +package dev.engine_room.flywheel.lib.model.part; + +import java.util.ArrayList; + +import org.jetbrains.annotations.Nullable; + +import dev.engine_room.flywheel.api.material.Material; +import dev.engine_room.flywheel.api.model.Mesh; +import dev.engine_room.flywheel.api.model.Model; +import dev.engine_room.flywheel.lib.model.RetexturedMesh; +import dev.engine_room.flywheel.lib.model.SingleMeshModel; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +/** + * A tree walking visitor that lowers a MeshTree to a ModelTree. + */ +public interface LoweringVisitor { + static ModelTree leaf(Model model) { + return leaf(model, PartPose.ZERO); + } + + static ModelTree leaf(Model model, PartPose initialPose) { + return ModelTree.create(model, initialPose, new ModelTree[0], new String[0]); + } + + static LoweringVisitor materialApplyingVisitor(Material material) { + return (path, mesh) -> new SingleMeshModel(mesh, material); + } + + static LoweringVisitor retexturingVisitor(Material material, TextureAtlasSprite sprite) { + return (path, mesh) -> new SingleMeshModel(new RetexturedMesh(mesh, sprite), material); + } + + static String append(String path, String child) { + if (path.isEmpty()) { + return child; + } + + return path + "/" + child; + } + + /** + * Walk the given MeshTree, lowering its Mesh to a Model, and lowering all children using the given visitor. + * + * @param path The absolute path to the MeshTree node. + * @param meshTree The MeshTree to walk. + * @param loweringVisitor The visitor to use to lower the Mesh and MeshTree nodes. + * @return The lowered ModelTree. + */ + static ModelTree walk(String path, MeshTree meshTree, LoweringVisitor loweringVisitor) { + Model out = null; + + if (meshTree.mesh() != null) { + out = loweringVisitor.visit(path, meshTree.mesh()); + } + + ArrayList children = new ArrayList<>(); + ArrayList childNames = new ArrayList<>(); + + for (int i = 0; i < meshTree.childCount(); i++) { + var child = loweringVisitor.visit(append(path, meshTree.childName(i)), meshTree.child(i)); + + if (child != null) { + children.add(child); + childNames.add(meshTree.childName(i)); + } + } + + return ModelTree.create(out, meshTree.initialPose(), children.toArray(new ModelTree[0]), childNames.toArray(new String[0])); + } + + /** + * Visit the given Mesh, converting it to a Model. + * + * @param path The absolute path to the MeshTree node containing the Mesh. + * @param mesh The Mesh to lower. + * @return The lowered Model, or null if the Model should be omitted. + */ + @Nullable Model visit(String path, Mesh mesh); + + /** + * Visit the given MeshTree, converting it to a ModelTree. + * + * @param path The absolute path to the MeshTree node. + * @param meshTree The MeshTree to lower. + * @return The lowered ModelTree, or null if the ModelTree should be omitted. + */ + @Nullable + default ModelTree visit(String path, MeshTree meshTree) { + return walk(path, meshTree, this); + } +} diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/ModelTree.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/ModelTree.java new file mode 100644 index 000000000..293394bef --- /dev/null +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/ModelTree.java @@ -0,0 +1,107 @@ +package dev.engine_room.flywheel.lib.model.part; + +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import dev.engine_room.flywheel.api.model.Model; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.PartPose; + +public class ModelTree { + private static final Map CACHE = new ConcurrentHashMap<>(); + + @Nullable + private final Model model; + private final PartPose initialPose; + private final ModelTree[] children; + private final String[] childNames; + + private ModelTree(@Nullable Model model, PartPose initialPose, ModelTree[] children, String[] childNames) { + this.model = model; + this.initialPose = initialPose; + this.children = children; + this.childNames = childNames; + } + + /** + * Create and memoize a ModelTree root. + * + *

This method is intended for use by Visuals. + * + * @param modelLayerLocation The model location to lower. + * @param loweringVisitor The visitor to use to lower the model. + * @return The cached ModelTree root. + */ + public static ModelTree of(ModelLayerLocation modelLayerLocation, LoweringVisitor loweringVisitor) { + return CACHE.computeIfAbsent(new ModelTreeKey(modelLayerLocation, loweringVisitor), k -> { + var meshTree = MeshTree.of(k.modelLayerLocation()); + + var out = k.loweringVisitor() + .visit("", meshTree); + + if (out == null) { + // Should this be an error, or a missing model? + return ModelTree.create(null, PartPose.ZERO, new ModelTree[0], new String[0]); + } + + return out; + }); + } + + /** + * Create a new ModelTree node. + * + *

This method is intended for use by {@link LoweringVisitor} implementations. + * + * @param model The model to associate with this node, or null if this node does not render. + * @param initialPose The initial pose of this node. + * @param children The children of this node. + * @param childNames The names of the children of this node. + * @return A new ModelTree node. + * @throws IllegalArgumentException if children and childNames have different lengths. + */ + public static ModelTree create(@Nullable Model model, PartPose initialPose, ModelTree[] children, String[] childNames) { + if (children.length != childNames.length) { + throw new IllegalArgumentException("children and childNames must have the same length (%s != %s)".formatted(children.length, childNames.length)); + } + + return new ModelTree(model, initialPose, children, childNames); + } + + public int childCount() { + return children.length; + } + + public ModelTree child(int index) { + return children[index]; + } + + public String childName(int index) { + return childNames[index]; + } + + public PartPose initialPose() { + return initialPose; + } + + @Nullable + public Model model() { + return model; + } + + public int childIndex(String name) { + return Arrays.binarySearch(childNames, name); + } + + @ApiStatus.Internal + public static void onEndClientResourceReload() { + CACHE.clear(); + } + + private record ModelTreeKey(ModelLayerLocation modelLayerLocation, LoweringVisitor loweringVisitor) { + } +} diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/ModelTreeCache.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/ModelTreeCache.java new file mode 100644 index 000000000..bf9274965 --- /dev/null +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/ModelTreeCache.java @@ -0,0 +1,15 @@ +package dev.engine_room.flywheel.lib.model.part; + +import java.util.function.Function; + +import dev.engine_room.flywheel.lib.model.ResourceReloadCache; + +/** + * If the lookup to create your model tree directly through {@link ModelTree#of} is particularly expensive, + * you can memoize the arguments here to hide the cost. + */ +public class ModelTreeCache extends ResourceReloadCache { + public ModelTreeCache(Function factory) { + super(factory); + } +} diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java index c5cb2af14..1d69910ed 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java @@ -7,16 +7,16 @@ import dev.engine_room.flywheel.api.instance.Instance; import dev.engine_room.flywheel.api.material.Material; -import dev.engine_room.flywheel.api.model.Model; import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.lib.material.SimpleMaterial; -import dev.engine_room.flywheel.lib.model.RetexturedMesh; +import dev.engine_room.flywheel.lib.model.ResourceReloadHolder; import dev.engine_room.flywheel.lib.model.part.InstanceTree; +import dev.engine_room.flywheel.lib.model.part.LoweringVisitor; +import dev.engine_room.flywheel.lib.model.part.ModelTree; import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.client.renderer.blockentity.BellRenderer; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; import net.minecraft.world.level.block.entity.BellBlockEntity; @@ -26,6 +26,9 @@ public class BellVisual extends AbstractBlockEntityVisual imple .mipmap(false) .build(); + // Need to hold the visitor in a ResourceReloadHolder to ensure we have a valid sprite. + private static final ResourceReloadHolder VISITOR = new ResourceReloadHolder<>(() -> LoweringVisitor.retexturingVisitor(MATERIAL, BellRenderer.BELL_RESOURCE_LOCATION.sprite())); + private final InstanceTree instances; private final InstanceTree bellBody; @@ -36,10 +39,7 @@ public class BellVisual extends AbstractBlockEntityVisual imple public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity, float partialTick) { super(ctx, blockEntity, partialTick); - TextureAtlasSprite sprite = BellRenderer.BELL_RESOURCE_LOCATION.sprite(); - instances = InstanceTree.create(instancerProvider(), ModelLayers.BELL, (path, mesh) -> { - return new Model.ConfiguredMesh(MATERIAL, new RetexturedMesh(mesh, sprite)); - }); + instances = InstanceTree.create(instancerProvider(), ModelTree.of(ModelLayers.BELL, VISITOR.get())); bellBody = instances.childOrThrow("bell_body"); BlockPos visualPos = getVisualPosition(); diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java index 90063c138..d6e0e6a88 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java @@ -4,6 +4,7 @@ import java.util.EnumMap; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Function; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; @@ -15,8 +16,11 @@ import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.lib.material.CutoutShaders; import dev.engine_room.flywheel.lib.material.SimpleMaterial; -import dev.engine_room.flywheel.lib.model.RetexturedMesh; +import dev.engine_room.flywheel.lib.model.ResourceReloadCache; import dev.engine_room.flywheel.lib.model.part.InstanceTree; +import dev.engine_room.flywheel.lib.model.part.LoweringVisitor; +import dev.engine_room.flywheel.lib.model.part.ModelTree; +import dev.engine_room.flywheel.lib.transform.TransformStack; import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; @@ -53,6 +57,8 @@ public class ChestVisual extends Abstrac LAYER_LOCATIONS.put(ChestType.RIGHT, ModelLayers.DOUBLE_CHEST_RIGHT); } + private static final Function VISITOR = new ResourceReloadCache<>(s -> LoweringVisitor.retexturingVisitor(MATERIAL, s)); + @Nullable private final InstanceTree instances; @Nullable @@ -77,10 +83,7 @@ public ChestVisual(VisualizationContext ctx, T blockEntity, float partialTick) { if (block instanceof AbstractChestBlock chestBlock) { ChestType chestType = blockState.hasProperty(ChestBlock.TYPE) ? blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE; TextureAtlasSprite sprite = Sheets.chooseMaterial(blockEntity, chestType, isChristmas()).sprite(); - - instances = InstanceTree.create(instancerProvider(), LAYER_LOCATIONS.get(chestType), (path, mesh) -> { - return new Model.ConfiguredMesh(MATERIAL, new RetexturedMesh(mesh, sprite)); - }); + instances = InstanceTree.create(instancerProvider(), ModelTree.of(LAYER_LOCATIONS.get(chestType), VISITOR.apply(sprite))); lid = instances.childOrThrow("lid"); lock = instances.childOrThrow("lock"); diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java index c7310c90e..4b0ad1891 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java @@ -14,6 +14,8 @@ import dev.engine_room.flywheel.lib.material.SimpleMaterial; import dev.engine_room.flywheel.lib.model.Models; import dev.engine_room.flywheel.lib.model.part.InstanceTree; +import dev.engine_room.flywheel.lib.model.part.LoweringVisitor; +import dev.engine_room.flywheel.lib.model.part.ModelTree; import dev.engine_room.flywheel.lib.visual.ComponentEntityVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import dev.engine_room.flywheel.lib.visual.SimpleTickableVisual; @@ -34,6 +36,7 @@ public class MinecartVisual extends ComponentEntityV .texture(TEXTURE) .mipmap(false) .build(); + private static final LoweringVisitor VISITOR = LoweringVisitor.materialApplyingVisitor(MATERIAL); private final InstanceTree instances; @Nullable @@ -47,7 +50,7 @@ public class MinecartVisual extends ComponentEntityV public MinecartVisual(VisualizationContext ctx, T entity, float partialTick, ModelLayerLocation layerLocation) { super(ctx, entity, partialTick); - instances = InstanceTree.create(instancerProvider(), layerLocation, MATERIAL); + instances = InstanceTree.create(instancerProvider(), ModelTree.of(layerLocation, VISITOR)); blockState = entity.getDisplayBlockState(); contents = createContentsInstance(); diff --git a/fabric/src/main/java/dev/engine_room/flywheel/impl/FlywheelFabric.java b/fabric/src/main/java/dev/engine_room/flywheel/impl/FlywheelFabric.java index d05ebb115..46c561fa8 100644 --- a/fabric/src/main/java/dev/engine_room/flywheel/impl/FlywheelFabric.java +++ b/fabric/src/main/java/dev/engine_room/flywheel/impl/FlywheelFabric.java @@ -9,10 +9,11 @@ import dev.engine_room.flywheel.backend.compile.FlwProgramsReloader; import dev.engine_room.flywheel.backend.engine.uniform.Uniforms; import dev.engine_room.flywheel.impl.visualization.VisualizationEventHandler; -import dev.engine_room.flywheel.lib.model.ModelCache; -import dev.engine_room.flywheel.lib.model.ModelHolder; +import dev.engine_room.flywheel.lib.model.ResourceReloadCache; +import dev.engine_room.flywheel.lib.model.ResourceReloadHolder; import dev.engine_room.flywheel.lib.model.baked.PartialModelEventHandler; import dev.engine_room.flywheel.lib.model.part.MeshTree; +import dev.engine_room.flywheel.lib.model.part.ModelTree; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents; @@ -68,12 +69,11 @@ private static void setupImpl() { } private static void setupLib() { - EndClientResourceReloadCallback.EVENT.register((minecraft, resourceManager, initialReload, error) -> - ModelCache.onEndClientResourceReload()); - EndClientResourceReloadCallback.EVENT.register((minecraft, resourceManager, initialReload, error) -> - ModelHolder.onEndClientResourceReload()); + EndClientResourceReloadCallback.EVENT.register((minecraft, resourceManager, initialReload, error) -> ResourceReloadCache.onEndClientResourceReload()); + EndClientResourceReloadCallback.EVENT.register((minecraft, resourceManager, initialReload, error) -> ResourceReloadHolder.onEndClientResourceReload()); EndClientResourceReloadCallback.EVENT.register((minecraft, resourceManager, initialReload, error) -> MeshTree.onEndClientResourceReload()); + EndClientResourceReloadCallback.EVENT.register((minecraft, resourceManager, initialReload, error) -> ModelTree.onEndClientResourceReload()); ModelLoadingPlugin.register(ctx -> { ctx.addModels(PartialModelEventHandler.onRegisterAdditional()); diff --git a/forge/src/main/java/dev/engine_room/flywheel/impl/FlywheelForge.java b/forge/src/main/java/dev/engine_room/flywheel/impl/FlywheelForge.java index 8fb860d6a..763324819 100644 --- a/forge/src/main/java/dev/engine_room/flywheel/impl/FlywheelForge.java +++ b/forge/src/main/java/dev/engine_room/flywheel/impl/FlywheelForge.java @@ -10,10 +10,11 @@ import dev.engine_room.flywheel.backend.compile.FlwProgramsReloader; import dev.engine_room.flywheel.backend.engine.uniform.Uniforms; import dev.engine_room.flywheel.impl.visualization.VisualizationEventHandler; -import dev.engine_room.flywheel.lib.model.ModelCache; -import dev.engine_room.flywheel.lib.model.ModelHolder; +import dev.engine_room.flywheel.lib.model.ResourceReloadCache; +import dev.engine_room.flywheel.lib.model.ResourceReloadHolder; import dev.engine_room.flywheel.lib.model.baked.PartialModelEventHandler; import dev.engine_room.flywheel.lib.model.part.MeshTree; +import dev.engine_room.flywheel.lib.model.part.ModelTree; import dev.engine_room.flywheel.lib.util.LevelAttached; import net.minecraft.client.Minecraft; import net.minecraft.commands.synchronization.ArgumentTypeInfos; @@ -110,9 +111,10 @@ private static void registerImplEventListeners(IEventBus forgeEventBus, IEventBu private static void registerLibEventListeners(IEventBus forgeEventBus, IEventBus modEventBus) { forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.invalidateLevel(e.getLevel())); - modEventBus.addListener((EndClientResourceReloadEvent e) -> ModelCache.onEndClientResourceReload()); - modEventBus.addListener((EndClientResourceReloadEvent e) -> ModelHolder.onEndClientResourceReload()); + modEventBus.addListener((EndClientResourceReloadEvent e) -> ResourceReloadCache.onEndClientResourceReload()); + modEventBus.addListener((EndClientResourceReloadEvent e) -> ResourceReloadHolder.onEndClientResourceReload()); modEventBus.addListener((EndClientResourceReloadEvent e) -> MeshTree.onEndClientResourceReload()); + modEventBus.addListener((EndClientResourceReloadEvent e) -> ModelTree.onEndClientResourceReload()); modEventBus.addListener(PartialModelEventHandler::onRegisterAdditional); modEventBus.addListener(PartialModelEventHandler::onBakingCompleted);