Merge remote-tracking branch 'origin/1.19/dev' into 1.19/fabric/dev

Conflicts:
	build.gradle
	gradle.properties
	src/main/java/com/jozufozu/flywheel/Flywheel.java
	src/main/java/com/jozufozu/flywheel/backend/Loader.java
	src/main/java/com/jozufozu/flywheel/config/FlwCommands.java
	src/main/java/com/jozufozu/flywheel/core/PartialModel.java
	src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java
	src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java
	src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java
	src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java
	src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java
	src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java
	src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java
	src/main/java/com/jozufozu/flywheel/util/RenderMath.java
	src/main/resources/META-INF/mods.toml
	src/main/resources/pack.mcmeta
This commit is contained in:
PepperCode1 2022-11-11 00:11:58 -08:00
commit 954d1d77fb
30 changed files with 393 additions and 187 deletions

View file

@ -61,7 +61,8 @@ dependencies {
// Fabric API
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
modCompileOnly 'curse.maven:starlight-521783:3667443'
// switch to implementation for debugging
modCompileOnly 'maven.modrinth:starlight:1.1.1+1.19'
modCompileOnly 'maven.modrinth:iris:1.18.x-v1.2.5'
modCompileOnly 'maven.modrinth:sodium:mc1.18.2-0.4.1'
@ -155,6 +156,6 @@ curseforge {
changelog = file('changelog.txt')
releaseType = project.curse_type
mainArtifact jar
addGameVersion '1.18.2'
addGameVersion '1.19.2'
}
}

View file

@ -3,11 +3,11 @@ org.gradle.daemon = false
# mod version info
mod_version = 0.6.8
artifact_minecraft_version = 1.18.2
artifact_minecraft_version = 1.19.2
minecraft_version = 1.18.2
minecraft_version = 1.19.2
loader_version = 0.14.9
fabric_version = 0.66.0+1.18.2
fabric_version = 0.66.0+1.19.2
# build dependency versions
loom_version = 1.0-SNAPSHOT

View file

