diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/CubicChunks.java b/src/main/java/io/github/opencubicchunks/cubicchunks/CubicChunks.java index 2e548924..49b9b72a 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/CubicChunks.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/CubicChunks.java @@ -19,6 +19,8 @@ @Mod("cubicchunks") public class CubicChunks extends CubicChunksBase { protected static CommonConfig config = null; + // For hardcoding height in P1 + public static final int SUPERFLAT_HEIGHT = 5; public CubicChunks(IEventBus modEventBus) { ChunkMap.class.getName(); diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/level/chunk/MixinChunkAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/level/chunk/MixinChunkAccess.java new file mode 100644 index 00000000..87083c13 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/level/chunk/MixinChunkAccess.java @@ -0,0 +1,30 @@ +package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.level.chunk; + +import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloAccess; +import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloPos; +import net.minecraft.core.Registry; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.levelgen.blending.BlendingData; +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; + +@Mixin(ChunkAccess.class) +public abstract class MixinChunkAccess implements CloAccess { + private CloPos cc_cloPos; + + @Inject(method = "", at = @At("RETURN")) + private void onInit(ChunkPos chunkPos, UpgradeData p_187622_, LevelHeightAccessor p_187623_, Registry p_187624_, long p_187625_, LevelChunkSection[] p_187626_, BlendingData p_187627_, + CallbackInfo ci) { + cc_cloPos = CloPos.chunk(chunkPos); + } + + public CloPos cc_getCloPos() { + return cc_cloPos; + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/level/cube/MixinCubeAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/level/cube/MixinCubeAccess.java new file mode 100644 index 00000000..65a4ebeb --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/level/cube/MixinCubeAccess.java @@ -0,0 +1,9 @@ +package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.level.cube; + +import io.github.opencubicchunks.cubicchunks.world.level.cube.CubeAccess; +import org.spongepowered.asm.mixin.Mixin; + +// Needed for DASM to apply +@Mixin(CubeAccess.class) +public class MixinCubeAccess { +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/CloAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/CloAccess.java index 92b4a1ef..3e2aee79 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/CloAccess.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/CloAccess.java @@ -1,4 +1,151 @@ package io.github.opencubicchunks.cubicchunks.world.level.chunklike; -public interface CloAccess { +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import it.unimi.dsi.fastutil.shorts.ShortList; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.BiomeGenerationSettings; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeResolver; +import net.minecraft.world.level.biome.Climate; +import net.minecraft.world.level.block.Block; +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.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LightChunk; +import net.minecraft.world.level.chunk.StructureAccess; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.gameevent.GameEventListenerRegistry; +import net.minecraft.world.level.levelgen.BelowZeroRetrogen; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.NoiseChunk; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.ticks.TickContainerAccess; + +public interface CloAccess extends BlockGetter, BiomeManager.NoiseBiomeSource, LightChunk, StructureAccess { + GameEventListenerRegistry getListenerRegistry(int p_251437_); + + @Nullable BlockState setBlockState(BlockPos p_62087_, BlockState p_62088_, boolean p_62089_); + + void setBlockEntity(BlockEntity p_156114_); + + void addEntity(Entity p_62078_); + + int getHighestFilledSectionIndex(); + + // Deprecated + int getHighestSectionPosition(); + + Set getBlockEntitiesPos(); + + LevelChunkSection[] getSections(); + + LevelChunkSection getSection(int p_187657_); + + Collection> getHeightmaps(); + + void setHeightmap(Heightmap.Types p_62083_, long[] p_62084_); + + Heightmap getOrCreateHeightmapUnprimed(Heightmap.Types p_62079_); + + boolean hasPrimedHeightmap(Heightmap.Types p_187659_); + + int getHeight(Heightmap.Types p_62080_, int p_62081_, int p_62082_); + + // replacement of ChunkPos getPos() + CloPos cc_getCloPos(); + + Map getAllStarts(); + + void setAllStarts(Map p_62090_); + + boolean isYSpaceEmpty(int p_62075_, int p_62076_); + + void setUnsaved(boolean p_62094_); + + boolean isUnsaved(); + + ChunkStatus getStatus(); + + ChunkStatus getHighestGeneratedStatus(); + + void removeBlockEntity(BlockPos p_62101_); + + void markPosForPostprocessing(BlockPos p_62102_); + + ShortList[] getPostProcessing(); + + void addPackedPostProcess(short p_62092_, int p_62093_); + + void setBlockEntityNbt(CompoundTag p_62091_); + + @Nullable CompoundTag getBlockEntityNbt(BlockPos p_62103_); + + @Nullable CompoundTag getBlockEntityNbtForSaving(BlockPos p_62104_); + + void findBlocks(Predicate p_285343_, BiConsumer p_285030_); + + void findBlocks(java.util.function.BiPredicate p_285343_, BiConsumer p_285030_); + + TickContainerAccess getBlockTicks(); + + TickContainerAccess getFluidTicks(); + + ChunkAccess.TicksToSave getTicksForSerialization(); + + UpgradeData getUpgradeData(); + + boolean isOldNoiseGeneration(); + + @Nullable BlendingData getBlendingData(); + + void setBlendingData(BlendingData p_187646_); + + long getInhabitedTime(); + + void incrementInhabitedTime(long p_187633_); + + void setInhabitedTime(long p_62099_); + + boolean isLightCorrect(); + + void setLightCorrect(boolean p_62100_); + + NoiseChunk getOrCreateNoiseChunk(Function p_223013_); + + @Deprecated BiomeGenerationSettings carverBiome(Supplier p_223015_); + + void fillBiomesFromNoise(BiomeResolver p_187638_, Climate.Sampler p_187639_); + + boolean hasAnyStructureReferences(); + + @Nullable BelowZeroRetrogen getBelowZeroRetrogen(); + + boolean isUpgrading(); + + LevelHeightAccessor getHeightAccessorForGeneration(); + + void initializeLightSources(); + + // TODO static methods +// static ShortList getOrCreateOffsetList(ShortList[] p_62096_, int p_62097_); +// +// static record TicksToSave(SerializableTickContainer blocks, SerializableTickContainer fluids); } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ImposterProtoClo.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ImposterProtoClo.java index b34ce141..441aa8d5 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ImposterProtoClo.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ImposterProtoClo.java @@ -1,4 +1,5 @@ package io.github.opencubicchunks.cubicchunks.world.level.chunklike; public interface ImposterProtoClo extends ProtoClo { + // Every method on ImposterProtoChunk is also on a parent class/interface } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/LevelClo.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/LevelClo.java index c1c61549..bf82a65c 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/LevelClo.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/LevelClo.java @@ -1,4 +1,61 @@ package io.github.opencubicchunks.cubicchunks.world.level.chunklike; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.material.FluidState; + public interface LevelClo extends CloAccess { + FluidState getFluidState(int p_62815_, int p_62816_, int p_62817_); + + @Nullable + BlockEntity getBlockEntity(BlockPos p_62868_, LevelChunk.EntityCreationType p_62869_); + + void addAndRegisterBlockEntity(BlockEntity p_156391_); + + boolean isTicking(BlockPos p_156411_); + + void runPostLoad(); + + boolean isEmpty(); + + void replaceWithPacketData( + FriendlyByteBuf p_187972_, CompoundTag p_187973_, Consumer p_187974_ + ); + + void replaceBiomes(FriendlyByteBuf p_275574_); + + void setLoaded(boolean p_62914_); + + Level getLevel(); + + Map getBlockEntities(); + + void postProcessGeneration(); + + void unpackTicks(long p_187986_); + + void registerTickContainerInLevel(ServerLevel p_187959_); + + void unregisterTickContainerFromLevel(ServerLevel p_187980_); + + FullChunkStatus getFullStatus(); + + void setFullStatus(Supplier p_62880_); + + void clearAllBlockEntities(); + + void registerAllBlockEntitiesAfterLevelLoad(); } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ProtoClo.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ProtoClo.java index 33f7371d..cbaa3312 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ProtoClo.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunklike/ProtoClo.java @@ -1,4 +1,50 @@ package io.github.opencubicchunks.cubicchunks.world.level.chunklike; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.CarvingMask; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.levelgen.BelowZeroRetrogen; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.ticks.LevelChunkTicks; + public interface ProtoClo extends CloAccess { + Map getBlockEntities(); + + void addEntity(CompoundTag p_63243_); + + List getEntities(); + + void setStatus(ChunkStatus p_63187_); + + Map getBlockEntityNbts(); + + @Nullable + CarvingMask getCarvingMask(GenerationStep.Carving p_188185_); + + CarvingMask getOrCreateCarvingMask(GenerationStep.Carving p_188191_); + + void setCarvingMask(GenerationStep.Carving p_188187_, CarvingMask p_188188_); + + void setLightEngine(LevelLightEngine p_63210_); + + void setBelowZeroRetrogen(@Nullable BelowZeroRetrogen p_188184_); + + LevelChunkTicks unpackBlockTicks(); + + LevelChunkTicks unpackFluidTicks(); + + // TODO statics +// public static short packOffsetCoordinates(BlockPos p_63281_); +// +// public static BlockPos unpackOffsetCoordinates(short p_63228_, int p_63229_, ChunkPos p_63230_); } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/CubeAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/CubeAccess.java index 08ae746d..3ec90bb4 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/CubeAccess.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/CubeAccess.java @@ -1,6 +1,338 @@ package io.github.opencubicchunks.cubicchunks.world.level.cube; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import com.google.common.collect.Maps; +import io.github.opencubicchunks.cc_core.api.CubicConstants; +import io.github.opencubicchunks.cc_core.utils.Coords; +import io.github.opencubicchunks.cubicchunks.CubicChunks; +import io.github.opencubicchunks.cubicchunks.mixin.DasmRedirect; +import io.github.opencubicchunks.cubicchunks.mixin.TransformFrom; import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloAccess; +import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloPos; +import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.shorts.ShortList; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +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.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeGenerationSettings; +import net.minecraft.world.level.biome.BiomeResolver; +import net.minecraft.world.level.biome.Climate; +import net.minecraft.world.level.block.Block; +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.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.levelgen.BelowZeroRetrogen; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.NoiseChunk; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; +import net.minecraft.world.level.lighting.ChunkSkyLightSources; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.ticks.TickContainerAccess; +import org.jetbrains.annotations.Nullable; + +@DasmRedirect({ "cubeAccessAndDescendants" }) +public abstract class CubeAccess implements CloAccess { + // Fields copied from ChunkAccess, except ChunkPos -> CloPos + protected final ShortList[] postProcessing; + protected volatile boolean unsaved; + private volatile boolean isLightCorrect; + protected final CloPos cloPos; + private long inhabitedTime; + @Nullable + @Deprecated + private BiomeGenerationSettings carverBiomeSettings; + // TODO (P3) NoiseChunk might need to be different + @Nullable protected NoiseChunk noiseChunk; + + protected final UpgradeData upgradeData; + @Nullable + protected BlendingData blendingData; + protected final Map heightmaps = Maps.newEnumMap(Heightmap.Types.class); + protected ChunkSkyLightSources skyLightSources; + private final Map structureStarts = Maps.newHashMap(); + private final Map structuresRefences = Maps.newHashMap(); + protected final Map pendingBlockEntities = Maps.newHashMap(); + protected final Map blockEntities = Maps.newHashMap(); + protected final LevelHeightAccessor levelHeightAccessor; + protected final LevelChunkSection[] sections; + + // Constructor signature matches ChunkAccess for DASM redirect purposes + public CubeAccess( + CloPos cloPos, + UpgradeData upgradeData, + LevelHeightAccessor levelHeightAccessor, + Registry biomeRegistry, + long inhabitedTime, + @Nullable LevelChunkSection[] chunkSections, + @Nullable BlendingData blendingData + ) { + this.cloPos = cloPos; + this.upgradeData = upgradeData; + this.levelHeightAccessor = levelHeightAccessor; + this.sections = new LevelChunkSection[CubicConstants.SECTION_COUNT]; + this.inhabitedTime = inhabitedTime; + this.postProcessing = new ShortList[CubicConstants.SECTION_COUNT]; + this.blendingData = blendingData; + this.skyLightSources = new ChunkSkyLightSources(levelHeightAccessor); + if (chunkSections != null) { + if (this.sections.length == chunkSections.length) { + System.arraycopy(chunkSections, 0, this.sections, 0, this.sections.length); + } else { + CubicChunks.LOGGER.warn("Could not set level cube sections, array length is {} instead of {}", chunkSections.length, this.sections.length); + } + } + + replaceMissingSections(biomeRegistry, this.sections); + } + + private static void replaceMissingSections(Registry p_281389_, LevelChunkSection[] p_282796_) { + for(int i = 0; i < p_282796_.length; ++i) { + if (p_282796_[i] == null) { + p_282796_[i] = new LevelChunkSection(p_281389_); + } + } + } + + @Override @Nullable public abstract BlockState setBlockState(BlockPos p_62087_, BlockState p_62088_, boolean p_62089_); + + @Override public abstract void setBlockEntity(BlockEntity p_156114_); + + @Override public abstract void addEntity(Entity p_62078_); + + // Next two methods are used for vanilla heightmaps/lighting/end gateways. We shouldn't need these + @Override public int getHighestFilledSectionIndex() { + // TODO is there a better dummy value to return? + return -1; + } + + @Override public int getHighestSectionPosition() { + return this.getMinBuildHeight(); + } + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getBlockEntitiesPos()Ljava/util/Set;") + @Override public native Set getBlockEntitiesPos(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getSections()[Lnet/minecraft/world/level/chunk/LevelChunkSection;") + @Override public native LevelChunkSection[] getSections(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getSection(I)Lnet/minecraft/world/level/chunk/LevelChunkSection;") + @Override public native LevelChunkSection getSection(int p_187657_); + + // TODO (P2) heightmap methods on cubes + @Override public Collection> getHeightmaps() { + throw new UnsupportedOperationException(); + } + + @Override public void setHeightmap(Heightmap.Types p_62083_, long[] p_62084_) { + } + + @Override public Heightmap getOrCreateHeightmapUnprimed(Heightmap.Types p_62079_) { + throw new UnsupportedOperationException(); + } + + @Override public boolean hasPrimedHeightmap(Heightmap.Types p_187659_) { + return false; + } + + @Override public int getHeight(Heightmap.Types p_62080_, int p_62081_, int p_62082_) { + return CubicChunks.SUPERFLAT_HEIGHT; + } + // end heightmaps + + @Override public CloPos cc_getCloPos() { + return cloPos; + } + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getStartForStructure(Lnet/minecraft/world/level/levelgen/structure/Structure;)" + + "Lnet/minecraft/world/level/levelgen/structure/StructureStart;") + @Override @Nullable public native StructureStart getStartForStructure(Structure p_223005_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setStartForStructure(Lnet/minecraft/world/level/levelgen/structure/Structure;" + + "Lnet/minecraft/world/level/levelgen/structure/StructureStart;)V") + @Override public native void setStartForStructure(Structure p_223010_, StructureStart p_223011_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getAllStarts()Ljava/util/Map;") + @Override public native Map getAllStarts(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setAllStarts(Ljava/util/Map;)V") + @Override public native void setAllStarts(Map p_62090_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getReferencesForStructure(Lnet/minecraft/world/level/levelgen/structure/Structure;)" + + "Lit/unimi/dsi/fastutil/longs/LongSet;") + @Override public native LongSet getReferencesForStructure(Structure p_223017_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "addReferenceForStructure(Lnet/minecraft/world/level/levelgen/structure/Structure;J)V") + @Override public native void addReferenceForStructure(Structure p_223007_, long p_223008_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getAllReferences()Ljava/util/Map;") + @Override public native Map getAllReferences(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setAllReferences(Ljava/util/Map;)V") + @Override public native void setAllReferences(Map p_187663_); + + @Override public boolean isYSpaceEmpty(int p_62075_, int p_62076_) { + // TODO + return false; + } + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setUnsaved(Z)V") + @Override public native void setUnsaved(boolean p_62094_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "isUnsaved()Z") + @Override public native boolean isUnsaved(); + + @Override public abstract ChunkStatus getStatus(); + + @Override public ChunkStatus getHighestGeneratedStatus() { + // In ChunkAccess this method is only used for below-zero retrogen; with no retrogen it does this + return this.getStatus(); + } + + @Override public abstract void removeBlockEntity(BlockPos p_62101_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "markPosForPostprocessing(Lnet/minecraft/core/BlockPos;)V") + @Override public native void markPosForPostprocessing(BlockPos p_62102_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getPostProcessing()[Lit/unimi/dsi/fastutil/shorts/ShortList;") + @Override public native ShortList[] getPostProcessing(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "addPackedPostProcess(SI)V") + @Override public native void addPackedPostProcess(short p_62092_, int p_62093_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setBlockEntityNbt(Lnet/minecraft/nbt/CompoundTag;)V") + @Override public native void setBlockEntityNbt(CompoundTag p_62091_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getBlockEntityNbt(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/nbt/CompoundTag;") + @Override @Nullable public native CompoundTag getBlockEntityNbt(BlockPos p_62103_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getBlockEntityNbtForSaving(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/nbt/CompoundTag;") + @Override @Nullable public native CompoundTag getBlockEntityNbtForSaving(BlockPos p_62104_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "findBlockLightSources(Ljava/util/function/BiConsumer;)V") + @Override public native void findBlockLightSources(BiConsumer p_285269_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "findBlocks(Ljava/util/function/Predicate;Ljava/util/function/BiConsumer;)V") + @Override public native void findBlocks(Predicate p_285343_, BiConsumer p_285030_); + + @Override public void findBlocks(BiPredicate p_285343_, BiConsumer p_285030_) { + BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + + for (int y = 0; y < CubicConstants.DIAMETER_IN_SECTIONS; y++) { + for (int z = 0; z < CubicConstants.DIAMETER_IN_SECTIONS; z++) { + for (int x = 0; x < CubicConstants.DIAMETER_IN_SECTIONS; x++) { + LevelChunkSection levelchunksection = this.getSection(Coords.sectionToIndex(x, y, z)); + if (levelchunksection.maybeHas((state) -> p_285343_.test(state, BlockPos.ZERO))) { + BlockPos blockpos = this.cloPos.cubePos().asSectionPos().offset(x, y, z).origin(); + + for(int sectionLocalY = 0; sectionLocalY < SectionPos.SECTION_SIZE; ++sectionLocalY) { + for(int sectionLocalZ = 0; sectionLocalZ < SectionPos.SECTION_SIZE; ++sectionLocalZ) { + for(int sectionLocalX = 0; sectionLocalX < SectionPos.SECTION_SIZE; ++sectionLocalX) { + BlockState blockstate = levelchunksection.getBlockState(sectionLocalX, sectionLocalY, sectionLocalZ); + mutableBlockPos.setWithOffset(blockpos, sectionLocalX, sectionLocalY, sectionLocalZ); + if (p_285343_.test(blockstate, mutableBlockPos.immutable())) { + p_285030_.accept(mutableBlockPos, blockstate); + } + } + } + } + } + } + } + } + } + + @Override public abstract TickContainerAccess getBlockTicks(); + + @Override public abstract TickContainerAccess getFluidTicks(); + + @Override public abstract ChunkAccess.TicksToSave getTicksForSerialization(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getUpgradeData()Lnet/minecraft/world/level/chunk/UpgradeData;") + @Override public native UpgradeData getUpgradeData(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "isOldNoiseGeneration()Z") + @Override public native boolean isOldNoiseGeneration(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getBlendingData()Lnet/minecraft/world/level/levelgen/blending/BlendingData;") + @Override @Nullable public native BlendingData getBlendingData(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setBlendingData(Lnet/minecraft/world/level/levelgen/blending/BlendingData;)V") + @Override public native void setBlendingData(BlendingData p_187646_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getInhabitedTime()J") + @Override public native long getInhabitedTime(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "incrementInhabitedTime(J)V") + @Override public native void incrementInhabitedTime(long p_187633_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setInhabitedTime(J)V") + @Override public native void setInhabitedTime(long p_62099_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "isLightCorrect()Z") + @Override public native boolean isLightCorrect(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "setLightCorrect(Z)V") + @Override public native void setLightCorrect(boolean p_62100_); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getMinBuildHeight()I") + @Override public native int getMinBuildHeight(); + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getHeight()I") + @Override public native int getHeight(); + + @Override public NoiseChunk getOrCreateNoiseChunk(Function p_223013_) { + throw new UnsupportedOperationException(); // TODO P3 + } + + @Override public BiomeGenerationSettings carverBiome(Supplier p_223015_) { + throw new UnsupportedOperationException(); // TODO P3 + } + + @Override public Holder getNoiseBiome(int p_204347_, int p_204348_, int p_204349_) { + throw new UnsupportedOperationException(); // TODO P3 + } + + @Override public void fillBiomesFromNoise(BiomeResolver p_187638_, Climate.Sampler p_187639_) { + throw new UnsupportedOperationException(); // TODO P3 + } + + @TransformFrom(copyFrom = ChunkAccess.class, value = "hasAnyStructureReferences()Z") + @Override public native boolean hasAnyStructureReferences(); + + @Override @Nullable public BelowZeroRetrogen getBelowZeroRetrogen() { + return null; // No below-zero retrogen in cubic worlds :) + } + + @Override public boolean isUpgrading() { + return false; // Used for below-zero retrogen; not applicable to cubes + } + + @TransformFrom(copyFrom = ChunkAccess.class, value = "getHeightAccessorForGeneration()Lnet/minecraft/world/level/LevelHeightAccessor;") + @Override public native LevelHeightAccessor getHeightAccessorForGeneration(); + + @Override public void initializeLightSources() { + // TODO P2 + } -public class CubeAccess implements CloAccess { + @Override public ChunkSkyLightSources getSkyLightSources() { + throw new UnsupportedOperationException(); // TODO P2 + } } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ImposterProtoCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ImposterProtoCube.java index e73d9ad9..cc8988d9 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ImposterProtoCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ImposterProtoCube.java @@ -2,5 +2,6 @@ import io.github.opencubicchunks.cubicchunks.world.level.chunklike.ImposterProtoClo; -public class ImposterProtoCube extends ProtoCube implements ImposterProtoClo { +// not yet implemented - stub class +public abstract class ImposterProtoCube extends ProtoCube implements ImposterProtoClo { } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/LevelCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/LevelCube.java index 940cc458..e72bdee8 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/LevelCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/LevelCube.java @@ -2,5 +2,9 @@ import io.github.opencubicchunks.cubicchunks.world.level.chunklike.LevelClo; -public class LevelCube extends CubeAccess implements LevelClo { +// not yet implemented - stub class +public abstract class LevelCube extends CubeAccess implements LevelClo { + public LevelCube() { + super(null, null, null, null, 0L, null, null); + } } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ProtoCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ProtoCube.java index cf1e255e..fa5c8382 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ProtoCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/cube/ProtoCube.java @@ -2,5 +2,9 @@ import io.github.opencubicchunks.cubicchunks.world.level.chunklike.ProtoClo; -public class ProtoCube extends CubeAccess implements ProtoClo { +// not yet implemented - stub class +public abstract class ProtoCube extends CubeAccess implements ProtoClo { + public ProtoCube() { + super(null, null, null, null, 0L, null, null); + } } diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 7ff4a573..8c910615 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -26,6 +26,8 @@ "common.server.level.MixinTickingTracker", "common.server.MixinMinecraftServer", "common.TestMixin", + "common.world.level.chunk.MixinChunkAccess", + "common.world.level.cube.MixinCubeAccess", "common.world.level.MixinLevel" ], "client": [], diff --git a/src/main/resources/dasm/sets/sets.dasm b/src/main/resources/dasm/sets/sets.dasm index 668ac721..9a1d4777 100644 --- a/src/main/resources/dasm/sets/sets.dasm +++ b/src/main/resources/dasm/sets/sets.dasm @@ -5,19 +5,32 @@ "net.minecraft.world.level.ChunkPos", "net.minecraft.world.level.chunk.LevelChunk", "net.minecraft.world.level.chunk.ChunkAccess", - "io.github.opencubicchunks.cubicchunks.world.level.cube.LevelCube", + "io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloAccess", "io.github.opencubicchunks.cubicchunks.world.level.cube.CubeAccess" ], "sets": { "general": { "typeRedirects": { "ChunkPos": "CloPos", - "LevelChunk": "LevelCube", + "ChunkAccess": "CloAccess" + }, + "fieldRedirects": { + }, + "methodRedirects": { + "ChunkAccess | ChunkPos getPos()": "cc_getCloPos" + } + }, + "cubeAccessAndDescendants": { + "typeRedirects": { + "ChunkPos": "CloPos", "ChunkAccess": "CubeAccess" }, "fieldRedirects": { + // TODO field redirects seem to break things currently? +// "ChunkAccess | ChunkPos chunkPos": "cloPos" }, "methodRedirects": { + "ChunkAccess | ChunkPos getPos()": "cc_getCloPos" } } } diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/test/misc/TestInterfacesMatchVanillaClasses.java b/src/test/java/io/github/opencubicchunks/cubicchunks/test/misc/TestInterfacesMatchVanillaClasses.java new file mode 100644 index 00000000..36d2b905 --- /dev/null +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/test/misc/TestInterfacesMatchVanillaClasses.java @@ -0,0 +1,76 @@ +package io.github.opencubicchunks.cubicchunks.test.misc; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.stream.Collectors; + +import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloAccess; +import net.minecraft.SharedConstants; +import net.minecraft.server.Bootstrap; +import net.minecraft.world.level.chunk.ChunkAccess; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class TestInterfacesMatchVanillaClasses { + @BeforeAll + public static void setup() { + SharedConstants.tryDetectVersion(); + Bootstrap.bootStrap(); + SharedConstants.IS_RUNNING_IN_IDE = true; + } + + private static String stringifyMethod(Method method) { + return method.getName() + "(" + Arrays.stream(method.getGenericParameterTypes()).map(Type::getTypeName).collect(Collectors.joining(", ")) + ") -> " + method.getGenericReturnType().getTypeName(); + } + + private static boolean isStatic(Method method) { + return Modifier.isStatic(method.getModifiers()); + } + + private void testParityIncludingAncestors(Class vanillaClass, Class cubicClass, Method... excludes) { + var excludesSet = Arrays.stream(excludes) + .map(TestInterfacesMatchVanillaClasses::stringifyMethod) + .collect(Collectors.toSet()); + var vanillaMethods = Arrays.stream(vanillaClass.getMethods()) + .filter(method -> method.getDeclaringClass() != Object.class && !isStatic(method)) + .map(TestInterfacesMatchVanillaClasses::stringifyMethod) + .filter(s -> !excludesSet.contains(s)) + .collect(Collectors.toSet()); + var cubicMethods = Arrays.stream(cubicClass.getMethods()) + .filter(method -> method.getDeclaringClass() != Object.class && !isStatic(method)) + .map(TestInterfacesMatchVanillaClasses::stringifyMethod) + .filter(methodString -> !vanillaMethods.remove(methodString)) // Filter methodStrings that are NOT in vanillaMethods + .toList(); + assertTrue(vanillaMethods.isEmpty() && cubicMethods.isEmpty(), () -> String.format(""" + Expected parity between %s %s and %s %s. + Extra methods in %s: + %s + Extra methods in %s: + %s + + """, + vanillaClass.isInterface() ? "interface" : "class", + vanillaClass.getName(), + cubicClass.isInterface() ? "interface" : "class", + cubicClass.getName(), + vanillaClass.getSimpleName(), + vanillaMethods.isEmpty() ? "[none]" : String.join("\n ", vanillaMethods), + cubicClass.getSimpleName(), + cubicMethods.isEmpty() ? "[none]" : String.join("\n ", cubicMethods))); + } + + @Test public void testChunkAccessCloAccessParity() throws NoSuchMethodException { + testParityIncludingAncestors( + ChunkAccess.class, + CloAccess.class, + ChunkAccess.class.getMethod("getWorldForge"), // TODO need to check existence; this would fail on Fabric + ChunkAccess.class.getMethod("getPos") + ); + } +} diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/test/world/level/chunk/TestCubeAccess.java b/src/test/java/io/github/opencubicchunks/cubicchunks/test/world/level/chunk/TestCubeAccess.java new file mode 100644 index 00000000..4c826bcf --- /dev/null +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/test/world/level/chunk/TestCubeAccess.java @@ -0,0 +1,135 @@ +package io.github.opencubicchunks.cubicchunks.test.world.level.chunk; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +import io.github.opencubicchunks.cc_core.api.CubicConstants; +import io.github.opencubicchunks.cc_core.utils.Coords; +import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloPos; +import io.github.opencubicchunks.cubicchunks.world.level.cube.CubeAccess; +import net.minecraft.SharedConstants; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.server.Bootstrap; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +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.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.gameevent.GameEventListenerRegistry; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.ticks.TickContainerAccess; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class TestCubeAccess { + @BeforeAll + public static void setup() { + SharedConstants.tryDetectVersion(); + Bootstrap.bootStrap(); + SharedConstants.IS_RUNNING_IN_IDE = true; + } + + static class CubeAccessTestImpl extends CubeAccess { + public CubeAccessTestImpl(CloPos cloPos, UpgradeData upgradeData, + LevelHeightAccessor levelHeightAccessor, Registry biomeRegistry, + long inhabitedTime, @Nullable LevelChunkSection[] chunkSections, + @Nullable BlendingData blendingData) { + super(cloPos, upgradeData, levelHeightAccessor, biomeRegistry, inhabitedTime, chunkSections, blendingData); + } + + @Override public GameEventListenerRegistry getListenerRegistry(int p_251437_) { + return null; + } + + @Override public @Nullable BlockState setBlockState(BlockPos blockPos, BlockState state, boolean unused) { + int sectionIndex = Coords.blockToIndex(blockPos); + int localX = Coords.blockToSectionLocal(blockPos.getX()); + int localY = Coords.blockToSectionLocal(blockPos.getY()); + int localZ = Coords.blockToSectionLocal(blockPos.getZ()); + return this.sections[sectionIndex].setBlockState(localX, localY, localZ, state); + } + + @Override public void setBlockEntity(BlockEntity p_156114_) { + + } + + @Override public void addEntity(Entity p_62078_) { + + } + + @Override public ChunkStatus getStatus() { + return null; + } + + @Override public void removeBlockEntity(BlockPos p_62101_) { + + } + + @Override public TickContainerAccess getBlockTicks() { + return null; + } + + @Override public TickContainerAccess getFluidTicks() { + return null; + } + + @Override public ChunkAccess.TicksToSave getTicksForSerialization() { + return null; + } + + @Nullable @Override public BlockEntity getBlockEntity(BlockPos p_45570_) { + return null; + } + + @Override public BlockState getBlockState(BlockPos p_45571_) { + return null; + } + + @Override public FluidState getFluidState(BlockPos p_45569_) { + return null; + } + } + + private void findBlocks(Random random) { + CloPos cubePos = CloPos.cube(random.nextInt(20000)-10000, random.nextInt(20000)-10000, random.nextInt(20000)-10000); + var cubeAccess = new CubeAccessTestImpl(cubePos, mock(), mock(), mock(), 0L, new LevelChunkSection[CubicConstants.SECTION_COUNT], mock()); + Set visitedPositions = new HashSet<>(); + Set expectedPositions = new HashSet<>(); + for (int i = 0; i < 1000; i++) { + BlockPos pos = cubePos.cubePos().asBlockPos(random.nextInt(CubicConstants.DIAMETER_IN_BLOCKS), random.nextInt(CubicConstants.DIAMETER_IN_BLOCKS), random.nextInt(CubicConstants.DIAMETER_IN_BLOCKS)); + if (!visitedPositions.add(pos)) continue; + if (random.nextBoolean()) { + cubeAccess.setBlockState(pos, Blocks.STONE.defaultBlockState(), false); + expectedPositions.add(pos); + } else { + cubeAccess.setBlockState(pos, Blocks.DIRT.defaultBlockState(), false); + } + } + Set foundPositions = new HashSet<>(); + cubeAccess.findBlocks((state, pos) -> state == Blocks.STONE.defaultBlockState(), (pos, state) -> foundPositions.add(new BlockPos(pos))); + assertEquals(expectedPositions, foundPositions); + } + + @Test public void testFindBlocks() { + var random = new Random(-99); + for (int i = 0; i < 100; i++) { + findBlocks(random); + } + } +}