From a970e422c1f60c199c4ae04fa9a8a8e6bae856cd Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:51:10 -0600 Subject: [PATCH 1/6] Update README and issue template - Add license and Modrinth badges to README - Update buildscript dependency example and Maven link in README - Add 0.6.9 and 1.20.1 to issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 ++ README.md | 27 +++++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3dbe6f0b0..7ef4717ff 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -59,6 +59,7 @@ body: label: Mod Version description: The version of the mod you were using when the bug occured options: + - "0.6.9" - "0.6.8.a" - "0.6.8" - "0.6.7" @@ -94,6 +95,7 @@ body: label: Minecraft Version description: The version of Minecraft you were using when the bug occured options: + - "1.20.1" - "1.19.2" - "1.18.2" - "1.18.1" diff --git a/README.md b/README.md index 95d7ba6ba..3764cc92d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@
-Logo by @voxel_dani on Twitter -

Flywheel

-
A modern engine for modded Minecraft.
-Jenkins -Discord -Curseforge Downloads -
+ Logo by @voxel_dani on Twitter +

Flywheel

+
A modern engine for modded Minecraft.
+ Jenkins + License + Discord + Curseforge Downloads + Modrinth +

### About @@ -22,7 +24,7 @@ and write custom shaders to ingest that data. ### Shaders -To accomodate the developer and leave more in the hands of the engine, Flywheel provides a custom shader loading and +To accommodate the developer and leave more in the hands of the engine, Flywheel provides a custom shader loading and templating system to hide the details of the CPU/GPU interface. This system is a work in progress. There will be breaking changes, and I make no guarantees of backwards compatibility. @@ -46,14 +48,15 @@ repositories { } dependencies { - implementation fg.deobf("com.jozufozu.flywheel:Flywheel-Forge:${flywheel_version}") + implementation fg.deobf("com.jozufozu.flywheel:flywheel-forge-${flywheel_minecraft_version}:${flywheel_version}") } ``` -`${flywheel_version}` gets replaced by the version of Flywheel you want to use, eg. `1.18-0.3.0.3` +`${flywheel_version}` gets replaced by the version of Flywheel you want to use, eg. `0.6.9`. +`${flywheel_minecraft_version}` gets replaced by the version of Minecraft, eg. `1.18.2`. -For a list of available Flywheel versions, you can check [the maven](https://maven.tterrag.com/com/jozufozu/flywheel/Flywheel-Forge/). +For a list of available Flywheel versions, you can check [the maven](https://maven.tterrag.com/com/jozufozu/flywheel/). -If you aren't using mixed mappings (or just want to be safe), add the following properties to your run configurations: +If you aren't using Mojang mappings (or just want to be safe), add the following properties to your run configurations: ```groovy property 'mixin.env.remapRefMap', 'true' property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" From 833edce4e5ffc901c76696072c2681d73ea931aa Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:01:01 -0600 Subject: [PATCH 2/6] Fix license badge link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3764cc92d..b42d833ec 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

Flywheel

