mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-24 20:07:54 +01:00
Home alone
- Remove LoweringVisitor - Move functionality of four main static methods in LoweringVisitor to new ModelTrees class - Return ModelTree directly - Accept Material instead of TextureAtlasSprite for efficiency, so visuals don't need to look up the sprite to get the ModelTree - Use ResourceReloadCache for MeshTree.CACHE
This commit is contained in:
parent
5a75fe972f
commit
62a0954381
11 changed files with 146 additions and 267 deletions
|
@ -1,128 +0,0 @@
|
|||
package dev.engine_room.flywheel.lib.model.part;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
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 create(Material material) {
|
||||
return (path, mesh) -> new SingleMeshModel(mesh, material);
|
||||
}
|
||||
|
||||
static LoweringVisitor create(Material material, TextureAtlasSprite sprite) {
|
||||
return (path, mesh) -> new SingleMeshModel(new RetexturedMesh(mesh, sprite), material);
|
||||
}
|
||||
|
||||
static LoweringVisitor pruning(Set<String> prune, Material material) {
|
||||
return new LoweringVisitor() {
|
||||
@Override
|
||||
public @Nullable ModelTree visit(String path, MeshTree meshTree) {
|
||||
if (prune.contains(path)) {
|
||||
return null;
|
||||
}
|
||||
return LoweringVisitor.super.visit(path, meshTree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model visit(String path, Mesh mesh) {
|
||||
return new SingleMeshModel(mesh, material);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static LoweringVisitor pruning(Set<String> prune, Material material, TextureAtlasSprite sprite) {
|
||||
return new LoweringVisitor() {
|
||||
@Override
|
||||
public @Nullable ModelTree visit(String path, MeshTree meshTree) {
|
||||
if (prune.contains(path)) {
|
||||
return null;
|
||||
}
|
||||
return LoweringVisitor.super.visit(path, meshTree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model visit(String path, Mesh mesh) {
|
||||
return 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<ModelTree> children = new ArrayList<>();
|
||||
ArrayList<String> 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);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,8 @@
|
|||
package dev.engine_room.flywheel.lib.model.part;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
@ -14,6 +10,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||
import dev.engine_room.flywheel.api.model.Mesh;
|
||||
import dev.engine_room.flywheel.lib.internal.FlwLibLink;
|
||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||
import dev.engine_room.flywheel.lib.model.ResourceReloadCache;
|
||||
import dev.engine_room.flywheel.lib.model.SimpleQuadMesh;
|
||||
import dev.engine_room.flywheel.lib.vertex.PosTexNormalVertexView;
|
||||
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||
|
@ -28,7 +25,7 @@ import net.minecraft.client.renderer.texture.OverlayTexture;
|
|||
public final class MeshTree {
|
||||
private static final ThreadLocal<ThreadLocalObjects> THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new);
|
||||
private static final PoseStack.Pose IDENTITY_POSE = new PoseStack().last();
|
||||
private static final Map<ModelLayerLocation, MeshTree> CACHE = new ConcurrentHashMap<>();
|
||||
private static final ResourceReloadCache<ModelLayerLocation, MeshTree> CACHE = new ResourceReloadCache<>(MeshTree::convert);
|
||||
|
||||
@Nullable
|
||||
private final Mesh mesh;
|
||||
|
@ -44,7 +41,7 @@ public final class MeshTree {
|
|||
}
|
||||
|
||||
public static MeshTree of(ModelLayerLocation layer) {
|
||||
return CACHE.computeIfAbsent(layer, MeshTree::convert);
|
||||
return CACHE.get(layer);
|
||||
}
|
||||
|
||||
private static MeshTree convert(ModelLayerLocation layer) {
|
||||
|
@ -58,9 +55,9 @@ public final class MeshTree {
|
|||
private static MeshTree convert(ModelPart modelPart, ThreadLocalObjects objects) {
|
||||
var modelPartChildren = FlwLibLink.INSTANCE.getModelPartChildren(modelPart);
|
||||
|
||||
// Freeze the ordering here. Maybe we want to sort this?
|
||||
String[] childNames = modelPartChildren.keySet()
|
||||
.toArray(String[]::new);
|
||||
Arrays.sort(childNames);
|
||||
|
||||
MeshTree[] children = new MeshTree[childNames.length];
|
||||
for (int i = 0; i < childNames.length; i++) {
|
||||
|
@ -135,20 +132,6 @@ public final class MeshTree {
|
|||
return child;
|
||||
}
|
||||
|
||||
public void traverse(Consumer<Mesh> consumer) {
|
||||
if (mesh != null) {
|
||||
consumer.accept(mesh);
|
||||
}
|
||||
for (MeshTree child : children) {
|
||||
child.traverse(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void onEndClientResourceReload() {
|
||||
CACHE.clear();
|
||||
}
|
||||
|
||||
private static class ThreadLocalObjects {
|
||||
public final VertexWriter vertexWriter = new VertexWriter();
|
||||
}
|
||||
|
|
|
@ -2,74 +2,50 @@ package dev.engine_room.flywheel.lib.model.part;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
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<ModelTreeKey, ModelTree> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
public final class ModelTree {
|
||||
@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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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));
|
||||
public ModelTree(@Nullable Model model, PartPose initialPose, Map<String, ModelTree> children) {
|
||||
this.model = model;
|
||||
this.initialPose = initialPose;
|
||||
|
||||
String[] childNames = children.keySet().toArray(String[]::new);
|
||||
Arrays.sort(childNames);
|
||||
|
||||
ModelTree[] childArray = new ModelTree[childNames.length];
|
||||
for (int i = 0; i < childNames.length; i++) {
|
||||
childArray[i] = children.get(childNames[i]);
|
||||
}
|
||||
|
||||
return new ModelTree(model, initialPose, children, childNames);
|
||||
this.children = childArray;
|
||||
this.childNames = childNames;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Model model() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public PartPose initialPose() {
|
||||
return initialPose;
|
||||
}
|
||||
|
||||
public int childCount() {
|
||||
|
@ -84,24 +60,32 @@ public class ModelTree {
|
|||
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();
|
||||
public boolean hasChild(String name) {
|
||||
return childIndex(name) >= 0;
|
||||
}
|
||||
|
||||
private record ModelTreeKey(ModelLayerLocation modelLayerLocation, LoweringVisitor loweringVisitor) {
|
||||
@Nullable
|
||||
public ModelTree child(String name) {
|
||||
int index = childIndex(name);
|
||||
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return child(index);
|
||||
}
|
||||
|
||||
public ModelTree childOrThrow(String name) {
|
||||
ModelTree child = child(name);
|
||||
|
||||
if (child == null) {
|
||||
throw new NoSuchElementException("Can't find part " + name);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
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<T> extends ResourceReloadCache<T, ModelTree> {
|
||||
public ModelTreeCache(Function<T, ModelTree> factory) {
|
||||
super(factory);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package dev.engine_room.flywheel.lib.model.part;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.ResourceReloadCache;
|
||||
import dev.engine_room.flywheel.lib.model.RetexturedMesh;
|
||||
import dev.engine_room.flywheel.lib.model.SingleMeshModel;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
|
||||
public final class ModelTrees {
|
||||
private static final ResourceReloadCache<ModelTreeKey, ModelTree> CACHE = new ResourceReloadCache<>(k -> {
|
||||
ModelTree tree = convert("", MeshTree.of(k.layer), k.pathsToPrune, k.texture != null ? k.texture.sprite() : null, k.material);
|
||||
|
||||
if (tree == null) {
|
||||
throw new IllegalArgumentException("Cannot prune root node!");
|
||||
}
|
||||
|
||||
return tree;
|
||||
});
|
||||
|
||||
private ModelTrees() {
|
||||
}
|
||||
|
||||
public static ModelTree of(ModelLayerLocation layer, Material material) {
|
||||
return CACHE.get(new ModelTreeKey(layer, Collections.emptySet(), null, material));
|
||||
}
|
||||
|
||||
public static ModelTree of(ModelLayerLocation layer, net.minecraft.client.resources.model.Material texture, Material material) {
|
||||
return CACHE.get(new ModelTreeKey(layer, Collections.emptySet(), texture, material));
|
||||
}
|
||||
|
||||
public static ModelTree of(ModelLayerLocation layer, Set<String> pathsToPrune, Material material) {
|
||||
return CACHE.get(new ModelTreeKey(layer, Set.copyOf(pathsToPrune), null, material));
|
||||
}
|
||||
|
||||
public static ModelTree of(ModelLayerLocation layer, Set<String> pathsToPrune, net.minecraft.client.resources.model.Material texture, Material material) {
|
||||
return CACHE.get(new ModelTreeKey(layer, Set.copyOf(pathsToPrune), texture, material));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ModelTree convert(String path, MeshTree meshTree, Set<String> pathsToPrune, @Nullable TextureAtlasSprite sprite, Material material) {
|
||||
if (pathsToPrune.contains(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Model model = null;
|
||||
Mesh mesh = meshTree.mesh();
|
||||
|
||||
if (mesh != null) {
|
||||
if (sprite != null) {
|
||||
mesh = new RetexturedMesh(mesh, sprite);
|
||||
}
|
||||
|
||||
model = new SingleMeshModel(mesh, material);
|
||||
}
|
||||
|
||||
Map<String, ModelTree> children = new HashMap<>();
|
||||
String pathSlash = path + "/";
|
||||
|
||||
for (int i = 0; i < meshTree.childCount(); i++) {
|
||||
String childName = meshTree.childName(i);
|
||||
var child = convert(pathSlash + childName, meshTree.child(i), pathsToPrune, sprite, material);
|
||||
|
||||
if (child != null) {
|
||||
children.put(childName, child);
|
||||
}
|
||||
}
|
||||
|
||||
return new ModelTree(model, meshTree.initialPose(), children);
|
||||
}
|
||||
|
||||
private record ModelTreeKey(ModelLayerLocation layer, Set<String> pathsToPrune, @Nullable net.minecraft.client.resources.model.Material texture, Material material) {
|
||||
}
|
||||
}
|
|
@ -9,10 +9,8 @@ import dev.engine_room.flywheel.api.instance.Instance;
|
|||
import dev.engine_room.flywheel.api.material.Material;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||
import dev.engine_room.flywheel.lib.material.SimpleMaterial;
|
||||
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.model.part.ModelTrees;
|
||||
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
|
||||
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
|
||||
import net.minecraft.client.model.geom.ModelLayers;
|
||||
|
@ -26,9 +24,6 @@ public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> imple
|
|||
.mipmap(false)
|
||||
.build();
|
||||
|
||||
// Need to hold the visitor in a ResourceReloadHolder to ensure we have a valid sprite.
|
||||
private static final ResourceReloadHolder<LoweringVisitor> VISITOR = new ResourceReloadHolder<>(() -> LoweringVisitor.create(MATERIAL, BellRenderer.BELL_RESOURCE_LOCATION.sprite()));
|
||||
|
||||
private final InstanceTree instances;
|
||||
private final InstanceTree bellBody;
|
||||
|
||||
|
@ -39,7 +34,7 @@ public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> imple
|
|||
public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity, float partialTick) {
|
||||
super(ctx, blockEntity, partialTick);
|
||||
|
||||
instances = InstanceTree.create(instancerProvider(), ModelTree.of(ModelLayers.BELL, VISITOR.get()));
|
||||
instances = InstanceTree.create(instancerProvider(), ModelTrees.of(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION, MATERIAL));
|
||||
bellBody = instances.childOrThrow("bell_body");
|
||||
|
||||
BlockPos visualPos = getVisualPosition();
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.util.Calendar;
|
|||
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,10 +14,8 @@ import dev.engine_room.flywheel.api.material.Material;
|
|||
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.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.model.part.ModelTrees;
|
||||
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
|
||||
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
|
||||
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
|
||||
|
@ -28,7 +25,6 @@ import net.minecraft.client.model.geom.ModelLayers;
|
|||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.util.Mth;
|
||||
|
@ -55,8 +51,6 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
|
|||
LAYER_LOCATIONS.put(ChestType.RIGHT, ModelLayers.DOUBLE_CHEST_RIGHT);
|
||||
}
|
||||
|
||||
private static final Function<TextureAtlasSprite, LoweringVisitor> VISITOR = new ResourceReloadCache<>(s -> LoweringVisitor.create(MATERIAL, s));
|
||||
|
||||
@Nullable
|
||||
private final InstanceTree instances;
|
||||
@Nullable
|
||||
|
@ -80,8 +74,8 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
|
|||
Block block = blockState.getBlock();
|
||||
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(), ModelTree.of(LAYER_LOCATIONS.get(chestType), VISITOR.apply(sprite)));
|
||||
net.minecraft.client.resources.model.Material texture = Sheets.chooseMaterial(blockEntity, chestType, isChristmas());
|
||||
instances = InstanceTree.create(instancerProvider(), ModelTrees.of(LAYER_LOCATIONS.get(chestType), texture, MATERIAL));
|
||||
lid = instances.childOrThrow("lid");
|
||||
lock = instances.childOrThrow("lock");
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@ import dev.engine_room.flywheel.lib.instance.TransformedInstance;
|
|||
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.model.part.ModelTrees;
|
||||
import dev.engine_room.flywheel.lib.visual.ComponentEntityVisual;
|
||||
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
|
||||
import dev.engine_room.flywheel.lib.visual.SimpleTickableVisual;
|
||||
|
@ -36,7 +35,6 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
|
|||
.texture(TEXTURE)
|
||||
.mipmap(false)
|
||||
.build();
|
||||
private static final LoweringVisitor VISITOR = LoweringVisitor.create(MATERIAL);
|
||||
|
||||
private final InstanceTree instances;
|
||||
@Nullable
|
||||
|
@ -50,7 +48,7 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
|
|||
public MinecartVisual(VisualizationContext ctx, T entity, float partialTick, ModelLayerLocation layerLocation) {
|
||||
super(ctx, entity, partialTick);
|
||||
|
||||
instances = InstanceTree.create(instancerProvider(), ModelTree.of(layerLocation, VISITOR));
|
||||
instances = InstanceTree.create(instancerProvider(), ModelTrees.of(layerLocation, MATERIAL));
|
||||
blockState = entity.getDisplayBlockState();
|
||||
contents = createContentsInstance();
|
||||
|
||||
|
|
|
@ -2,23 +2,20 @@ package dev.engine_room.flywheel.vanilla;
|
|||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
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.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.model.part.ModelTrees;
|
||||
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.Sheets;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
|
@ -26,15 +23,13 @@ import net.minecraft.world.level.block.ShulkerBoxBlock;
|
|||
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
|
||||
|
||||
public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockEntity> implements SimpleDynamicVisual {
|
||||
private static final dev.engine_room.flywheel.api.material.Material MATERIAL = SimpleMaterial.builder()
|
||||
private static final Material MATERIAL = SimpleMaterial.builder()
|
||||
.cutout(CutoutShaders.ONE_TENTH)
|
||||
.texture(Sheets.SHULKER_SHEET)
|
||||
.mipmap(false)
|
||||
.backfaceCulling(false)
|
||||
.build();
|
||||
|
||||
|
||||
private static final Function<Material, LoweringVisitor> VISITORS = new ResourceReloadCache<>(m -> LoweringVisitor.pruning(Set.of("head"), MATERIAL, m.sprite()));
|
||||
private static final Set<String> PATHS_TO_PRUNE = Set.of("/head");
|
||||
|
||||
private final InstanceTree instances;
|
||||
private final InstanceTree lid;
|
||||
|
@ -47,23 +42,22 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
|
|||
super(ctx, blockEntity, partialTick);
|
||||
|
||||
DyeColor color = blockEntity.getColor();
|
||||
Material texture;
|
||||
net.minecraft.client.resources.model.Material texture;
|
||||
if (color == null) {
|
||||
texture = Sheets.DEFAULT_SHULKER_TEXTURE_LOCATION;
|
||||
} else {
|
||||
texture = Sheets.SHULKER_TEXTURE_LOCATION.get(color.getId());
|
||||
}
|
||||
|
||||
instances = InstanceTree.create(instancerProvider(), ModelTree.of(ModelLayers.SHULKER, VISITORS.apply(texture)));
|
||||
instances = InstanceTree.create(instancerProvider(), ModelTrees.of(ModelLayers.SHULKER, PATHS_TO_PRUNE, texture, MATERIAL));
|
||||
lid = instances.childOrThrow("lid");
|
||||
|
||||
initialPose = createInitialPose();
|
||||
|
||||
lid = instances.childOrThrow("lid");
|
||||
}
|
||||
|
||||
private Matrix4f createInitialPose() {
|
||||
var rotation = getDirection().getRotation();
|
||||
var visualPosition = getVisualPosition();
|
||||
var rotation = getDirection().getRotation();
|
||||
return new Matrix4f().translate(visualPosition.getX(), visualPosition.getY(), visualPosition.getZ())
|
||||
.translate(0.5f, 0.5f, 0.5f)
|
||||
.scale(0.9995f)
|
||||
|
|
|
@ -12,8 +12,6 @@ import dev.engine_room.flywheel.impl.visualization.VisualizationEventHandler;
|
|||
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;
|
||||
|
@ -71,9 +69,6 @@ public final class FlywheelFabric implements ClientModInitializer {
|
|||
private static void setupLib() {
|
||||
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());
|
||||
|
|
|
@ -13,8 +13,6 @@ import dev.engine_room.flywheel.impl.visualization.VisualizationEventHandler;
|
|||
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;
|
||||
|
@ -113,8 +111,6 @@ public final class FlywheelForge {
|
|||
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue