mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-26 06:57:02 +01:00
Improve and fix VirtualRenderWorld
- Fix calling VirtualRenderWorld#getExistingBlockEntity causing a crash - Bump version
This commit is contained in:
parent
833edce4e5
commit
6709870456
7 changed files with 381 additions and 309 deletions
|
@ -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
|
||||
|
|
|
@ -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,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<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_) {
|
||||
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<ConfiguredStructureFeature<?, ?>, StructureStart> pStructureStarts) {
|
||||
public void setAllStarts(Map<ConfiguredStructureFeature<?, ?>, 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<ConfiguredStructureFeature<?, ?>, LongSet> pStructureReferences) {
|
||||
public void setAllReferences(Map<ConfiguredStructureFeature<?, ?>, 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<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,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<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);
|
||||
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<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
|
||||
|
@ -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<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
|
||||
|
@ -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<Block> 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) {
|
||||
|
|
Loading…
Reference in a new issue