A modern engine for modded Minecraft.
Jenkins - License + License Discord Curseforge Downloads Modrinth @@ -18,7 +18,7 @@ graphics programming. ### Instancing -Flywheel provides an alternate, unified path for entity and tile entity rendering that takes advantage of GPU +Flywheel provides an alternate, unified path for entity and block entity rendering that takes advantage of GPU instancing. In doing so, Flywheel gives the developer the flexibility to define their own vertex and instance formats, and write custom shaders to ingest that data. From 67098704567e814ec8cc5c78ca5944113c225a6a Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:17:47 -0700 Subject: [PATCH 3/6] Improve and fix VirtualRenderWorld - Fix calling VirtualRenderWorld#getExistingBlockEntity causing a crash - Bump version --- gradle.properties | 2 +- .../flywheel/core/virtual/VirtualChunk.java | 252 ++++++------- .../core/virtual/VirtualChunkSection.java | 14 +- .../core/virtual/VirtualChunkSource.java | 53 +-- .../core/virtual/VirtualEmptyBlockGetter.java | 13 +- .../virtual/VirtualLevelEntityGetter.java | 12 +- .../core/virtual/VirtualRenderWorld.java | 344 +++++++++++------- 7 files changed, 381 insertions(+), 309 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9bd695b3f..ccf465b19 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G org.gradle.daemon = false # mod version info -mod_version = 0.6.9 +mod_version = 0.6.10 artifact_minecraft_version = 1.18.2 minecraft_version = 1.18.2 diff --git a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunk.java b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunk.java index eaed3e59f..1160163c5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunk.java +++ b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunk.java @@ -17,6 +17,7 @@ import it.unimi.dsi.fastutil.longs.LongSets; import it.unimi.dsi.fastutil.shorts.ShortList; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; @@ -36,13 +37,11 @@ import net.minecraft.world.ticks.BlackholeTickAccess; import net.minecraft.world.ticks.TickContainerAccess; public class VirtualChunk extends ChunkAccess { + public final VirtualRenderWorld world; - final VirtualRenderWorld world; - boolean needsLight; - final int x; - final int z; + private final VirtualChunkSection[] sections; - private final LevelChunkSection[] sections; + private boolean needsLight; public VirtualChunk(VirtualRenderWorld world, int x, int z) { super(new ChunkPos(x, z), UpgradeData.EMPTY, world, world.registryAccess() @@ -50,34 +49,39 @@ public class VirtualChunk extends ChunkAccess { .orElseThrow(), 0L, null, null); this.world = world; - this.needsLight = true; - this.x = x; - this.z = z; int sectionCount = world.getSectionsCount(); - this.sections = new LevelChunkSection[sectionCount]; + this.sections = new VirtualChunkSection[sectionCount]; for (int i = 0; i < sectionCount; i++) { sections[i] = new VirtualChunkSection(this, i << 4); } + this.needsLight = true; + Mods.STARLIGHT.executeIfInstalled(() -> () -> { - ((ExtendedChunk)this).setBlockNibbles(StarLightEngine.getFilledEmptyLight(this)); - ((ExtendedChunk)this).setSkyNibbles(StarLightEngine.getFilledEmptyLight(this)); + ((ExtendedChunk) this).setBlockNibbles(StarLightEngine.getFilledEmptyLight(this)); + ((ExtendedChunk) this).setSkyNibbles(StarLightEngine.getFilledEmptyLight(this)); }); } @Override - public Stream getLights() { - return world.blocksAdded.entrySet() - .stream() - .filter(it -> { - BlockPos blockPos = it.getKey(); - boolean chunkContains = blockPos.getX() >> 4 == x && blockPos.getZ() >> 4 == z; - return chunkContains && it.getValue() - .getLightEmission(world, blockPos) != 0; - }) - .map(Map.Entry::getKey); + @Nullable + public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving) { + return null; + } + + @Override + public void setBlockEntity(BlockEntity blockEntity) { + } + + @Override + public void addEntity(Entity entity) { + } + + @Override + public Set getBlockEntitiesPos() { + return Collections.emptySet(); } @Override @@ -85,121 +89,33 @@ public class VirtualChunk extends ChunkAccess { return sections; } - @Override - public ChunkStatus getStatus() { - return ChunkStatus.LIGHT; - } - - @Nullable - @Override - public BlockState setBlockState(BlockPos p_177436_1_, BlockState p_177436_2_, boolean p_177436_3_) { - return null; - } - - @Override - public void setBlockEntity(BlockEntity p_177426_2_) {} - - @Override - public void addEntity(Entity p_76612_1_) {} - - @Override - public Set getBlockEntitiesPos() { - return null; - } - @Override public Collection> getHeightmaps() { + return Collections.emptySet(); + } + + @Override + public void setHeightmap(Heightmap.Types type, long[] data) { + } + + @Override + public Heightmap getOrCreateHeightmapUnprimed(Heightmap.Types type) { return null; } @Override - public void setHeightmap(Heightmap.Types p_201607_1_, long[] p_201607_2_) {} - - @Override - public Heightmap getOrCreateHeightmapUnprimed(Heightmap.Types p_217303_1_) { - return null; - } - - @Override - public int getHeight(Heightmap.Types p_201576_1_, int p_201576_2_, int p_201576_3_) { + public int getHeight(Heightmap.Types type, int x, int z) { return 0; } @Override - public void setUnsaved(boolean p_177427_1_) {} - - @Override - public boolean isUnsaved() { - return false; - } - - @Override - public void removeBlockEntity(BlockPos p_177425_1_) {} - - @Override - public ShortList[] getPostProcessing() { - return new ShortList[0]; - } - @Nullable - @Override - public CompoundTag getBlockEntityNbt(BlockPos p_201579_1_) { - return null; - } - - @Nullable - @Override - public CompoundTag getBlockEntityNbtForSaving(BlockPos p_223134_1_) { + public StructureStart getStartForFeature(ConfiguredStructureFeature structure) { return null; } @Override - public UpgradeData getUpgradeData() { - return null; - } - - @Override - public void setInhabitedTime(long p_177415_1_) {} - - @Override - public long getInhabitedTime() { - return 0; - } - - @Override - public boolean isLightCorrect() { - return needsLight; - } - - @Override - public void setLightCorrect(boolean needsLight) { - this.needsLight = needsLight; - } - - @Nullable - @Override - public BlockEntity getBlockEntity(BlockPos pos) { - return null; - } - - @Override - public BlockState getBlockState(BlockPos pos) { - return world.getBlockState(pos); - } - - @Override - public FluidState getFluidState(BlockPos p_204610_1_) { - return null; - } - - @Override - @Nullable - public StructureStart getStartForFeature(ConfiguredStructureFeature pStructure) { - return null; - } - - @Override - public void setStartForFeature(ConfiguredStructureFeature pStructure, StructureStart pStart) { + public void setStartForFeature(ConfiguredStructureFeature structure, StructureStart start) { } @Override @@ -208,16 +124,16 @@ public class VirtualChunk extends ChunkAccess { } @Override - public void setAllStarts(Map, StructureStart> pStructureStarts) { + public void setAllStarts(Map, StructureStart> structureStarts) { } @Override - public LongSet getReferencesForFeature(ConfiguredStructureFeature pStructure) { + public LongSet getReferencesForFeature(ConfiguredStructureFeature structure) { return LongSets.emptySet(); } @Override - public void addReferenceForFeature(ConfiguredStructureFeature pStructure, long pReference) { + public void addReferenceForFeature(ConfiguredStructureFeature structure, long reference) { } @Override @@ -226,17 +142,60 @@ public class VirtualChunk extends ChunkAccess { } @Override - public void setAllReferences(Map, LongSet> pStructureReferences) { + public void setAllReferences(Map, LongSet> structureReferences) { } @Override - public int getHeight() { - return world.getHeight(); + public void setUnsaved(boolean unsaved) { } @Override - public int getMinBuildHeight() { - return world.getMinBuildHeight(); + public boolean isUnsaved() { + return false; + } + + @Override + public ChunkStatus getStatus() { + return ChunkStatus.LIGHT; + } + + @Override + public void removeBlockEntity(BlockPos pos) { + } + + @Override + public ShortList[] getPostProcessing() { + return new ShortList[0]; + } + + @Override + @Nullable + public CompoundTag getBlockEntityNbt(BlockPos pos) { + return null; + } + + @Override + @Nullable + public CompoundTag getBlockEntityNbtForSaving(BlockPos pos) { + return null; + } + + @Override + public Stream getLights() { + return world.blockStates.entrySet() + .stream() + .filter(it -> { + BlockPos blockPos = it.getKey(); + boolean chunkContains = SectionPos.blockToSectionCoord(blockPos.getX()) == chunkPos.x && SectionPos.blockToSectionCoord(blockPos.getZ()) == chunkPos.z; + return chunkContains && it.getValue() + .getLightEmission(world, blockPos) != 0; + }) + .map(Map.Entry::getKey); + } + + @Override + public TickContainerAccess getBlockTicks() { + return BlackholeTickAccess.emptyContainer(); } @Override @@ -246,12 +205,41 @@ public class VirtualChunk extends ChunkAccess { @Override public TicksToSave getTicksForSerialization() { - return null; + throw new UnsupportedOperationException(); } @Override - public TickContainerAccess getBlockTicks() { - return BlackholeTickAccess.emptyContainer(); + public long getInhabitedTime() { + return 0; } + @Override + public void setInhabitedTime(long amount) { + } + + @Override + public boolean isLightCorrect() { + return needsLight; + } + + @Override + public void setLightCorrect(boolean lightCorrect) { + this.needsLight = lightCorrect; + } + + @Override + @Nullable + public BlockEntity getBlockEntity(BlockPos pos) { + return world.getBlockEntity(pos); + } + + @Override + public BlockState getBlockState(BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public FluidState getFluidState(BlockPos pos) { + return world.getFluidState(pos); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSection.java b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSection.java index a3d4f1952..01414b065 100644 --- a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSection.java +++ b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSection.java @@ -3,10 +3,10 @@ package com.jozufozu.flywheel.core.virtual; import net.minecraft.core.Registry; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.material.FluidState; public class VirtualChunkSection extends LevelChunkSection { - - public VirtualChunk owner; + public final VirtualChunk owner; public final int xStart; public final int yStart; @@ -32,8 +32,12 @@ public class VirtualChunkSection extends LevelChunkSection { } @Override - public BlockState setBlockState(int p_177484_1_, int p_177484_2_, int p_177484_3_, BlockState p_177484_4_, - boolean p_177484_5_) { - throw new IllegalStateException("Chunk sections should not be mutated in a fake world."); + public FluidState getFluidState(int x, int y, int z) { + return getBlockState(x, y, z).getFluidState(); + } + + @Override + public BlockState setBlockState(int x, int y, int z, BlockState state, boolean useLocks) { + throw new UnsupportedOperationException("Chunk sections cannot be mutated in a fake world."); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSource.java b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSource.java index 7fa73d38d..ff91f12da 100644 --- a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSource.java +++ b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunkSource.java @@ -1,62 +1,65 @@ package com.jozufozu.flywheel.core.virtual; -import java.util.HashMap; import java.util.function.BooleanSupplier; -import net.minecraft.world.level.BlockGetter; +import org.jetbrains.annotations.Nullable; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.lighting.LevelLightEngine; public class VirtualChunkSource extends ChunkSource { private final VirtualRenderWorld world; - - public final HashMap chunks = new HashMap<>(); + private final Long2ObjectMap chunks = new Long2ObjectOpenHashMap<>(); public VirtualChunkSource(VirtualRenderWorld world) { this.world = world; } - @Override - public BlockGetter getChunkForLighting(int x, int z) { - return getChunk(x, z); - } - @Override public Level getLevel() { return world; } - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus status, boolean p_212849_4_) { - return getChunk(x, z); - } - public ChunkAccess getChunk(int x, int z) { long pos = ChunkPos.asLong(x, z); - return chunks.computeIfAbsent(pos, $ -> new VirtualChunk(world, x, z)); } + @Override + @Nullable + public LevelChunk getChunk(int x, int z, boolean load) { + return null; + } + + @Override + @Nullable + public ChunkAccess getChunk(int x, int z, ChunkStatus status, boolean load) { + return getChunk(x, z); + } + + @Override + public void tick(BooleanSupplier hasTimeLeft, boolean tickChunks) { + } + @Override public String gatherStats() { - return "WrappedChunkProvider"; - } - - @Override - public LevelLightEngine getLightEngine() { - return world.getLightEngine(); - } - - @Override - public void tick(BooleanSupplier p_202162_, boolean p_202163_) { + return "VirtualChunkSource"; } @Override public int getLoadedChunksCount() { return 0; } + + @Override + public LevelLightEngine getLightEngine() { + return world.getLightEngine(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java index ebfbe9389..8785d3ada 100644 --- a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java +++ b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.core.virtual; +import org.jetbrains.annotations.Nullable; + import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -32,6 +34,7 @@ public interface VirtualEmptyBlockGetter extends BlockAndTintGetter { } @Override + @Nullable default BlockEntity getBlockEntity(BlockPos pos) { return null; } @@ -99,7 +102,7 @@ public interface VirtualEmptyBlockGetter extends BlockAndTintGetter { } @Override - public void onBlockEmissionIncrease(BlockPos pos, int p_164456_) { + public void onBlockEmissionIncrease(BlockPos pos, int emissionLevel) { } @Override @@ -108,16 +111,16 @@ public interface VirtualEmptyBlockGetter extends BlockAndTintGetter { } @Override - public int runUpdates(int p_164449_, boolean p_164450_, boolean p_164451_) { - return p_164449_; + public int runUpdates(int pos, boolean isQueueEmpty, boolean updateBlockLight) { + return pos; } @Override - public void updateSectionStatus(SectionPos pos, boolean p_75838_) { + public void updateSectionStatus(SectionPos pos, boolean isQueueEmpty) { } @Override - public void enableLightSources(ChunkPos pos, boolean p_164453_) { + public void enableLightSources(ChunkPos pos, boolean isQueueEmpty) { } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualLevelEntityGetter.java b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualLevelEntityGetter.java index 2edd3fdf3..67ce31b48 100644 --- a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualLevelEntityGetter.java +++ b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualLevelEntityGetter.java @@ -10,14 +10,13 @@ import net.minecraft.world.level.entity.LevelEntityGetter; import net.minecraft.world.phys.AABB; public class VirtualLevelEntityGetter implements LevelEntityGetter { - @Override - public T get(int p_156931_) { + public T get(int id) { return null; } @Override - public T get(UUID pUuid) { + public T get(UUID uuid) { return null; } @@ -27,15 +26,14 @@ public class VirtualLevelEntityGetter implements LevelEn } @Override - public void get(EntityTypeTest p_156935_, Consumer p_156936_) { + public void get(EntityTypeTest test, Consumer consumer) { } @Override - public void get(AABB p_156937_, Consumer p_156938_) { + public void get(AABB boundingBox, Consumer consumer) { } @Override - public void get(EntityTypeTest p_156932_, AABB p_156933_, Consumer p_156934_) { + public void get(EntityTypeTest test, AABB bounds, Consumer consumer) { } - } diff --git a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualRenderWorld.java b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualRenderWorld.java index 39574d808..8e3266ed7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualRenderWorld.java +++ b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualRenderWorld.java @@ -3,16 +3,15 @@ package com.jozufozu.flywheel.core.virtual; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; import javax.annotation.Nullable; import com.jozufozu.flywheel.api.FlywheelWorld; +import it.unimi.dsi.fastutil.objects.Object2ShortMap; +import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; @@ -33,48 +32,54 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.ChunkStatus; 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.lighting.LevelLightEngine; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import net.minecraft.world.level.storage.WritableLevelData; import net.minecraft.world.scores.Scoreboard; import net.minecraft.world.ticks.LevelTickAccess; public class VirtualRenderWorld extends Level implements FlywheelWorld { - public final Map blocksAdded = new HashMap<>(); - public final Map besAdded = new HashMap<>(); - public final Set spannedSections = new HashSet<>(); - private final BlockPos.MutableBlockPos scratch = new BlockPos.MutableBlockPos(); - protected final Level level; - protected final LevelLightEngine lighter; - protected final VirtualChunkSource chunkSource; - protected final LevelEntityGetter entityGetter = new VirtualLevelEntityGetter<>(); - - protected final int height; protected final int minBuildHeight; + protected final int height; protected final Vec3i biomeOffset; + protected final VirtualChunkSource chunkSource; + protected final LevelLightEngine lightEngine; + + protected final Map blockStates = new HashMap<>(); + protected final Map blockEntities = new HashMap<>(); + protected final Object2ShortMap nonEmptyBlockCounts = new Object2ShortOpenHashMap<>(); + + protected final LevelEntityGetter entityGetter = new VirtualLevelEntityGetter<>(); + + protected final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos(); + public VirtualRenderWorld(Level level) { - this(level, Vec3i.ZERO, level.getHeight(), level.getMinBuildHeight()); + this(level, Vec3i.ZERO); } public VirtualRenderWorld(Level level, Vec3i biomeOffset) { - this(level, biomeOffset, level.getHeight(), level.getMinBuildHeight()); + this(level, level.getMinBuildHeight(), level.getHeight(), biomeOffset); } - public VirtualRenderWorld(Level level, Vec3i biomeOffset, int height, int minBuildHeight) { - super((WritableLevelData) level.getLevelData(), level.dimension(), level.dimensionTypeRegistration(), level::getProfiler, + public VirtualRenderWorld(Level level, int minBuildHeight, int height, Vec3i biomeOffset) { + super((WritableLevelData) level.getLevelData(), level.dimension(), level.dimensionTypeRegistration(), level.getProfilerSupplier(), true, false, 0); - this.biomeOffset = biomeOffset; this.level = level; - this.height = nextMultipleOf16(height); this.minBuildHeight = nextMultipleOf16(minBuildHeight); + this.height = nextMultipleOf16(height); + this.biomeOffset = biomeOffset; + this.chunkSource = new VirtualChunkSource(this); - this.lighter = new LevelLightEngine(chunkSource, true, false); + this.lightEngine = new LevelLightEngine(chunkSource, true, false); } /** @@ -89,67 +94,145 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld { } } - /** - * Run this after you're done using setBlock(). - */ - public void runLightingEngine() { - for (Map.Entry entry : blocksAdded.entrySet()) { - BlockPos pos = entry.getKey(); - BlockState state = entry.getValue(); - int light = state.getLightEmission(this, pos); - if (light > 0) { - lighter.onBlockEmissionIncrease(pos, light); - } - } + public void clear() { + blockStates.clear(); + blockEntities.clear(); - lighter.runUpdates(Integer.MAX_VALUE, false, false); + nonEmptyBlockCounts.forEach((sectionPos, nonEmptyBlockCount) -> { + if (nonEmptyBlockCount > 0) { + lightEngine.updateSectionStatus(sectionPos, true); + } + }); + + nonEmptyBlockCounts.clear(); + + runLightEngine(); } public void setBlockEntities(Collection blockEntities) { - besAdded.clear(); - blockEntities.forEach(be -> besAdded.put(be.getBlockPos(), be)); + this.blockEntities.clear(); + blockEntities.forEach(this::setBlockEntity); } - public void clear() { - blocksAdded.clear(); + /** + * Run this after you're done using setBlock(). + */ + public void runLightEngine() { + blockStates.forEach((pos, state) -> { + int light = state.getLightEmission(this, pos); + if (light > 0) { + lightEngine.onBlockEmissionIncrease(pos, light); + } + }); + + lightEngine.runUpdates(Integer.MAX_VALUE, false, false); } // MEANINGFUL OVERRIDES @Override - public boolean setBlock(BlockPos pos, BlockState newState, int flags) { - blocksAdded.put(pos, newState); + public LevelChunk getChunk(int x, int z) { + throw new UnsupportedOperationException(); + } + + public ChunkAccess actuallyGetChunk(int x, int z) { + return getChunk(x, z, ChunkStatus.FULL); + } + + @Override + public ChunkAccess getChunk(BlockPos pos) { + return actuallyGetChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); + } + + @Override + public boolean setBlock(BlockPos pos, BlockState newState, int flags, int recursionLeft) { + if (isOutsideBuildHeight(pos)) { + return false; + } + + pos = pos.immutable(); + + BlockState oldState = getBlockState(pos); + if (oldState == newState) { + return false; + } + + blockStates.put(pos, newState); SectionPos sectionPos = SectionPos.of(pos); - if (spannedSections.add(sectionPos)) { - lighter.updateSectionStatus(sectionPos, false); + short nonEmptyBlockCount = nonEmptyBlockCounts.getShort(sectionPos); + boolean prevEmpty = nonEmptyBlockCount == 0; + if (!oldState.isAir()) { + --nonEmptyBlockCount; + } + if (!newState.isAir()) { + ++nonEmptyBlockCount; + } + nonEmptyBlockCounts.put(sectionPos, nonEmptyBlockCount); + boolean nowEmpty = nonEmptyBlockCount == 0; + + if (prevEmpty != nowEmpty) { + lightEngine.updateSectionStatus(sectionPos, nowEmpty); } if ((flags & Block.UPDATE_SUPPRESS_LIGHT) == 0) { - lighter.checkBlock(pos); + lightEngine.checkBlock(pos); } return true; } - @Override - public int getHeight() { - return height; - } - - @Override - public int getMinBuildHeight() { - return minBuildHeight; - } - - @Override - public ChunkSource getChunkSource() { - return chunkSource; - } - @Override public LevelLightEngine getLightEngine() { - return lighter; + return lightEngine; + } + + @Override + public BlockState getBlockState(BlockPos pos) { + if (isOutsideBuildHeight(pos)) { + return Blocks.VOID_AIR.defaultBlockState(); + } + BlockState state = blockStates.get(pos); + if (state != null) { + return state; + } + return Blocks.AIR.defaultBlockState(); + } + + public BlockState getBlockState(int x, int y, int z) { + return getBlockState(scratchPos.set(x, y, z)); + } + + @Override + public FluidState getFluidState(BlockPos pos) { + if (isOutsideBuildHeight(pos)) { + return Fluids.EMPTY.defaultFluidState(); + } + return getBlockState(pos).getFluidState(); + } + + @Override + @Nullable + public BlockEntity getBlockEntity(BlockPos pos) { + if (!isOutsideBuildHeight(pos)) { + return blockEntities.get(pos); + } + return null; + } + + @Override + public void setBlockEntity(BlockEntity blockEntity) { + BlockPos pos = blockEntity.getBlockPos(); + if (!isOutsideBuildHeight(pos)) { + blockEntities.put(pos, blockEntity); + } + } + + @Override + public void removeBlockEntity(BlockPos pos) { + if (!isOutsideBuildHeight(pos)) { + blockEntities.remove(pos); + } } @Override @@ -158,52 +241,39 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld { } @Override - public BlockState getBlockState(@Nullable BlockPos pos) { - BlockState state = blocksAdded.get(pos); - if (state != null) - return state; - return Blocks.AIR.defaultBlockState(); + public ChunkSource getChunkSource() { + return chunkSource; } @Override - public boolean setBlockAndUpdate(BlockPos pos, BlockState state) { - return setBlock(pos, state, 0); + public int getMinBuildHeight() { + return minBuildHeight; } @Override - @Nullable - public BlockEntity getBlockEntity(BlockPos pos) { - return besAdded.get(pos); - } - - @Override - public boolean isStateAtPosition(BlockPos pos, Predicate condition) { - return condition.test(getBlockState(pos)); - } - - public BlockState getBlockState(int x, int y, int z) { - return getBlockState(scratch.set(x, y, z)); + public int getHeight() { + return height; } // BIOME OFFSET @Override - public Holder getBiome(BlockPos pPos) { - return super.getBiome(pPos.offset(biomeOffset)); + public Holder getBiome(BlockPos pos) { + return super.getBiome(pos.offset(biomeOffset)); } @Override - public Holder getUncachedNoiseBiome(int pX, int pY, int pZ) { + public Holder getNoiseBiome(int x, int y, int z) { // Control flow should never reach this method, // so we add biomeOffset in case some other mod calls this directly. - return level.getUncachedNoiseBiome(pX + biomeOffset.getX(), pY + biomeOffset.getY(), pZ + biomeOffset.getZ()); + return level.getNoiseBiome(x + biomeOffset.getX(), y + biomeOffset.getY(), z + biomeOffset.getZ()); } @Override - public Holder getNoiseBiome(int pX, int pY, int pZ) { + public Holder getUncachedNoiseBiome(int x, int y, int z) { // Control flow should never reach this method, // so we add biomeOffset in case some other mod calls this directly. - return level.getNoiseBiome(pX + biomeOffset.getX(), pY + biomeOffset.getY(), pZ + biomeOffset.getZ()); + return level.getUncachedNoiseBiome(x + biomeOffset.getX(), y + biomeOffset.getY(), z + biomeOffset.getZ()); } // RENDERING CONSTANTS @@ -214,22 +284,27 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld { } @Override - public float getShade(Direction p_230487_1_, boolean p_230487_2_) { + public float getShade(Direction direction, boolean shade) { return 1f; } - // THIN WRAPPERS AHEAD + // THIN WRAPPERS + + @Override + public Scoreboard getScoreboard() { + return level.getScoreboard(); + } + + @Override + public RecipeManager getRecipeManager() { + return level.getRecipeManager(); + } @Override public BiomeManager getBiomeManager() { return level.getBiomeManager(); } - @Override - public RegistryAccess registryAccess() { - return level.registryAccess(); - } - @Override public LevelTickAccess getBlockTicks() { return level.getBlockTicks(); @@ -241,21 +316,44 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld { } @Override - public RecipeManager getRecipeManager() { - return level.getRecipeManager(); + public RegistryAccess registryAccess() { + return level.registryAccess(); + } + + // ADDITIONAL OVERRRIDES + + @Override + public void updateNeighbourForOutputSignal(BlockPos pos, Block block) { } @Override - public int getFreeMapId() { - return level.getFreeMapId(); + public boolean isLoaded(BlockPos pos) { + return true; } @Override - public Scoreboard getScoreboard() { - return level.getScoreboard(); + public boolean isAreaLoaded(BlockPos center, int range) { + return true; } - // UNIMPORTANT CONSTANTS + // UNIMPORTANT IMPLEMENTATIONS + + @Override + public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) { + } + + @Override + public void playSound(@Nullable Player player, double x, double y, double z, SoundEvent sound, SoundSource category, float volume, float pitch) { + } + + @Override + public void playSound(@Nullable Player player, Entity entity, SoundEvent sound, SoundSource category, float volume, float pitch) { + } + + @Override + public String gatherChunkSourceStats() { + return ""; + } @Override @Nullable @@ -270,13 +368,24 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld { } @Override - public boolean isLoaded(BlockPos pos) { - return true; + public void setMapData(String mapId, MapItemSavedData data) { } @Override - public boolean isAreaLoaded(BlockPos center, int range) { - return true; + public int getFreeMapId() { + return 0; + } + + @Override + public void destroyBlockProgress(int breakerId, BlockPos pos, int progress) { + } + + @Override + public void levelEvent(@Nullable Player player, int type, BlockPos pos, int data) { + } + + @Override + public void gameEvent(@Nullable Entity entity, GameEvent event, BlockPos pos) { } @Override @@ -284,39 +393,6 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld { return Collections.emptyList(); } - @Override - public String gatherChunkSourceStats() { - return ""; - } - - // NOOP - - @Override - public void levelEvent(@Nullable Player player, int type, BlockPos pos, int data) {} - - @Override - public void playSound(@Nullable Player player, double x, double y, double z, SoundEvent soundIn, - SoundSource category, float volume, float pitch) {} - - @Override - public void playSound(@Nullable Player p_217384_1_, Entity p_217384_2_, SoundEvent p_217384_3_, - SoundSource p_217384_4_, float p_217384_5_, float p_217384_6_) {} - - @Override - public void setMapData(String pMapId, MapItemSavedData pData) {} - - @Override - public void destroyBlockProgress(int breakerId, BlockPos pos, int progress) {} - - @Override - public void updateNeighbourForOutputSignal(BlockPos p_175666_1_, Block p_175666_2_) {} - - @Override - public void gameEvent(@Nullable Entity pEntity, GameEvent pEvent, BlockPos pPos) {} - - @Override - public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) {} - // Override Starlight's ExtendedWorld interface methods: public LevelChunk getChunkAtImmediately(final int chunkX, final int chunkZ) { From 01f204eb0a2860465e78156d7cb4704b96ed1495 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:22:17 -0700 Subject: [PATCH 4/6] Update issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 7ef4717ff..768944eb4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -59,6 +59,7 @@ body: label: Mod Version description: The version of the mod you were using when the bug occured options: + - "0.6.10" - "0.6.9" - "0.6.8.a" - "0.6.8" From ecc3c2d92534d2291bdab43864dce0b7d049bef1 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Wed, 23 Aug 2023 10:03:57 -0700 Subject: [PATCH 5/6] Add Rubidium compatibility on our side - Move FixNormalScalingMixin from Create - Extract some of LevelRendererMixin into InstanceUpdateMixin --- build.gradle | 6 ++- .../instancing/InstancedRenderDispatcher.java | 16 +++++++ .../flywheel/mixin/FixFabulousDepthMixin.java | 27 ----------- .../flywheel/mixin/LevelRendererMixin.java | 17 ------- .../mixin/PausedPartialTickAccessor.java | 3 +- .../mixin/fix/FixFabulousDepthMixin.java | 18 +++++++ .../mixin/fix/FixNormalScalingMixin.java | 36 ++++++++++++++ .../ChunkRebuildHooksMixin.java | 18 ++----- .../instancemanage/InstanceUpdateMixin.java | 40 ++++++++++++++++ .../sodium/ChunkRenderRebuildTaskMixin.java | 23 +++++++++ .../mixin/sodium/FlywheelCompatMixin.java | 24 ++++++++++ .../mixin/sodium/SodiumMixinPlugin.java | 48 +++++++++++++++++++ .../flywheel/util/AnimationTickHolder.java | 2 +- src/main/resources/META-INF/mods.toml | 2 +- src/main/resources/flywheel.mixins.json | 4 +- .../resources/flywheel.sodium.mixins.json | 15 ++++++ 16 files changed, 234 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/mixin/FixFabulousDepthMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/fix/FixFabulousDepthMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/fix/FixNormalScalingMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/sodium/FlywheelCompatMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/sodium/SodiumMixinPlugin.java create mode 100644 src/main/resources/flywheel.sodium.mixins.json diff --git a/build.gradle b/build.gradle index 60dac7f25..7b1aaaff7 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,7 @@ minecraft { property 'flw.loadRenderDoc', 'true' arg '-mixin.config=flywheel.mixins.json' + arg '-mixin.config=flywheel.sodium.mixins.json' mods { flywheel { @@ -67,6 +68,7 @@ minecraft { property 'forge.logging.console.level', 'debug' arg '-mixin.config=flywheel.mixins.json' + arg '-mixin.config=flywheel.sodium.mixins.json' mods { flywheel { @@ -119,7 +121,7 @@ dependencies { // switch to implementation for debugging compileOnly fg.deobf('maven.modrinth:starlight-forge:1.0.2+1.18.2') - compileOnly fg.deobf('maven.modrinth:rubidium:0.5.2a') + compileOnly fg.deobf('maven.modrinth:rubidium:0.5.6') compileOnly fg.deobf('maven.modrinth:oculus:1.18.2-1.6.4') // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 @@ -159,7 +161,7 @@ jar { 'Implementation-Version' : project.jar.archiveVersion, //'Implementation-Vendor': 'flywheel authors', 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - 'MixinConfigs' : 'flywheel.mixins.json' + 'MixinConfigs' : 'flywheel.mixins.json,flywheel.sodium.mixins.json' ]) } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index 6f8f77e3d..bc51354d3 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -15,6 +15,7 @@ import com.jozufozu.flywheel.util.WorldAttached; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.api.distmarker.Dist; @@ -119,6 +120,21 @@ public class InstancedRenderDispatcher { .loadEntities(world); } + public static boolean tryAddBlockEntity(T blockEntity) { + Level level = blockEntity.getLevel(); + if (!Backend.canUseInstancing(level)) { + return false; + } + + if (!InstancedRenderRegistry.canInstance(blockEntity.getType())) { + return false; + } + + getBlockEntities(level).queueAdd(blockEntity); + + return InstancedRenderRegistry.shouldSkipRender(blockEntity); + } + public static void getDebugString(List debug) { debug.add(""); debug.add("Flywheel: " + Flywheel.getVersion()); diff --git a/src/main/java/com/jozufozu/flywheel/mixin/FixFabulousDepthMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/FixFabulousDepthMixin.java deleted file mode 100644 index 9c0978197..000000000 --- a/src/main/java/com/jozufozu/flywheel/mixin/FixFabulousDepthMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.jozufozu.flywheel.mixin; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix4f; - -import net.minecraft.client.Camera; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.LightTexture; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) -@Mixin(LevelRenderer.class) -public class FixFabulousDepthMixin { - - @Inject(method = "renderLevel", at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/client/renderer/PostChain;process(F)V")) - private void disableTransparencyShaderDepth(PoseStack p_228426_1_, float p_228426_2_, long p_228426_3_, boolean p_228426_5_, Camera p_228426_6_, GameRenderer p_228426_7_, LightTexture p_228426_8_, Matrix4f p_228426_9_, CallbackInfo ci) { - GlStateManager._depthMask(false); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java index f4895c7f8..7f29eef6d 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java @@ -8,7 +8,6 @@ import org.spongepowered.asm.mixin.injection.Inject; 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.core.crumbling.CrumblingRenderer; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent; @@ -24,8 +23,6 @@ import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.culling.Frustum; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.MinecraftForge; @@ -33,7 +30,6 @@ import net.minecraftforge.common.MinecraftForge; @OnlyIn(Dist.CLIENT) @Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after sodium public class LevelRendererMixin { - @Shadow private ClientLevel level; @@ -63,17 +59,4 @@ public class LevelRendererMixin { private void renderBlockBreaking(PoseStack stack, float p_228426_2_, long p_228426_3_, boolean p_228426_5_, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f p_228426_9_, CallbackInfo ci) { CrumblingRenderer.render(level, camera, stack); } - - // Instancing - - /** - * This gets called when a block is marked for rerender by vanilla. - */ - @Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V") - private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) { - if (Backend.isOn()) { - InstancedRenderDispatcher.getBlockEntities(level) - .update(level.getBlockEntity(pos)); - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/PausedPartialTickAccessor.java b/src/main/java/com/jozufozu/flywheel/mixin/PausedPartialTickAccessor.java index ab5e5aa18..8e196640b 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/PausedPartialTickAccessor.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/PausedPartialTickAccessor.java @@ -7,7 +7,6 @@ import net.minecraft.client.Minecraft; @Mixin(Minecraft.class) public interface PausedPartialTickAccessor { - @Accessor("pausePartialTick") - float flywheel$getPartialTicksPaused(); + float flywheel$getPausePartialTick(); } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/fix/FixFabulousDepthMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/fix/FixFabulousDepthMixin.java new file mode 100644 index 000000000..a119b1e09 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/fix/FixFabulousDepthMixin.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.mixin.fix; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.mojang.blaze3d.platform.GlStateManager; + +import net.minecraft.client.renderer.LevelRenderer; + +@Mixin(LevelRenderer.class) +public class FixFabulousDepthMixin { + @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/PostChain;process(F)V", ordinal = 1)) + private void flywheel$disableTransparencyShaderDepth(CallbackInfo ci) { + GlStateManager._depthMask(false); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/fix/FixNormalScalingMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/fix/FixNormalScalingMixin.java new file mode 100644 index 000000000..144d6efa9 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/fix/FixNormalScalingMixin.java @@ -0,0 +1,36 @@ +package com.jozufozu.flywheel.mixin.fix; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.mojang.blaze3d.vertex.PoseStack; + +@Mixin(PoseStack.class) +public class FixNormalScalingMixin { + /** + * Minecraft negates the normal matrix if all scales are equal and negative, but + * does not return afterward. This allows the rest of the method's logic to be + * applied, which negates the matrix again, resulting in the matrix being the + * same as in the beginning. + */ + @Inject(method = "scale(FFF)V", at = @At(value = "INVOKE", target = "Lcom/mojang/math/Matrix3f;mul(F)V", shift = Shift.AFTER), cancellable = true) + private void flywheel$returnAfterNegate(float x, float y, float z, CallbackInfo ci) { + ci.cancel(); + } + + /** + * Minecraft takes the inverse cube root of the product of all scales to provide a + * rough estimate for normalization so that it does not need to be done later. It + * does not make sense for this "normalization factor" to be negative though, as + * that would invert all normals. Additionally, Minecraft's fastInvCubeRoot method + * does not work for negative numbers. + */ + @ModifyArg(method = "scale(FFF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;fastInvCubeRoot(F)F")) + private float flywheel$absInvCbrtInput(float input) { + return Math.abs(input); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java index e16d78545..200afb9c8 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java @@ -7,27 +7,17 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; 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 net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -@OnlyIn(Dist.CLIENT) @Mixin(targets = "net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$RenderChunk$RebuildTask") public class ChunkRebuildHooksMixin { - - @Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true) - private void addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set set, E be, CallbackInfo ci) { - if (Backend.canUseInstancing(be.getLevel())) { - if (InstancedRenderRegistry.canInstance(be.getType())) - InstancedRenderDispatcher.getBlockEntities(be.getLevel()).queueAdd(be); - - if (InstancedRenderRegistry.shouldSkipRender(be)) - ci.cancel(); + @Inject(method = "handleBlockEntity(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$CompiledChunk;Ljava/util/Set;Lnet/minecraft/world/level/block/entity/BlockEntity;)V", at = @At("HEAD"), cancellable = true) + private void flywheel$tryAddBlockEntity(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set globalBlockEntities, BlockEntity blockEntity, CallbackInfo ci) { + if (InstancedRenderDispatcher.tryAddBlockEntity(blockEntity)) { + ci.cancel(); } } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java new file mode 100644 index 000000000..88136cd63 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java @@ -0,0 +1,40 @@ +package com.jozufozu.flywheel.mixin.instancemanage; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +@Mixin(LevelRenderer.class) +public class InstanceUpdateMixin { + @Shadow + private ClientLevel level; + + /** + * This gets called when a block is marked for rerender by vanilla. + */ + @Inject(method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V", at = @At("TAIL")) + private void flywheel$checkUpdate(BlockPos pos, BlockState oldState, BlockState newState, CallbackInfo ci) { + if (!Backend.isOn()) { + return; + } + + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity == null) { + return; + } + + InstancedRenderDispatcher.getBlockEntities(level) + .queueUpdate(blockEntity); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java new file mode 100644 index 000000000..782bfc482 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java @@ -0,0 +1,23 @@ +package com.jozufozu.flywheel.mixin.sodium; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; + +import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderRebuildTask; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.world.level.block.entity.BlockEntity; + +@Mixin(value = ChunkRenderRebuildTask.class, remap = false) +public class ChunkRenderRebuildTaskMixin { + @Redirect(method = "performBuild", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/blockentity/BlockEntityRenderDispatcher;getRenderer(Lnet/minecraft/world/level/block/entity/BlockEntity;)Lnet/minecraft/client/renderer/blockentity/BlockEntityRenderer;")) + private BlockEntityRenderer flywheel$redirectGetRenderer(BlockEntityRenderDispatcher dispatcher, BlockEntity blockEntity) { + if (InstancedRenderDispatcher.tryAddBlockEntity(blockEntity)) { + return null; + } + return dispatcher.getRenderer(blockEntity); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/sodium/FlywheelCompatMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/sodium/FlywheelCompatMixin.java new file mode 100644 index 000000000..4e2d8e406 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/sodium/FlywheelCompatMixin.java @@ -0,0 +1,24 @@ +package com.jozufozu.flywheel.mixin.sodium; + +import java.util.Collection; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +import me.jellysquid.mods.sodium.client.compat.FlywheelCompat; +import net.minecraft.world.level.block.entity.BlockEntity; + +/** + * Overwrite all methods in this class with stubs. Flywheel compatibility is now added by Flywheel itself through mixins. + */ +@Mixin(value = FlywheelCompat.class, remap = false) +public class FlywheelCompatMixin { + @Overwrite + public static boolean addAndFilterBEs(BlockEntity blockEntity) { + return true; + } + + @Overwrite + public static void filterBlockEntityList(Collection blockEntities) { + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/sodium/SodiumMixinPlugin.java b/src/main/java/com/jozufozu/flywheel/mixin/sodium/SodiumMixinPlugin.java new file mode 100644 index 000000000..6107e740d --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/sodium/SodiumMixinPlugin.java @@ -0,0 +1,48 @@ +package com.jozufozu.flywheel.mixin.sodium; + +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; + +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import com.google.common.base.Suppliers; + +import net.minecraftforge.fml.loading.LoadingModList; + +public class SodiumMixinPlugin implements IMixinConfigPlugin { + private static final Supplier IS_SODIUM_LOADED = Suppliers.memoize(() -> LoadingModList.get().getModFileById("rubidium") != null); + + @Override + public void onLoad(String mixinPackage) { + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return IS_SODIUM_LOADED.get(); + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + } +} diff --git a/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java b/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java index 20ed918df..79d4f5442 100644 --- a/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java +++ b/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java @@ -37,7 +37,7 @@ public class AnimationTickHolder { public static float getPartialTicks() { Minecraft mc = Minecraft.getInstance(); - return (mc.isPaused() ? ((PausedPartialTickAccessor) mc).flywheel$getPartialTicksPaused() : mc.getFrameTime()); + return (mc.isPaused() ? ((PausedPartialTickAccessor) mc).flywheel$getPausePartialTick() : mc.getFrameTime()); } // Unused but might be useful for debugging. diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 3ddcc67c7..2bfab3886 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -11,7 +11,7 @@ displayName = "Flywheel" logoFile = "logo.png" displayURL = "https://www.curseforge.com/minecraft/mc-mods/flywheel" updateJSONURL = "https://api.modrinth.com/updates/flywheel/forge_updates.json" -authors = "Jozufozu" +authors = "Jozufozu, PepperCode1" description = ''' A modern engine for modded minecraft.''' diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json index 33931bb88..e019e719f 100644 --- a/src/main/resources/flywheel.mixins.json +++ b/src/main/resources/flywheel.mixins.json @@ -12,7 +12,6 @@ "ClientLevelMixin", "ClientMainMixin", "EntityTypeMixin", - "FixFabulousDepthMixin", "FrustumMixin", "GlStateManagerMixin", "LevelRendererAccessor", @@ -20,9 +19,12 @@ "PausedPartialTickAccessor", "RenderTexturesMixin", "RenderTypeMixin", + "fix.FixFabulousDepthMixin", + "fix.FixNormalScalingMixin", "instancemanage.ChunkRebuildHooksMixin", "instancemanage.InstanceAddMixin", "instancemanage.InstanceRemoveMixin", + "instancemanage.InstanceUpdateMixin", "light.LightUpdateMixin", "light.NetworkLightUpdateMixin", "matrix.Matrix3fMixin", diff --git a/src/main/resources/flywheel.sodium.mixins.json b/src/main/resources/flywheel.sodium.mixins.json new file mode 100644 index 000000000..19bff5bf8 --- /dev/null +++ b/src/main/resources/flywheel.sodium.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.jozufozu.flywheel.mixin.sodium", + "compatibilityLevel": "JAVA_17", + "refmap": "flywheel.refmap.json", + "plugin": "com.jozufozu.flywheel.mixin.sodium.SodiumMixinConfigPlugin", + "client": [ + "ChunkRenderRebuildTaskMixin", + "FlywheelCompatMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} From 4c94abc2e84e25c700c42466b57ae27935db4393 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:06:34 -0700 Subject: [PATCH 6/6] Update light mixins ClientboundLevelChunkWithLightPacket now also causes the LightUpdater to notify its listeners --- .../mixin/light/LightUpdateMixin.java | 19 ++++++------ .../mixin/light/NetworkLightUpdateMixin.java | 30 +++++++++++++++---- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/jozufozu/flywheel/mixin/light/LightUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/light/LightUpdateMixin.java index b4b97fe20..d11c29ede 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/light/LightUpdateMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/light/LightUpdateMixin.java @@ -1,6 +1,8 @@ package com.jozufozu.flywheel.mixin.light; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -12,12 +14,12 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.SectionPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.chunk.ChunkSource; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -@OnlyIn(Dist.CLIENT) @Mixin(ClientChunkCache.class) public abstract class LightUpdateMixin extends ChunkSource { + @Shadow + @Final + ClientLevel level; /** * JUSTIFICATION: This method is called after a lighting tick once per subchunk where a @@ -25,12 +27,9 @@ public abstract class LightUpdateMixin extends ChunkSource { * the rendering system that it needs to redraw a chunk. It does all that work asynchronously, * and we should too. */ - @Inject(at = @At("HEAD"), method = "onLightUpdate") - private void onLightUpdate(LightLayer type, SectionPos pos, CallbackInfo ci) { - ClientChunkCache thi = ((ClientChunkCache) (Object) this); - ClientLevel world = (ClientLevel) thi.getLevel(); - - LightUpdater.get(world) - .onLightUpdate(type, pos.asLong()); + @Inject(method = "onLightUpdate(Lnet/minecraft/world/level/LightLayer;Lnet/minecraft/core/SectionPos;)V", at = @At("HEAD")) + private void flywheel$onLightUpdate(LightLayer layer, SectionPos pos, CallbackInfo ci) { + LightUpdater.get(level) + .onLightUpdate(layer, pos.asLong()); } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/light/NetworkLightUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/light/NetworkLightUpdateMixin.java index d38d18fdc..2c1867fa8 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/light/NetworkLightUpdateMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/light/NetworkLightUpdateMixin.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.mixin.light; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -8,25 +9,42 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.jozufozu.flywheel.backend.RenderWork; import com.jozufozu.flywheel.light.LightUpdater; -import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; @Mixin(ClientPacketListener.class) public class NetworkLightUpdateMixin { + @Shadow + private ClientLevel level; - @Inject(at = @At("TAIL"), method = "handleLightUpdatePacket") - private void onLightPacket(ClientboundLightUpdatePacket packet, CallbackInfo ci) { + @Inject(method = "handleLevelChunkWithLight(Lnet/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket;)V", at = @At("TAIL")) + private void flywheel$onLevelChunkWithLight(ClientboundLevelChunkWithLightPacket packet, CallbackInfo ci) { RenderWork.enqueue(() -> { - ClientLevel world = Minecraft.getInstance().level; + ClientLevel level = this.level; - if (world == null) return; + if (level == null) return; int chunkX = packet.getX(); int chunkZ = packet.getZ(); - LightUpdater.get(world) + LightUpdater.get(level) + .onLightPacket(chunkX, chunkZ); + }); + } + + @Inject(method = "handleLightUpdatePacket(Lnet/minecraft/network/protocol/game/ClientboundLightUpdatePacket;)V", at = @At("TAIL")) + private void flywheel$onLightUpdatePacket(ClientboundLightUpdatePacket packet, CallbackInfo ci) { + RenderWork.enqueue(() -> { + ClientLevel level = this.level; + + if (level == null) return; + + int chunkX = packet.getX(); + int chunkZ = packet.getZ(); + + LightUpdater.get(level) .onLightPacket(chunkX, chunkZ); }); }