diff --git a/common/build.gradle b/common/build.gradle index 061701ba7..d68cff3fb 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -6,9 +6,11 @@ dependencies { modCompileOnly "net.fabricmc:fabric-loader:$fabric_loader_version" compileOnly "com.google.code.findbugs:jsr305:3.0.2" + + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' } -test.configure { +test { useJUnitPlatform() } diff --git a/common/src/main/java/com/jozufozu/flywheel/api/internal/InternalFlywheelApi.java b/common/src/main/java/com/jozufozu/flywheel/api/internal/InternalFlywheelApi.java index 72c368630..cb88d5f63 100644 --- a/common/src/main/java/com/jozufozu/flywheel/api/internal/InternalFlywheelApi.java +++ b/common/src/main/java/com/jozufozu/flywheel/api/internal/InternalFlywheelApi.java @@ -12,8 +12,6 @@ import com.jozufozu.flywheel.api.vertex.VertexViewProvider; import com.jozufozu.flywheel.api.visualization.BlockEntityVisualizer; import com.jozufozu.flywheel.api.visualization.EntityVisualizer; import com.jozufozu.flywheel.api.visualization.VisualizationManager; -import com.jozufozu.flywheel.lib.transform.PoseTransformStack; -import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.world.entity.Entity; @@ -94,6 +92,4 @@ public interface InternalFlywheelApi { void setVisualizer(BlockEntityType type, BlockEntityVisualizer visualizer); void setVisualizer(EntityType type, EntityVisualizer visualizer); - - PoseTransformStack getPoseTransformStackOf(PoseStack stack); } diff --git a/common/src/main/java/com/jozufozu/flywheel/impl/InternalFlywheelImpl.java b/common/src/main/java/com/jozufozu/flywheel/impl/InternalFlywheelImpl.java index c32738e52..4dd9829f0 100644 --- a/common/src/main/java/com/jozufozu/flywheel/impl/InternalFlywheelImpl.java +++ b/common/src/main/java/com/jozufozu/flywheel/impl/InternalFlywheelImpl.java @@ -111,9 +111,4 @@ public final class InternalFlywheelImpl implements InternalFlywheelApi { public void setVisualizer(EntityType type, EntityVisualizer visualizer) { VisualizerRegistryImpl.setVisualizer(type, visualizer); } - - @Override - public PoseTransformStack getPoseTransformStackOf(PoseStack stack) { - return ((PoseStackExtension) stack).flywheel$transformStack(); - } } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/internal/FlywheelLibPlatform.java b/common/src/main/java/com/jozufozu/flywheel/lib/internal/FlywheelLibPlatform.java new file mode 100644 index 000000000..9413c94b9 --- /dev/null +++ b/common/src/main/java/com/jozufozu/flywheel/lib/internal/FlywheelLibPlatform.java @@ -0,0 +1,64 @@ +package com.jozufozu.flywheel.lib.internal; + +import java.lang.reflect.Constructor; + +import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.MultiBlockModelBuilder; +import com.jozufozu.flywheel.lib.transform.PoseTransformStack; +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +public interface FlywheelLibPlatform { + FlywheelLibPlatform INSTANCE = load(); + + // Adapted from https://github.com/CaffeineMC/sodium-fabric/blob/bf4fc9dab16e1cca07b2f23a1201c9bf237c8044/src/api/java/net/caffeinemc/mods/sodium/api/internal/DependencyInjection.java + private static FlywheelLibPlatform load() { + Class apiClass = FlywheelLibPlatform.class; + Class implClass; + + try { + implClass = Class.forName("com.jozufozu.flywheel.impl.FlywheelLibPlatformImpl"); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Could not find implementation", e); + } + + if (!apiClass.isAssignableFrom(implClass)) { + throw new RuntimeException("Class %s does not implement interface %s" + .formatted(implClass.getName(), apiClass.getName())); + } + + Constructor implConstructor; + + try { + implConstructor = implClass.getConstructor(); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Could not find default constructor", e); + } + + Object implInstance; + + try { + implInstance = implConstructor.newInstance(); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Could not instantiate implementation", e); + } + + return apiClass.cast(implInstance); + } + + PoseTransformStack getPoseTransformStackOf(PoseStack stack); + + BlockRenderDispatcher createVanillaRenderer(); + + BakedModelBuilder bakedModelBuilder(BakedModel bakedModel); + + BlockModelBuilder blockModelBuilder(BlockState state); + + MultiBlockModelBuilder multiBlockModelBuilder(BlockAndTintGetter level, Iterable positions); +} diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/internal/package-info.java b/common/src/main/java/com/jozufozu/flywheel/lib/internal/package-info.java new file mode 100644 index 000000000..b4efe3fa3 --- /dev/null +++ b/common/src/main/java/com/jozufozu/flywheel/lib/internal/package-info.java @@ -0,0 +1,12 @@ +@ApiStatus.Internal +@ParametersAreNonnullByDefault +@FieldsAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.lib.internal; + +import javax.annotation.ParametersAreNonnullByDefault; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.FieldsAreNonnullByDefault; +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java index dc2a155de..8a5797343 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.lib.model; -import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.util.Collection; @@ -8,8 +7,8 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.joml.Vector4f; import org.lwjgl.system.MemoryUtil; -import org.slf4j.Logger; +import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Model; @@ -22,43 +21,21 @@ import com.jozufozu.flywheel.lib.vertex.PosVertexView; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.BufferBuilder.DrawState; import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.logging.LogUtils; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraftforge.fml.util.ObfuscationReflectionHelper; public final class ModelUtil { - private static final Logger LOGGER = LogUtils.getLogger(); - /** * An alternative BlockRenderDispatcher that circumvents the Forge rendering pipeline to ensure consistency. * Meant to be used for virtual rendering. */ - public static final BlockRenderDispatcher VANILLA_RENDERER = createVanillaRenderer(); + public static final BlockRenderDispatcher VANILLA_RENDERER = FlywheelLibPlatform.INSTANCE.createVanillaRenderer(); private static final float BOUNDING_SPHERE_EPSILON = 1e-4f; private ModelUtil() { } - private static BlockRenderDispatcher createVanillaRenderer() { - BlockRenderDispatcher defaultDispatcher = Minecraft.getInstance().getBlockRenderer(); - BlockRenderDispatcher dispatcher = new BlockRenderDispatcher(null, null, null); - try { - for (Field field : BlockRenderDispatcher.class.getDeclaredFields()) { - field.setAccessible(true); - field.set(dispatcher, field.get(defaultDispatcher)); - } - ObfuscationReflectionHelper.setPrivateValue(BlockRenderDispatcher.class, dispatcher, new ModelBlockRenderer(Minecraft.getInstance().getBlockColors()), "f_110900_"); - } catch (Exception e) { - LOGGER.error("Failed to initialize vanilla BlockRenderDispatcher!", e); - return defaultDispatcher; - } - return dispatcher; - } - public static MemoryBlock convertVanillaBuffer(BufferBuilder.RenderedBuffer buffer, VertexView vertexView) { DrawState drawState = buffer.drawState(); int vertexCount = drawState.vertexCount(); diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/Models.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/Models.java index a0dbbd72e..ad821d6ee 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/Models.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/Models.java @@ -19,8 +19,10 @@ import net.minecraft.world.level.block.state.BlockState; * method with the same parameters will return the same object. */ public final class Models { - private static final ModelCache BLOCK_STATE = new ModelCache<>(it -> new BlockModelBuilder(it).build()); - private static final ModelCache PARTIAL = new ModelCache<>(it -> new BakedModelBuilder(it.get()).build()); + private static final ModelCache BLOCK_STATE = new ModelCache<>(it -> BlockModelBuilder.create(it) + .build()); + private static final ModelCache PARTIAL = new ModelCache<>(it -> BakedModelBuilder.create(it.get()) + .build()); private static final ModelCache> TRANSFORMED_PARTIAL = new ModelCache<>(TransformedPartial::create); private Models() { @@ -85,7 +87,7 @@ public final class Models { private Model create() { var stack = new PoseStack(); transformer.accept(key, stack); - return new BakedModelBuilder(partial.get()) + return BakedModelBuilder.create(partial.get()) .poseStack(stack) .build(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java index 550c54cce..238aedd9e 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java @@ -8,11 +8,12 @@ import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.vertex.VertexView; +import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.SimpleMesh; import com.jozufozu.flywheel.lib.model.SimpleModel; -import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer; import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView; import com.mojang.blaze3d.vertex.PoseStack; @@ -21,22 +22,23 @@ import net.minecraft.client.resources.model.BakedModel; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.data.ModelData; -public class BakedModelBuilder { - private final BakedModel bakedModel; +public abstract class BakedModelBuilder { + protected final BakedModel bakedModel; @Nullable - private BlockAndTintGetter level; + protected BlockAndTintGetter level; @Nullable - private BlockState blockState; + protected BlockState blockState; @Nullable - private PoseStack poseStack; + protected PoseStack poseStack; @Nullable - private ModelData modelData; - @Nullable - private BiFunction materialFunc; + protected BiFunction materialFunc; - public BakedModelBuilder(BakedModel bakedModel) { + public static BakedModelBuilder create(BakedModel bakedModel) { + return FlywheelLibPlatform.INSTANCE.bakedModelBuilder(bakedModel); + } + + protected BakedModelBuilder(BakedModel bakedModel) { this.bakedModel = bakedModel; } @@ -55,43 +57,10 @@ public class BakedModelBuilder { return this; } - public BakedModelBuilder modelData(ModelData modelData) { - this.modelData = modelData; - return this; - } - public BakedModelBuilder materialFunc(BiFunction materialFunc) { this.materialFunc = materialFunc; return this; } - public SimpleModel build() { - if (level == null) { - level = VirtualEmptyBlockGetter.INSTANCE; - } - if (blockState == null) { - blockState = Blocks.AIR.defaultBlockState(); - } - if (modelData == null) { - modelData = ModelData.EMPTY; - } - if (materialFunc == null) { - materialFunc = ModelUtil::getMaterial; - } - - var out = ImmutableList.builder(); - - ResultConsumer resultConsumer = (renderType, shaded, data) -> { - Material material = materialFunc.apply(renderType, shaded); - if (material != null) { - VertexView vertexView = new NoOverlayVertexView(); - MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); - var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded); - out.add(new Model.ConfiguredMesh(material, mesh)); - } - }; - BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, modelData, resultConsumer); - - return new SimpleModel(out.build()); - } + public abstract SimpleModel build(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java index c0e16e7db..7058735d8 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java @@ -8,31 +8,33 @@ import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.vertex.VertexView; +import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.SimpleMesh; import com.jozufozu.flywheel.lib.model.SimpleModel; -import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer; import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.RenderType; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.data.ModelData; -public class BlockModelBuilder { - private final BlockState state; +public abstract class BlockModelBuilder { + protected final BlockState state; @Nullable - private BlockAndTintGetter level; + protected BlockAndTintGetter level; @Nullable - private PoseStack poseStack; + protected PoseStack poseStack; @Nullable - private ModelData modelData; - @Nullable - private BiFunction materialFunc; + protected BiFunction materialFunc; - public BlockModelBuilder(BlockState state) { + public static BlockModelBuilder create(BlockState state) { + return FlywheelLibPlatform.INSTANCE.blockModelBuilder(state); + } + + protected BlockModelBuilder(BlockState state) { this.state = state; } @@ -46,40 +48,10 @@ public class BlockModelBuilder { return this; } - public BlockModelBuilder modelData(ModelData modelData) { - this.modelData = modelData; - return this; - } - public BlockModelBuilder materialFunc(BiFunction materialFunc) { this.materialFunc = materialFunc; return this; } - public SimpleModel build() { - if (level == null) { - level = VirtualEmptyBlockGetter.INSTANCE; - } - if (modelData == null) { - modelData = ModelData.EMPTY; - } - if (materialFunc == null) { - materialFunc = ModelUtil::getMaterial; - } - - var out = ImmutableList.builder(); - - ResultConsumer resultConsumer = (renderType, shaded, data) -> { - Material material = materialFunc.apply(renderType, shaded); - if (material != null) { - VertexView vertexView = new NoOverlayVertexView(); - MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); - var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded); - out.add(new Model.ConfiguredMesh(material, mesh)); - } - }; - BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, modelData, resultConsumer); - - return new SimpleModel(out.build()); - } + public abstract SimpleModel build(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java index caa332875..b8d5be399 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java @@ -17,14 +17,14 @@ class MeshEmitter implements VertexConsumer { private boolean lastQuadWasShaded; private boolean seenFirstQuad; @Nullable - private BakedModelBufferer.ResultConsumer resultConsumer; + private MeshEmitter.ResultConsumer resultConsumer; MeshEmitter(BufferBuilder bufferBuilder, RenderType renderType) { this.bufferBuilder = bufferBuilder; this.renderType = renderType; } - public void begin(BakedModelBufferer.ResultConsumer resultConsumer) { + public void begin(ResultConsumer resultConsumer) { this.resultConsumer = resultConsumer; begin(); @@ -112,4 +112,8 @@ class MeshEmitter implements VertexConsumer { public void unsetDefaultColor() { throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); } + + public interface ResultConsumer { + void accept(RenderType renderType, boolean shaded, BufferBuilder.RenderedBuffer data); + } } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java index f372d36ba..61d46ae95 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java @@ -1,39 +1,32 @@ package com.jozufozu.flywheel.lib.model.baked; import java.util.function.BiFunction; -import java.util.function.Function; import org.jetbrains.annotations.Nullable; -import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.api.model.Model; -import com.jozufozu.flywheel.api.vertex.VertexView; -import com.jozufozu.flywheel.lib.memory.MemoryBlock; -import com.jozufozu.flywheel.lib.model.ModelUtil; -import com.jozufozu.flywheel.lib.model.SimpleMesh; +import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform; import com.jozufozu.flywheel.lib.model.SimpleModel; -import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer; -import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraftforge.client.model.data.ModelData; -public class MultiBlockModelBuilder { - private final BlockAndTintGetter level; - private final Iterable positions; +public abstract class MultiBlockModelBuilder { + protected final BlockAndTintGetter level; + protected final Iterable positions; @Nullable - private PoseStack poseStack; + protected PoseStack poseStack; + protected boolean renderFluids = false; @Nullable - private Function modelDataLookup; - private boolean renderFluids = false; - @Nullable - private BiFunction materialFunc; + protected BiFunction materialFunc; - public MultiBlockModelBuilder(BlockAndTintGetter level, Iterable positions) { + public static MultiBlockModelBuilder create(BlockAndTintGetter level, Iterable positions) { + return FlywheelLibPlatform.INSTANCE.multiBlockModelBuilder(level, positions); + } + + protected MultiBlockModelBuilder(BlockAndTintGetter level, Iterable positions) { this.level = level; this.positions = positions; } @@ -43,11 +36,6 @@ public class MultiBlockModelBuilder { return this; } - public MultiBlockModelBuilder modelDataLookup(Function modelDataLookup) { - this.modelDataLookup = modelDataLookup; - return this; - } - public MultiBlockModelBuilder enableFluidRendering() { renderFluids = true; return this; @@ -58,27 +46,5 @@ public class MultiBlockModelBuilder { return this; } - public SimpleModel build() { - if (modelDataLookup == null) { - modelDataLookup = pos -> ModelData.EMPTY; - } - if (materialFunc == null) { - materialFunc = ModelUtil::getMaterial; - } - - var out = ImmutableList.builder(); - - ResultConsumer resultConsumer = (renderType, shaded, data) -> { - Material material = materialFunc.apply(renderType, shaded); - if (material != null) { - VertexView vertexView = new NoOverlayVertexView(); - MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); - var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded); - out.add(new Model.ConfiguredMesh(material, mesh)); - } - }; - BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, modelDataLookup, renderFluids, resultConsumer); - - return new SimpleModel(out.build()); - } + public abstract SimpleModel build(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModel.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModel.java index c8fc27a0c..48ce637be 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModel.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModel.java @@ -5,7 +5,6 @@ import java.util.List; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.event.ModelEvent; /** * A helper class for loading and accessing json models. @@ -19,8 +18,8 @@ import net.minecraftforge.client.event.ModelEvent; * Attempting to create a PartialModel after {@link ModelEvent.RegisterAdditional} will cause an error. */ public class PartialModel { - private static final List ALL = new ArrayList<>(); - private static boolean tooLate = false; + static final List ALL = new ArrayList<>(); + static boolean tooLate = false; protected final ResourceLocation modelLocation; protected BakedModel bakedModel; @@ -34,30 +33,11 @@ public class PartialModel { ALL.add(this); } - public static void onModelRegistry(ModelEvent.RegisterAdditional event) { - for (PartialModel partial : ALL) { - event.register(partial.getLocation()); - } - - tooLate = true; - } - - public static void onModelBake(ModelEvent.BakingCompleted event) { - var modelRegistry = event.getModels(); - for (PartialModel partial : ALL) { - partial.set(modelRegistry.get(partial.getLocation())); - } - } - public String getName() { return getLocation() .toString(); } - protected void set(BakedModel bakedModel) { - this.bakedModel = bakedModel; - } - public ResourceLocation getLocation() { return modelLocation; } @@ -65,4 +45,8 @@ public class PartialModel { public BakedModel get() { return bakedModel; } + + void set(BakedModel bakedModel) { + this.bakedModel = bakedModel; + } } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/transform/TransformStack.java b/common/src/main/java/com/jozufozu/flywheel/lib/transform/TransformStack.java index 306972421..2d2db3a3c 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/transform/TransformStack.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/transform/TransformStack.java @@ -1,11 +1,11 @@ package com.jozufozu.flywheel.lib.transform; -import com.jozufozu.flywheel.api.internal.InternalFlywheelApi; +import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform; import com.mojang.blaze3d.vertex.PoseStack; public interface TransformStack> extends Transform { static PoseTransformStack of(PoseStack stack) { - return InternalFlywheelApi.INSTANCE.getPoseTransformStackOf(stack); + return FlywheelLibPlatform.INSTANCE.getPoseTransformStackOf(stack); } Self pushPose(); diff --git a/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java b/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java index e96eb55f2..8905e734b 100644 --- a/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java +++ b/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java @@ -19,7 +19,7 @@ import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler; import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; import com.jozufozu.flywheel.lib.model.ModelCache; import com.jozufozu.flywheel.lib.model.ModelHolder; -import com.jozufozu.flywheel.lib.model.baked.PartialModel; +import com.jozufozu.flywheel.lib.model.baked.PartialModelEventHandler; import com.jozufozu.flywheel.lib.util.LevelAttached; import com.jozufozu.flywheel.lib.util.StringUtil; @@ -98,8 +98,8 @@ public class FlywheelForge { modEventBus.addListener($ -> ModelCache.onEndClientResourceReload()); modEventBus.addListener($ -> ModelHolder.onEndClientResourceReload()); - modEventBus.addListener(PartialModel::onModelRegistry); - modEventBus.addListener(PartialModel::onModelBake); + modEventBus.addListener(PartialModelEventHandler::onModelRegistry); + modEventBus.addListener(PartialModelEventHandler::onModelBake); Flywheel.earlyInit(); CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString); diff --git a/forge/src/main/java/com/jozufozu/flywheel/impl/FlywheelLibPlatformImpl.java b/forge/src/main/java/com/jozufozu/flywheel/impl/FlywheelLibPlatformImpl.java new file mode 100644 index 000000000..547375265 --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/impl/FlywheelLibPlatformImpl.java @@ -0,0 +1,67 @@ +package com.jozufozu.flywheel.impl; + +import java.lang.reflect.Field; + +import org.slf4j.Logger; + +import com.jozufozu.flywheel.impl.extension.PoseStackExtension; +import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.ForgeBakedModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.ForgeBlockModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.ForgeMultiBlockModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.MultiBlockModelBuilder; +import com.jozufozu.flywheel.lib.transform.PoseTransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.logging.LogUtils; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; + +public class FlywheelLibPlatformImpl implements FlywheelLibPlatform { + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public PoseTransformStack getPoseTransformStackOf(PoseStack stack) { + return ((PoseStackExtension) stack).flywheel$transformStack(); + } + + @Override + public BlockRenderDispatcher createVanillaRenderer() { + BlockRenderDispatcher defaultDispatcher = Minecraft.getInstance().getBlockRenderer(); + BlockRenderDispatcher dispatcher = new BlockRenderDispatcher(null, null, null); + try { + for (Field field : BlockRenderDispatcher.class.getDeclaredFields()) { + field.setAccessible(true); + field.set(dispatcher, field.get(defaultDispatcher)); + } + ObfuscationReflectionHelper.setPrivateValue(BlockRenderDispatcher.class, dispatcher, new ModelBlockRenderer(Minecraft.getInstance().getBlockColors()), "f_110900_"); + } catch (Exception e) { + LOGGER.error("Failed to initialize vanilla BlockRenderDispatcher!", e); + return defaultDispatcher; + } + return dispatcher; + } + + @Override + public BakedModelBuilder bakedModelBuilder(BakedModel bakedModel) { + return new ForgeBakedModelBuilder(bakedModel); + } + + @Override + public BlockModelBuilder blockModelBuilder(BlockState state) { + return new ForgeBlockModelBuilder(state); + } + + @Override + public MultiBlockModelBuilder multiBlockModelBuilder(BlockAndTintGetter level, Iterable positions) { + return new ForgeMultiBlockModelBuilder(level, positions); + } +} diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java similarity index 92% rename from common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java rename to forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java index dcfa860f7..c454aaf52 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java +++ b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java @@ -33,7 +33,7 @@ final class BakedModelBufferer { private BakedModelBufferer() { } - public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ResultConsumer resultConsumer) { + public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, MeshEmitter.ResultConsumer resultConsumer) { ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; @@ -59,7 +59,7 @@ final class BakedModelBufferer { } } - public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter level, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ResultConsumer resultConsumer) { + public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter level, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, MeshEmitter.ResultConsumer resultConsumer) { if (state.getRenderShape() != RenderShape.MODEL) { return; } @@ -67,7 +67,7 @@ final class BakedModelBufferer { bufferSingle(renderDispatcher.getModelRenderer(), level, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer); } - public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator posIterator, BlockAndTintGetter level, @Nullable PoseStack poseStack, Function modelDataLookup, boolean renderFluids, ResultConsumer resultConsumer) { + public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator posIterator, BlockAndTintGetter level, @Nullable PoseStack poseStack, Function modelDataLookup, boolean renderFluids, MeshEmitter.ResultConsumer resultConsumer) { ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; @@ -142,13 +142,13 @@ final class BakedModelBufferer { public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer(); - public final MeshEmitter[] emitters = new MeshEmitter[CHUNK_LAYER_AMOUNT]; + public final ForgeMeshEmitter[] emitters = new ForgeMeshEmitter[CHUNK_LAYER_AMOUNT]; { for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { var renderType = CHUNK_LAYERS[layerIndex]; var buffer = new BufferBuilder(renderType.bufferSize()); - emitters[layerIndex] = new MeshEmitter(buffer, renderType); + emitters[layerIndex] = new ForgeMeshEmitter(buffer, renderType); } } } diff --git a/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeBakedModelBuilder.java b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeBakedModelBuilder.java new file mode 100644 index 000000000..e313a8aa7 --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeBakedModelBuilder.java @@ -0,0 +1,62 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.model.Model; +import com.jozufozu.flywheel.api.vertex.VertexView; +import com.jozufozu.flywheel.lib.memory.MemoryBlock; +import com.jozufozu.flywheel.lib.model.ModelUtil; +import com.jozufozu.flywheel.lib.model.SimpleMesh; +import com.jozufozu.flywheel.lib.model.SimpleModel; +import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer; +import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView; + +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.world.level.block.Blocks; +import net.minecraftforge.client.model.data.ModelData; + +public class ForgeBakedModelBuilder extends BakedModelBuilder { + @Nullable + private ModelData modelData; + + public ForgeBakedModelBuilder(BakedModel bakedModel) { + super(bakedModel); + } + + public ForgeBakedModelBuilder modelData(ModelData modelData) { + this.modelData = modelData; + return this; + } + + public SimpleModel build() { + if (level == null) { + level = VirtualEmptyBlockGetter.INSTANCE; + } + if (blockState == null) { + blockState = Blocks.AIR.defaultBlockState(); + } + if (modelData == null) { + modelData = ModelData.EMPTY; + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + var out = ImmutableList.builder(); + + ResultConsumer resultConsumer = (renderType, shaded, data) -> { + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + VertexView vertexView = new NoOverlayVertexView(); + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); + var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded); + out.add(new Model.ConfiguredMesh(material, mesh)); + } + }; + BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, modelData, resultConsumer); + + return new SimpleModel(out.build()); + } +} diff --git a/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeBlockModelBuilder.java b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeBlockModelBuilder.java new file mode 100644 index 000000000..017480a30 --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeBlockModelBuilder.java @@ -0,0 +1,58 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.model.Model; +import com.jozufozu.flywheel.api.vertex.VertexView; +import com.jozufozu.flywheel.lib.memory.MemoryBlock; +import com.jozufozu.flywheel.lib.model.ModelUtil; +import com.jozufozu.flywheel.lib.model.SimpleMesh; +import com.jozufozu.flywheel.lib.model.SimpleModel; +import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer; +import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView; + +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.ModelData; + +public class ForgeBlockModelBuilder extends BlockModelBuilder { + @Nullable + private ModelData modelData; + + public ForgeBlockModelBuilder(BlockState state) { + super(state); + } + + public ForgeBlockModelBuilder modelData(ModelData modelData) { + this.modelData = modelData; + return this; + } + + public SimpleModel build() { + if (level == null) { + level = VirtualEmptyBlockGetter.INSTANCE; + } + if (modelData == null) { + modelData = ModelData.EMPTY; + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + var out = ImmutableList.builder(); + + ResultConsumer resultConsumer = (renderType, shaded, data) -> { + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + VertexView vertexView = new NoOverlayVertexView(); + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); + var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded); + out.add(new Model.ConfiguredMesh(material, mesh)); + } + }; + BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, modelData, resultConsumer); + + return new SimpleModel(out.build()); + } +} diff --git a/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeMultiBlockModelBuilder.java b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeMultiBlockModelBuilder.java new file mode 100644 index 000000000..bc4bc05cc --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeMultiBlockModelBuilder.java @@ -0,0 +1,58 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import java.util.function.Function; + +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.model.Model; +import com.jozufozu.flywheel.api.vertex.VertexView; +import com.jozufozu.flywheel.lib.memory.MemoryBlock; +import com.jozufozu.flywheel.lib.model.ModelUtil; +import com.jozufozu.flywheel.lib.model.SimpleMesh; +import com.jozufozu.flywheel.lib.model.SimpleModel; +import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer; +import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraftforge.client.model.data.ModelData; + +public class ForgeMultiBlockModelBuilder extends MultiBlockModelBuilder { + @Nullable + private Function modelDataLookup; + + public ForgeMultiBlockModelBuilder(BlockAndTintGetter level, Iterable positions) { + super(level, positions); + } + + public ForgeMultiBlockModelBuilder modelDataLookup(Function modelDataLookup) { + this.modelDataLookup = modelDataLookup; + return this; + } + + public SimpleModel build() { + if (modelDataLookup == null) { + modelDataLookup = pos -> ModelData.EMPTY; + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + var out = ImmutableList.builder(); + + ResultConsumer resultConsumer = (renderType, shaded, data) -> { + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + VertexView vertexView = new NoOverlayVertexView(); + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); + var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded); + out.add(new Model.ConfiguredMesh(material, mesh)); + } + }; + BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, modelDataLookup, renderFluids, resultConsumer); + + return new SimpleModel(out.build()); + } +} diff --git a/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModelEventHandler.java b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModelEventHandler.java new file mode 100644 index 000000000..0c2f4d57a --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModelEventHandler.java @@ -0,0 +1,20 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import net.minecraftforge.client.event.ModelEvent; + +public class PartialModelEventHandler { + public static void onModelRegistry(ModelEvent.RegisterAdditional event) { + for (PartialModel partial : PartialModel.ALL) { + event.register(partial.getLocation()); + } + + PartialModel.tooLate = true; + } + + public static void onModelBake(ModelEvent.BakingCompleted event) { + var modelRegistry = event.getModels(); + for (PartialModel partial : PartialModel.ALL) { + partial.set(modelRegistry.get(partial.getLocation())); + } + } +}