@ -7,6 +7,7 @@ import com.jozufozu.flywheel.backend.Loader;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.backend.ShadersModHandler;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.config.FlwCommands;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.PartialModel;
@ -21,6 +22,7 @@ import com.jozufozu.flywheel.vanilla.VanillaInstances;
import com.mojang.logging.LogUtils;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
@ -55,6 +57,7 @@ public class Flywheel implements ClientModInitializer {
ShadersModHandler.init();
Backend.init();
ClientCommandRegistrationCallback.EVENT.register(FlwCommands::registerClientCommands);
FlywheelEvents.RELOAD_RENDERERS.register(ProgramCompiler::invalidateAll);
FlywheelEvents.GATHER_CONTEXT.register(Contexts::flwInit);

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.backend;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -90,11 +90,11 @@ public class Loader {
private void loadProgramSpecs(ResourceManager manager) {
programs.clear();
Collection<ResourceLocation> programSpecs = manager.listResources(PROGRAM_DIR, s -> s.endsWith(".json"));
Map<ResourceLocation, Resource> programSpecs = manager.listResources(PROGRAM_DIR, loc -> loc.getPath().endsWith(".json"));
for (ResourceLocation location : programSpecs) {
try (Resource resource = manager.getResource(location)) {
String s = StringUtil.readToString(resource.getInputStream());
programSpecs.forEach((location, resource) -> {
try (InputStream inputStream = resource.open()) {
String s = StringUtil.readToString(inputStream);
ResourceLocation specName = ResourceUtil.trim(location, PROGRAM_DIR, ".json");
@ -114,7 +114,7 @@ public class Loader {
} catch (Exception e) {
Backend.LOGGER.error("Could not load program " + location, e);
}
}
});
}
public static class ResourceReloadListener implements ResourceManagerReloadListener, IdentifiableResourceReloadListener {

View file

@ -1,50 +0,0 @@
package com.jozufozu.flywheel.config;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.network.chat.TranslatableComponent;
public enum BackendTypeArgument implements ArgumentType<BackendType> {
INSTANCE;
private static final Dynamic2CommandExceptionType INVALID = new Dynamic2CommandExceptionType((found, constants) -> {
// TODO: don't steal lang
return new TranslatableComponent("commands.forge.arguments.enum.invalid", constants, found);
});
@Override
public BackendType parse(StringReader reader) throws CommandSyntaxException {
String string = reader.readUnquotedString();
BackendType engine = BackendType.byName(string);
if (engine == null) {
throw INVALID.createWithContext(reader, string, BackendType.validNames());
}
return engine;
}
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return SharedSuggestionProvider.suggest(BackendType.validNames(), builder);
}
@Override
public Collection<String> getExamples() {
return BackendType.validNames();
}
public static BackendTypeArgument getInstance() {
return INSTANCE;
}
}

View file

@ -8,17 +8,20 @@ import org.jetbrains.annotations.NotNull;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.config.Option.EnumOption;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
public final class FlwCommands {
public static void init(FlwConfig config) {
public static void registerClientCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandBuildContext context) {
FlwConfig config = FlwConfig.get();
ConfigCommandBuilder commandBuilder = new ConfigCommandBuilder("flywheel");
commandBuilder.addOption(config.backend, (builder, option) -> enumOptionCommand(builder, config, option,
@ -34,27 +37,27 @@ public final class FlwCommands {
commandBuilder.addOption(config.debugNormals, (builder, option) -> booleanOptionCommand(builder, config, option,
(source, value) -> {
Component text = new TextComponent("Normal debug mode is currently: ").append(boolToText(value));
Component text = Component.literal("Normal debug mode is currently: ").append(boolToText(value));
source.sendFeedback(text);
},
(source, value) -> {
Component text = boolToText(value).append(new TextComponent(" normal debug mode").withStyle(ChatFormatting.WHITE));
Component text = boolToText(value).append(Component.literal(" normal debug mode").withStyle(ChatFormatting.WHITE));
source.sendFeedback(text);
}
));
commandBuilder.addOption(config.limitUpdates, (builder, option) -> booleanOptionCommand(builder, config, option,
(source, value) -> {
Component text = new TextComponent("Update limiting is currently: ").append(boolToText(value));
Component text = Component.literal("Update limiting is currently: ").append(boolToText(value));
source.sendFeedback(text);
},
(source, value) -> {
Component text = boolToText(value).append(new TextComponent(" update limiting.").withStyle(ChatFormatting.WHITE));
Component text = boolToText(value).append(Component.literal(" update limiting.").withStyle(ChatFormatting.WHITE));
source.sendFeedback(text);
}
));
commandBuilder.build();
commandBuilder.build(dispatcher);
}
public static void booleanOptionCommand(LiteralArgumentBuilder<FabricClientCommandSource> builder, FlwConfig config, Option<Boolean> option, BiConsumer<FabricClientCommandSource, Boolean> displayAction, BiConsumer<FabricClientCommandSource, Boolean> setAction) {
@ -96,14 +99,14 @@ public final class FlwCommands {
}
public static MutableComponent boolToText(boolean b) {
return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN) : new TextComponent("disabled").withStyle(ChatFormatting.RED);
return b ? Component.literal("enabled").withStyle(ChatFormatting.DARK_GREEN) : Component.literal("disabled").withStyle(ChatFormatting.RED);
}
public static Component getEngineMessage(@NotNull BackendType type) {
return switch (type) {
case OFF -> new TextComponent("Disabled Flywheel").withStyle(ChatFormatting.RED);
case INSTANCING -> new TextComponent("Using Instancing Engine").withStyle(ChatFormatting.GREEN);
case BATCHING -> new TextComponent("Using Batching Engine").withStyle(ChatFormatting.GREEN);
case OFF -> Component.literal("Disabled Flywheel").withStyle(ChatFormatting.RED);
case INSTANCING -> Component.literal("Using Instancing Engine").withStyle(ChatFormatting.GREEN);
case BATCHING -> Component.literal("Using Batching Engine").withStyle(ChatFormatting.GREEN);
};
}
@ -124,8 +127,8 @@ public final class FlwCommands {
command.then(builder);
}
public void build() {
ClientCommandManager.DISPATCHER.register(command);
public void build(CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(command);
}
}
}

View file

@ -51,7 +51,6 @@ public class FlwConfig {
public static void init() {
INSTANCE.load();
FlwCommands.init(INSTANCE);
}
public BackendType getBackendType() {

View file

@ -22,10 +22,10 @@ import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
* Creating a PartialModel will make the associated modelLocation automatically load.
* PartialModels must be initialized the mod class constructor.
* <br>
* Once {@link ModelBakeEvent} finishes, all PartialModels (with valid modelLocations)
* Once {@link ModelEvent.BakingCompleted} finishes, all PartialModels (with valid modelLocations)
* will have their bakedModel fields populated.
* <br>
* Attempting to create a PartialModel after {@link ModelRegistryEvent} will cause an error.
* Attempting to create a PartialModel after {@link ModelEvent.RegisterAdditional} will cause an error.
*/
public class PartialModel {
@ -36,7 +36,7 @@ public class PartialModel {
protected BakedModel bakedModel;
public PartialModel(ResourceLocation modelLocation) {
if (tooLate) throw new RuntimeException("PartialModel '" + modelLocation + "' loaded after ModelRegistryEvent");
if (tooLate) throw new RuntimeException("PartialModel '" + modelLocation + "' loaded after ModelEvent.RegisterAdditional");
this.modelLocation = modelLocation;
ALL.add(this);

View file

@ -1,8 +1,6 @@
package com.jozufozu.flywheel.core.model;
import java.util.Random;
import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter;
import com.jozufozu.flywheel.fabric.model.DefaultLayerFilteringBakedModel;
import com.mojang.blaze3d.vertex.PoseStack;
@ -12,6 +10,7 @@ import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
@ -42,7 +41,7 @@ public final class BakedModelBuilder implements Bufferable {
}
@Override
public void bufferInto(ModelBlockRenderer blockRenderer, VertexConsumer consumer, Random random) {
public void bufferInto(ModelBlockRenderer blockRenderer, VertexConsumer consumer, RandomSource random) {
BakedModel model = DefaultLayerFilteringBakedModel.wrap(this.model);
if (consumer instanceof ShadeSeparatingVertexConsumer shadeSeparatingWrapper) {
model = shadeSeparatingWrapper.wrapModel(model);

View file

@ -1,9 +1,25 @@
package com.jozufozu.flywheel.core.model;
import java.nio.ByteBuffer;
import java.util.function.Supplier;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
import com.jozufozu.flywheel.backend.model.ElementBuffer;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.QuadConverter;
import com.jozufozu.flywheel.util.Pair;
import com.mojang.blaze3d.platform.MemoryTracker;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexFormat.IndexType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.model.BakedModel;
@ -16,6 +32,7 @@ public class BlockModel implements Model {
private final VertexList reader;
private final String name;
private final EBOSupplier eboSupplier;
public BlockModel(BlockState state) {
this(Minecraft.getInstance()
@ -36,9 +53,19 @@ public class BlockModel implements Model {
this(bufferable.build(), name);
}
public BlockModel(ShadeSeparatedBufferBuilder bufferBuilder, String name) {
public BlockModel(Pair<RenderedBuffer, Integer> pair, String name) {
this.name = name;
reader = Formats.BLOCK.createReader(bufferBuilder);
RenderedBuffer renderedBuffer = pair.first();
BufferBuilder.DrawState drawState = renderedBuffer.drawState();
reader = Formats.BLOCK.createReader(renderedBuffer, pair.second());
if (!drawState.sequentialIndex()) {
eboSupplier = new BufferEBOSupplier(renderedBuffer.indexBuffer(), drawState.indexCount(), drawState.indexType());
} else {
eboSupplier = () -> QuadConverter.getInstance()
.quads2Tris(vertexCount() / 4);
}
}
@Override
@ -56,6 +83,11 @@ public class BlockModel implements Model {
return reader;
}
@Override
public ElementBuffer createEBO() {
return eboSupplier.get();
}
@Override
public VertexType getType() {
return Formats.BLOCK;
@ -70,5 +102,55 @@ public class BlockModel implements Model {
//
}
}
eboSupplier.delete();
}
private interface EBOSupplier extends Supplier<ElementBuffer> {
default void delete() {
}
}
private static class BufferEBOSupplier implements EBOSupplier {
private final ByteBuffer indexBuffer;
private final int indexCount;
private final IndexType indexType;
private int eboName = -1;
private ElementBuffer ebo;
public BufferEBOSupplier(ByteBuffer indexBufferSrc, int indexCount, IndexType indexType) {
indexBuffer = MemoryTracker.create(indexBufferSrc.capacity());
MemoryUtil.memCopy(indexBufferSrc, indexBuffer);
this.indexCount = indexCount;
this.indexType = indexType;
}
@Override
public ElementBuffer get() {
if (eboName == -1) {
eboName = createEBO();
ebo = new ElementBuffer(eboName, indexCount, indexType);
MemoryUtil.memFree(indexBuffer);
}
return ebo;
}
private int createEBO() {
int vbo = GL32.glGenBuffers();
// XXX ARRAY_BUFFER is bound and restored
var bufferType = GlBufferType.ARRAY_BUFFER;
var oldBuffer = bufferType.getBoundBuffer();
bufferType.bind(vbo);
GL15.glBufferData(bufferType.glEnum, indexBuffer, GlBufferUsage.STATIC_DRAW.glEnum);
bufferType.bind(oldBuffer);
return vbo;
}
@Override
public void delete() {
GL32.glDeleteBuffers(eboName);
}
}
}

View file

@ -1,19 +1,20 @@
package com.jozufozu.flywheel.core.model;
import java.util.Random;
import com.jozufozu.flywheel.util.Pair;
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.util.RandomSource;
/**
* An interface for objects that can "rendered" into a BufferBuilder.
*/
public interface Bufferable {
void bufferInto(ModelBlockRenderer renderer, VertexConsumer consumer, Random random);
void bufferInto(ModelBlockRenderer renderer, VertexConsumer consumer, RandomSource random);
default ShadeSeparatedBufferBuilder build() {
return ModelUtil.getBufferBuilder(this);
default Pair<RenderedBuffer, Integer> build() {
return ModelUtil.getRenderedBuffer(this);
}
}

View file

@ -1,11 +1,13 @@
package com.jozufozu.flywheel.core.model;
import java.util.Collection;
import java.util.Random;
import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
import com.jozufozu.flywheel.util.Pair;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexFormat;
@ -15,6 +17,7 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
@ -22,7 +25,18 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
public class ModelUtil {
private static final ThreadLocal<ThreadLocalObjects> THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new);
public static ShadeSeparatedBufferBuilder getBufferBuilder(Bufferable bufferable) {
public static Pair<RenderedBuffer, Integer> endShadeSeparated(BufferBuilder shadedBuilder, BufferBuilder unshadedBuilder) {
int unshadedStartVertex = ((BufferBuilderExtension) shadedBuilder).flywheel$getVertices();
RenderedBuffer unshadedBuffer = unshadedBuilder.endOrDiscardIfEmpty();
if (unshadedBuffer != null) {
// FIXME: Unshaded indices
((BufferBuilderExtension) shadedBuilder).flywheel$appendBufferUnsafe(unshadedBuffer.vertexBuffer());
}
RenderedBuffer buffer = shadedBuilder.end();
return Pair.of(buffer, unshadedStartVertex);
}
public static Pair<RenderedBuffer, Integer> getRenderedBuffer(Bufferable bufferable) {
ModelBlockRenderer blockRenderer = Minecraft.getInstance().getBlockRenderer().getModelRenderer();
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
@ -30,31 +44,29 @@ public class ModelUtil {
bufferable.bufferInto(blockRenderer, objects.shadeSeparatingWrapper, objects.random);
objects.end();
return objects.separatedBufferBuilder;
return objects.end();
}
public static ShadeSeparatedBufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack poseStack) {
public static Pair<RenderedBuffer, Integer> getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack poseStack) {
return new BakedModelBuilder(model).withReferenceState(referenceState)
.withPoseStack(poseStack)
.build();
}
public static ShadeSeparatedBufferBuilder getBufferBuilder(BlockAndTintGetter renderWorld, BakedModel model, BlockState referenceState, PoseStack poseStack) {
public static Pair<RenderedBuffer, Integer> getBufferBuilder(BlockAndTintGetter renderWorld, BakedModel model, BlockState referenceState, PoseStack poseStack) {
return new BakedModelBuilder(model).withReferenceState(referenceState)
.withPoseStack(poseStack)
.withRenderWorld(renderWorld)
.build();
}
public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks) {
public static Pair<RenderedBuffer, Integer> getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks) {
return new WorldModelBuilder(layer).withRenderWorld(renderWorld)
.withBlocks(blocks)
.build();
}
public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, PoseStack poseStack) {
public static Pair<RenderedBuffer, Integer> getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, PoseStack poseStack) {
return new WorldModelBuilder(layer).withRenderWorld(renderWorld)
.withBlocks(blocks)
.withPoseStack(poseStack)
@ -73,22 +85,20 @@ public class ModelUtil {
}
private static class ThreadLocalObjects {
public final Random random = new Random();
public final RandomSource random = RandomSource.create();
public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
public final ShadeSeparatedBufferBuilder separatedBufferBuilder = new ShadeSeparatedBufferBuilder(512);
public final BufferBuilder shadedBuilder = new BufferBuilder(512);
public final BufferBuilder unshadedBuilder = new BufferBuilder(512);
private void begin() {
this.separatedBufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
this.shadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
this.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
this.shadeSeparatingWrapper.prepare(this.separatedBufferBuilder, this.unshadedBuilder);
this.shadeSeparatingWrapper.prepare(this.shadedBuilder, this.unshadedBuilder);
}
private void end() {
private Pair<RenderedBuffer, Integer> end() {
this.shadeSeparatingWrapper.clear();
this.unshadedBuilder.end();
this.separatedBufferBuilder.appendUnshadedVertices(this.unshadedBuilder);
this.separatedBufferBuilder.end();
return ModelUtil.endShadeSeparated(shadedBuilder, unshadedBuilder);
}
}
}

View file

@ -1,28 +0,0 @@
package com.jozufozu.flywheel.core.model;
import java.nio.ByteBuffer;
import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
import com.jozufozu.flywheel.fabric.helper.BufferBuilderHelper;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.datafixers.util.Pair;
public class ShadeSeparatedBufferBuilder extends BufferBuilder {
protected int unshadedStartVertex;
public ShadeSeparatedBufferBuilder(int capacity) {
super(capacity);
}
public void appendUnshadedVertices(BufferBuilder unshadedBuilder) {
Pair<DrawState, ByteBuffer> data = unshadedBuilder.popNextBuffer();
ByteBuffer buffer = data.getSecond();
BufferBuilderHelper.fixByteOrder(unshadedBuilder, buffer);
unshadedStartVertex = ((BufferBuilderExtension) this).flywheel$getVertices();
((BufferBuilderExtension) this).flywheel$appendBufferUnsafe(buffer);
}
public int getUnshadedStartVertex() {
return unshadedStartVertex;
}
}

View file

@ -1,6 +1,5 @@
package com.jozufozu.flywheel.core.model;
import java.util.Random;
import java.util.function.Supplier;
import com.jozufozu.flywheel.fabric.model.FabricModelUtil;
@ -13,6 +12,7 @@ import net.fabricmc.fabric.api.renderer.v1.render.RenderContext.QuadTransform;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
@ -113,7 +113,7 @@ public class ShadeSeparatingVertexConsumer implements VertexConsumer {
}
@Override
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
context.pushTransform(quadTransform);
super.emitBlockQuads(blockView, state, pos, randomSupplier, context);
context.popTransform();

View file

@ -2,7 +2,6 @@ package com.jozufozu.flywheel.core.model;
import java.util.Collection;
import java.util.Collections;
import java.util.Random;
import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter;
import com.jozufozu.flywheel.fabric.model.CullingBakedModel;
@ -19,6 +18,7 @@ import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockState;
@ -36,7 +36,7 @@ public final class WorldModelBuilder implements Bufferable {
}
@Override
public void bufferInto(ModelBlockRenderer modelRenderer, VertexConsumer consumer, Random random) {
public void bufferInto(ModelBlockRenderer modelRenderer, VertexConsumer consumer, RandomSource random) {
BlockRenderDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer();
ModelBlockRenderer.enableCaching();
@ -87,6 +87,6 @@ public final class WorldModelBuilder implements Bufferable {
}
public BlockModel intoMesh(String name) {
return new BlockModel(ModelUtil.getBufferBuilder(this), name);
return new BlockModel(this, name);
}
}

View file

@ -1,8 +1,8 @@
package com.jozufozu.flywheel.core.source;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@ -28,24 +28,25 @@ public class ShaderSources implements SourceFinder {
public final Index index;
public ShaderSources(ResourceManager manager) {
Collection<ResourceLocation> allShaders = manager.listResources(SHADER_DIR, s -> {
Map<ResourceLocation, Resource> allShaders = manager.listResources(SHADER_DIR, loc -> {
String path = loc.getPath();
for (String ext : EXTENSIONS) {
if (s.endsWith(ext)) return true;
if (path.endsWith(ext)) return true;
}
return false;
});
for (ResourceLocation location : allShaders) {
try (Resource resource = manager.getResource(location)) {
String source = StringUtil.readToString(resource.getInputStream());
allShaders.forEach((location, resource) -> {
try (InputStream inputStream = resource.open()) {
String source = StringUtil.readToString(inputStream);
ResourceLocation name = ResourceUtil.removePrefixUnchecked(location, SHADER_DIR);
shaderSources.put(name, new SourceFile(this, name, source));
} catch (IOException e) {
//
} catch (IOException ignored) {
}
}
});
index = new Index(shaderSources);
}

View file

@ -6,11 +6,8 @@ import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.CommonItems;
import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
import com.jozufozu.flywheel.fabric.helper.BufferBuilderHelper;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.datafixers.util.Pair;
public class BlockVertex implements VertexType {
@ -63,21 +60,21 @@ Vertex FLWCreateVertex() {
return new BlockVertexListUnsafe.Shaded(buffer, vertexCount, unshadedStartVertex);
}
public VertexList createReader(BufferBuilder bufferBuilder) {
public VertexList createReader(BufferBuilder.RenderedBuffer renderedBuffer, int unshadedStartVertex) {
// TODO: try to avoid virtual model rendering
Pair<BufferBuilder.DrawState, ByteBuffer> pair = bufferBuilder.popNextBuffer();
BufferBuilder.DrawState drawState = pair.getFirst();
BufferBuilder.DrawState drawState = renderedBuffer.drawState();
if (drawState.format() != DefaultVertexFormat.BLOCK) {
throw new RuntimeException("Cannot use BufferBuilder with " + drawState.format());
}
ByteBuffer vertexBuffer = renderedBuffer.vertexBuffer();
ByteBuffer buffer = pair.getSecond();
BufferBuilderHelper.fixByteOrder(bufferBuilder, buffer);
if (bufferBuilder instanceof ShadeSeparatedBufferBuilder separated) {
return createReader(buffer, drawState.vertexCount(), separated.getUnshadedStartVertex());
int vertexCount = drawState.vertexCount();
if (unshadedStartVertex >= 0 && unshadedStartVertex < vertexCount) {
return createReader(vertexBuffer, vertexCount, unshadedStartVertex);
} else {
return createReader(buffer, drawState.vertexCount());
return createReader(vertexBuffer, vertexCount);
}
}
}

View file

@ -28,7 +28,7 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
@ -194,39 +194,39 @@ public class VirtualChunk extends ChunkAccess {
@Override
@Nullable
public StructureStart getStartForFeature(ConfiguredStructureFeature<?, ?> pStructure) {
public StructureStart getStartForStructure(Structure structure) {
return null;
}
@Override
public void setStartForFeature(ConfiguredStructureFeature<?, ?> pStructure, StructureStart pStart) {
public void setStartForStructure(Structure structure, StructureStart start) {
}
@Override
public Map<ConfiguredStructureFeature<?, ?>, StructureStart> getAllStarts() {
public Map<Structure, StructureStart> getAllStarts() {
return Collections.emptyMap();
}
@Override
public void setAllStarts(Map<ConfiguredStructureFeature<?, ?>, StructureStart> pStructureStarts) {
public void setAllStarts(Map<Structure, StructureStart> structureStarts) {
}
@Override
public LongSet getReferencesForFeature(ConfiguredStructureFeature<?, ?> pStructure) {
public LongSet getReferencesForStructure(Structure structure) {
return LongSets.emptySet();
}
@Override
public void addReferenceForFeature(ConfiguredStructureFeature<?, ?> pStructure, long pReference) {
public void addReferenceForStructure(Structure structure, long reference) {
}
@Override
public Map<ConfiguredStructureFeature<?, ?>, LongSet> getAllReferences() {
public Map<Structure, LongSet> getAllReferences() {
return Collections.emptyMap();
}
@Override
public void setAllReferences(Map<ConfiguredStructureFeature<?, ?>, LongSet> pStructureReferences) {
public void setAllReferences(Map<Structure, LongSet> structureReferences) {
}
@Override

View file

@ -36,10 +36,12 @@ import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.entity.LevelEntityGetter;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.gameevent.GameEvent.Context;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import net.minecraft.world.level.storage.WritableLevelData;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.ticks.LevelTickAccess;
@ -68,7 +70,7 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld {
public VirtualRenderWorld(Level level, Vec3i biomeOffset, int height, int minBuildHeight) {
super((WritableLevelData) level.getLevelData(), level.dimension(), level.dimensionTypeRegistration(), level::getProfiler,
true, false, 0);
true, false, 0, 0);
this.biomeOffset = biomeOffset;
this.level = level;
this.height = nextMultipleOf16(height);
@ -289,6 +291,17 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld {
@Override
public void levelEvent(@Nullable Player player, int type, BlockPos pos, int data) {}
@Override
public void gameEvent(GameEvent p_220404_, Vec3 p_220405_, Context p_220406_) {}
@Override
public void playSeededSound(Player p_220363_, double p_220364_, double p_220365_, double p_220366_,
SoundEvent p_220367_, SoundSource p_220368_, float p_220369_, float p_220370_, long p_220371_) {}
@Override
public void playSeededSound(Player p_220372_, Entity p_220373_, SoundEvent p_220374_, SoundSource p_220375_,
float p_220376_, float p_220377_, long p_220378_) {}
@Override
public void playSound(@Nullable Player player, double x, double y, double z, SoundEvent soundIn,
SoundSource category, float volume, float pitch) {}

View file

@ -1,6 +1,5 @@
package com.jozufozu.flywheel.fabric.model;
import java.util.Random;
import java.util.function.Supplier;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
@ -8,6 +7,7 @@ import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
@ -33,7 +33,7 @@ public class CullingBakedModel extends ForwardingBakedModel {
}
@Override
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
completionFlags = 0;
resultFlags = 0;
context.pushTransform(quad -> {

View file

@ -1,6 +1,5 @@
package com.jozufozu.flywheel.fabric.model;
import java.util.Random;
import java.util.function.Supplier;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
@ -10,6 +9,7 @@ import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
@ -30,14 +30,14 @@ public class DefaultLayerFilteringBakedModel extends ForwardingBakedModel {
}
@Override
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
context.pushTransform(DefaultLayerFilteringBakedModel::hasDefaultBlendMode);
super.emitBlockQuads(blockView, state, pos, randomSupplier, context);
context.popTransform();
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
public void emitItemQuads(ItemStack stack, Supplier<RandomSource> randomSupplier, RenderContext context) {
context.pushTransform(DefaultLayerFilteringBakedModel::hasDefaultBlendMode);
super.emitItemQuads(stack, randomSupplier, context);
context.popTransform();

View file

@ -1,6 +1,5 @@
package com.jozufozu.flywheel.fabric.model;
import java.util.Random;
import java.util.function.Supplier;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
@ -9,6 +8,7 @@ import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
@ -33,7 +33,7 @@ public class LayerFilteringBakedModel extends ForwardingBakedModel {
}
@Override
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
RenderType defaultLayer = ItemBlockRenderTypes.getChunkRenderType(state);
if (super.isVanillaAdapter()) {
if (defaultLayer == targetLayer) {

View file

@ -1,30 +1,78 @@
package com.jozufozu.flywheel.mixin.instancemanage;
import java.util.Set;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import com.jozufozu.flywheel.util.RenderChunkExtension;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
import net.minecraft.client.renderer.chunk.RenderChunkRegion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
@Mixin(targets = "net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$RenderChunk$RebuildTask")
public class ChunkRebuildHooksMixin {
public abstract class ChunkRebuildHooksMixin {
@Unique
private Level flywheel$level;
@Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true)
private <E extends BlockEntity> void addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set<BlockEntity> set, E be, CallbackInfo ci) {
if (Backend.canUseInstancing(be.getLevel())) {
if (InstancedRenderRegistry.canInstance(be.getType()))
InstancedRenderDispatcher.getBlockEntities(be.getLevel()).queueAdd(be);
@Inject(method = "<init>(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;DLnet/minecraft/client/renderer/chunk/RenderChunkRegion;Z)V", at = @At("RETURN"))
private void setLevel(ChunkRenderDispatcher.RenderChunk this$1, double p_194427_, RenderChunkRegion region, boolean p_194429_, CallbackInfo ci) {
flywheel$level = ((RenderChunkExtension) this$1).flywheel$getLevel();
}
if (InstancedRenderRegistry.shouldSkipRender(be))
ci.cancel();
@Redirect(method = "doTask", at = @At(value = "INVOKE", target = "Ljava/util/List;addAll(Ljava/util/Collection;)Z"))
private <E extends BlockEntity> boolean addAndFilterBEs(List<BlockEntity> self, Collection<? extends E> es) {
if (!Backend.canUseInstancing(flywheel$level)) {
return self.addAll(es);
}
boolean added = false;
var instanced = new ArrayList<BlockEntity>();
for (E be : es) {
if (InstancedRenderRegistry.canInstance(be.getType())) {
instanced.add(be);
}
if (!InstancedRenderRegistry.shouldSkipRender(be)) {
self.add(be);
added = true;
}
}
InstancedRenderDispatcher.getBlockEntities(flywheel$level).queueAddAll(instanced);
return added;
}
@Redirect(method = "doTask", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;updateGlobalBlockEntities(Ljava/util/Collection;)V"))
private void addAndFilterBEs(ChunkRenderDispatcher.RenderChunk self, Collection<BlockEntity> bes) {
if (!Backend.canUseInstancing(flywheel$level)) {
((RenderChunkAccessor) self).flywheel$updateGlobalBlockEntities(bes);
return;
}
var global = new ArrayList<BlockEntity>();
var instanced = new ArrayList<BlockEntity>();
for (BlockEntity be : bes) {
if (InstancedRenderRegistry.canInstance(be.getType())) {
instanced.add(be);
}
if (!InstancedRenderRegistry.shouldSkipRender(be)) {
global.add(be);
}
}
InstancedRenderDispatcher.getBlockEntities(flywheel$level).queueAddAll(instanced);
((RenderChunkAccessor) self).flywheel$updateGlobalBlockEntities(global);
}
}

View file

@ -0,0 +1,14 @@
package com.jozufozu.flywheel.mixin.instancemanage;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
@Mixin(ChunkRenderDispatcher.class)
public interface ChunkRenderDispatcherAccessor {
@Accessor
ClientLevel getLevel();
}

View file

@ -0,0 +1,19 @@
package com.jozufozu.flywheel.mixin.instancemanage;
import java.util.Collection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
import net.minecraft.world.level.block.entity.BlockEntity;
/**
* For use in {@link ChunkRebuildHooksMixin#addAndFilterBEs(ChunkRenderDispatcher.RenderChunk, Collection)}
*/
@Mixin(ChunkRenderDispatcher.RenderChunk.class)
public interface RenderChunkAccessor {
@Invoker("updateGlobalBlockEntities")
void flywheel$updateGlobalBlockEntities(Collection<BlockEntity> blockEntities);
}

View file

@ -0,0 +1,21 @@
package com.jozufozu.flywheel.mixin.instancemanage;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
@Mixin(ChunkRenderDispatcher.RenderChunk.class)
public class RenderChunkMixin implements com.jozufozu.flywheel.util.RenderChunkExtension {
@Shadow(aliases = {"this$0", "field_20833", "f_dssekupm"}) // Optifine does not use the obfuscated name so the mapped name must be included as an alias
@Final
private ChunkRenderDispatcher this$0;
@Override
public ClientLevel flywheel$getLevel() {
return ((ChunkRenderDispatcherAccessor) this$0).getLevel();
}
}

View file

@ -0,0 +1,62 @@
package com.jozufozu.flywheel.mixin.instancemanage;
import java.util.ArrayList;
import java.util.List;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
@Mixin(targets = "me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData$Builder", remap = false)
public class SodiumChunkRenderDataMixin {
@Unique
private List<BlockEntity> flywheel$blockEntities;
@Unique
private Level flywheel$level;
@Inject(method = "addBlockEntity", at = @At("HEAD"), cancellable = true, require = 0)
private void flywheel$onAddBlockEntity(BlockEntity be, boolean cull, CallbackInfo ci) {
if (flywheel$level == null) {
flywheel$level = be.getLevel();
}
if (!Backend.canUseInstancing(flywheel$level)) {
return;
}
if (InstancedRenderRegistry.canInstance(be.getType())) {
if (flywheel$blockEntities == null) {
flywheel$blockEntities = new ArrayList<>();
}
// Collect BEs in a temporary list to avoid excessive synchronization in InstancedRenderDispatcher.
flywheel$blockEntities.add(be);
}
if (InstancedRenderRegistry.shouldSkipRender(be)) {
ci.cancel();
}
}
@Inject(method = "build", at = @At("HEAD"))
private void flywheel$onBuild(CallbackInfoReturnable<ChunkRenderData> cir) {
if (flywheel$level == null || flywheel$blockEntities == null || !Backend.canUseInstancing(flywheel$level)) {
return;
}
InstancedRenderDispatcher.getBlockEntities(flywheel$level)
.queueAddAll(flywheel$blockEntities);
}
}

View file

@ -0,0 +1,7 @@
package com.jozufozu.flywheel.util;
import net.minecraft.client.multiplayer.ClientLevel;
public interface RenderChunkExtension {
ClientLevel flywheel$getLevel();
}

View file

@ -33,7 +33,7 @@
"depends": {
"fabricloader": ">=0.11.3",
"fabric": "*",
"minecraft": ">=1.18.2",
"minecraft": ">=1.19.2",
"java": ">=17"
}
}

View file

@ -22,8 +22,12 @@
"atlas.AtlasDataMixin",
"atlas.SheetDataAccessor",
"instancemanage.ChunkRebuildHooksMixin",
"instancemanage.ChunkRenderDispatcherAccessor",
"instancemanage.InstanceAddMixin",
"instancemanage.InstanceRemoveMixin",
"instancemanage.RenderChunkAccessor",
"instancemanage.RenderChunkMixin",
"instancemanage.SodiumChunkRenderDataMixin",
"light.LightUpdateMixin",
"light.NetworkLightUpdateMixin",
"matrix.Matrix3fMixin",