mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-13 07:46:07 +01:00
Merge branch '1.18/dev' into 1.19/dev
Conflicts: build.gradle gradle.properties src/main/java/com/jozufozu/flywheel/core/virtual/VirtualChunk.java src/main/java/com/jozufozu/flywheel/core/virtual/VirtualRenderWorld.java src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java src/main/resources/flywheel.mixins.json
This commit is contained in:
commit
23860ad857
30 changed files with 642 additions and 586 deletions
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -59,6 +59,8 @@ 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"
|
||||
- "0.6.7"
|
||||
|
@ -94,6 +96,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"
|
||||
|
|
29
README.md
29
README.md
|
@ -1,11 +1,13 @@
|
|||
<div align="center">
|
||||
<img src="https://i.imgur.com/yVFgPpr.png" alt="Logo by @voxel_dani on Twitter" width="250">
|
||||
<h1>Flywheel</h1>
|
||||
<h6>A modern engine for modded Minecraft.</h6>
|
||||
<a href='https://ci.tterrag.com/job/Flywheel/job/Forge/job/1.18/'><img src='https://ci.tterrag.com/job/Flywheel/job/Forge/job/1.18/badge/icon' alt="Jenkins"></a>
|
||||
<a href="https://discord.gg/xjD59ThnXy"><img src="https://img.shields.io/discord/841464837406195712?color=5865f2&label=Discord&style=flat" alt="Discord"></a>
|
||||
<a href="https://www.curseforge.com/minecraft/mc-mods/flywheel"><img src="http://cf.way2muchnoise.eu/486392.svg" alt="Curseforge Downloads"></a>
|
||||
<br>
|
||||
<img src="https://i.imgur.com/yVFgPpr.png" alt="Logo by @voxel_dani on Twitter" width="250">
|
||||
<h1>Flywheel</h1>
|
||||
<h6>A modern engine for modded Minecraft.</h6>
|
||||
<a href='https://ci.tterrag.com/job/Flywheel/job/Forge/job/1.18/'><img src='https://ci.tterrag.com/job/Flywheel/job/Forge/job/1.18/badge/icon' alt="Jenkins"></a>
|
||||
<a href="https://github.com/Jozufozu/Flywheel/blob/HEAD/LICENSE.md"><img src="https://img.shields.io/github/license/Jozufozu/Flywheel?style=flat&color=900c3f" alt="License"></a>
|
||||
<a href="https://discord.gg/xjD59ThnXy"><img src="https://img.shields.io/discord/841464837406195712?color=5865f2&label=Discord&style=flat" alt="Discord"></a>
|
||||
<a href="https://www.curseforge.com/minecraft/mc-mods/flywheel"><img src="http://cf.way2muchnoise.eu/486392.svg" alt="Curseforge Downloads"></a>
|
||||
<a href="https://modrinth.com/mod/flywheel"><img src="https://img.shields.io/modrinth/dt/flywheel?logo=modrinth&label=&suffix=%20&style=flat&color=242629&labelColor=5ca424&logoColor=1c1c1c" alt="Modrinth"></a>
|
||||
<br></br>
|
||||
</div>
|
||||
|
||||
### About
|
||||
|
@ -16,13 +18,13 @@ 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.
|
||||
|
||||
### 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"
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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'
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.19.2
|
||||
|
||||
minecraft_version = 1.19.2
|
||||
|
|
|
@ -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 <T extends BlockEntity> 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<String> debug) {
|
||||
debug.add("");
|
||||
debug.add("Flywheel: " + Flywheel.getVersion());
|
||||
|
|
|
@ -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<BlockPos> 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<BlockPos> getBlockEntitiesPos() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,113 +89,25 @@ 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<BlockPos> getBlockEntitiesPos() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Map.Entry<Heightmap.Types, Heightmap>> 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_) {
|
||||
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 getStartForStructure(Structure structure) {
|
||||
|
@ -199,7 +115,7 @@ public class VirtualChunk extends ChunkAccess {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setStartForStructure(Structure structure, StructureStart start) {
|
||||
public void setStartForStructure(Structure structure, StructureStart structureStart) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -212,7 +128,7 @@ public class VirtualChunk extends ChunkAccess {
|
|||
}
|
||||
|
||||
@Override
|
||||
public LongSet getReferencesForStructure(Structure structure) {
|
||||
public LongSet getReferencesForStructure(Structure pStructure) {
|
||||
return LongSets.emptySet();
|
||||
}
|
||||
|
||||
|
@ -226,17 +142,60 @@ public class VirtualChunk extends ChunkAccess {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAllReferences(Map<Structure, LongSet> structureReferences) {
|
||||
public void setAllReferences(Map<Structure, LongSet> structureReferencesMap) {
|
||||
}
|
||||
|
||||
@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<BlockPos> 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<Block> 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<Block> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Long, VirtualChunk> chunks = new HashMap<>();
|
||||
private final Long2ObjectMap<VirtualChunk> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,14 +10,13 @@ import net.minecraft.world.level.entity.LevelEntityGetter;
|
|||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
public class VirtualLevelEntityGetter<T extends EntityAccess> implements LevelEntityGetter<T> {
|
||||
|
||||
@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<T extends EntityAccess> implements LevelEn
|
|||
}
|
||||
|
||||
@Override
|
||||
public <U extends T> void get(EntityTypeTest<T, U> p_156935_, Consumer<U> p_156936_) {
|
||||
public <U extends T> void get(EntityTypeTest<T, U> test, Consumer<U> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void get(AABB p_156937_, Consumer<T> p_156938_) {
|
||||
public void get(AABB boundingBox, Consumer<T> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U extends T> void get(EntityTypeTest<T, U> p_156932_, AABB p_156933_, Consumer<U> p_156934_) {
|
||||
public <U extends T> void get(EntityTypeTest<T, U> test, AABB bounds, Consumer<U> consumer) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,12 +32,15 @@ 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.gameevent.GameEvent.Context;
|
||||
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.phys.Vec3;
|
||||
|
@ -46,37 +48,40 @@ import net.minecraft.world.scores.Scoreboard;
|
|||
import net.minecraft.world.ticks.LevelTickAccess;
|
||||
|
||||
public class VirtualRenderWorld extends Level implements FlywheelWorld {
|
||||
public final Map<BlockPos, BlockState> blocksAdded = new HashMap<>();
|
||||
public final Map<BlockPos, BlockEntity> besAdded = new HashMap<>();
|
||||
public final Set<SectionPos> 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<Entity> 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<BlockPos, BlockState> blockStates = new HashMap<>();
|
||||
protected final Map<BlockPos, BlockEntity> blockEntities = new HashMap<>();
|
||||
protected final Object2ShortMap<SectionPos> nonEmptyBlockCounts = new Object2ShortOpenHashMap<>();
|
||||
|
||||
protected final LevelEntityGetter<Entity> 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, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,67 +96,145 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run this after you're done using setBlock().
|
||||
*/
|
||||
public void runLightingEngine() {
|
||||
for (Map.Entry<BlockPos, BlockState> 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<BlockEntity> 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
|
||||
|
@ -160,52 +243,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<BlockState> 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<Biome> getBiome(BlockPos pPos) {
|
||||
return super.getBiome(pPos.offset(biomeOffset));
|
||||
public Holder<Biome> getBiome(BlockPos pos) {
|
||||
return super.getBiome(pos.offset(biomeOffset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Holder<Biome> getUncachedNoiseBiome(int pX, int pY, int pZ) {
|
||||
public Holder<Biome> 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<Biome> getNoiseBiome(int pX, int pY, int pZ) {
|
||||
public Holder<Biome> 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
|
||||
|
@ -216,22 +286,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<Block> getBlockTicks() {
|
||||
return level.getBlockTicks();
|
||||
|
@ -243,21 +318,46 @@ 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 playSeededSound(Player player, double x, double y, double z, SoundEvent soundEvent,
|
||||
SoundSource soundSource, float volume, float pitch, long seed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSeededSound(Player player, Entity entity, SoundEvent soundEvent, SoundSource soundSource,
|
||||
float volume, float pitch, long seed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String gatherChunkSourceStats() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
|
@ -272,13 +372,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(GameEvent event, Vec3 position, Context context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -286,50 +397,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 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) {}
|
||||
|
||||
@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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import net.minecraft.client.Minecraft;
|
|||
|
||||
@Mixin(Minecraft.class)
|
||||
public interface PausedPartialTickAccessor {
|
||||
|
||||
@Accessor("pausePartialTick")
|
||||
float flywheel$getPartialTicksPaused();
|
||||
float flywheel$getPausePartialTick();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,82 +1,21 @@
|
|||
package com.jozufozu.flywheel.mixin.instancemanage;
|
||||
|
||||
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.Coerce;
|
||||
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.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
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 abstract class ChunkRebuildHooksMixin {
|
||||
@Unique
|
||||
private Level flywheel$level;
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;Lnet/minecraft/world/level/ChunkPos;DLnet/minecraft/client/renderer/chunk/RenderChunkRegion;Z)V", at = @At("RETURN"))
|
||||
private void setLevel(ChunkRenderDispatcher.RenderChunk this$1, ChunkPos pos, double p_194427_, RenderChunkRegion region, boolean p_194429_, CallbackInfo ci) {
|
||||
flywheel$level = ((RenderChunkExtension) this$1).flywheel$getLevel();
|
||||
}
|
||||
|
||||
@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);
|
||||
public class ChunkRebuildHooksMixin {
|
||||
@Inject(method = "handleBlockEntity(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk$RebuildTask$CompileResults;Lnet/minecraft/world/level/block/entity/BlockEntity;)V", at = @At("HEAD"), cancellable = true)
|
||||
private void flywheel$tryAddBlockEntity(@Coerce Object compileResults, BlockEntity blockEntity, CallbackInfo ci) {
|
||||
if (InstancedRenderDispatcher.tryAddBlockEntity(blockEntity)) {
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
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);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
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") // 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();
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
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;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<Boolean> 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<String> myTargets, Set<String> otherTargets) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> 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) {
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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.'''
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
"ClientLevelMixin",
|
||||
"ClientMainMixin",
|
||||
"EntityTypeMixin",
|
||||
"FixFabulousDepthMixin",
|
||||
"FrustumMixin",
|
||||
"GlStateManagerMixin",
|
||||
"LevelRendererAccessor",
|
||||
|
@ -20,13 +19,12 @@
|
|||
"PausedPartialTickAccessor",
|
||||
"RenderTexturesMixin",
|
||||
"RenderTypeMixin",
|
||||
"fix.FixFabulousDepthMixin",
|
||||
"fix.FixNormalScalingMixin",
|
||||
"instancemanage.ChunkRebuildHooksMixin",
|
||||
"instancemanage.ChunkRenderDispatcherAccessor",
|
||||
"instancemanage.InstanceAddMixin",
|
||||
"instancemanage.InstanceRemoveMixin",
|
||||
"instancemanage.RenderChunkAccessor",
|
||||
"instancemanage.RenderChunkMixin",
|
||||
"instancemanage.SodiumChunkRenderDataMixin",
|
||||
"instancemanage.InstanceUpdateMixin",
|
||||
"light.LightUpdateMixin",
|
||||
"light.NetworkLightUpdateMixin",
|
||||
"matrix.Matrix3fMixin",
|
||||
|
|
14
src/main/resources/flywheel.sodium.mixins.json
Normal file
14
src/main/resources/flywheel.sodium.mixins.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"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"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue