From 29b4a8e9850740037d70d55dbd35e87fee0722d1 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Thu, 2 Jan 2025 08:21:10 -0800 Subject: [PATCH 01/13] Compatibility with Forge+Bukkit hybrid environment --- .github/workflows/build_and_publish.yml | 8 +- build.gradle.kts | 4 + .../core/asm/coremod/CubicChunksCoreMod.java | 7 + .../mixin/core/common/MixinChunk_Column.java | 6 +- .../core/common/MixinChunk_Cubes_Bukkit.java | 1007 +++++++++++++++++ .../core/common/MixinPlayerList_Bukkit.java | 112 ++ .../core/common/MixinWorldServer_Bukkit.java | 434 +++++++ .../core/common/MixinWorld_HeightLimits.java | 10 - .../MixinWorld_HeightLimits_Bukkit_Sided.java | 58 + ...MixinWorld_HeightLimits_Vanilla_Sided.java | 57 + .../MixinDedicatedPlayerList_Bukkit.java | 44 + .../core/util/PlatformCompatUtils.java | 45 + .../cubicchunks.mixins.core.bukkit.json | 19 + .../resources/cubicchunks.mixins.core.json | 4 - .../cubicchunks.mixins.core.vanilla.json | 20 + 15 files changed, 1814 insertions(+), 21 deletions(-) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Vanilla_Sided.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java create mode 100644 src/main/resources/cubicchunks.mixins.core.bukkit.json create mode 100644 src/main/resources/cubicchunks.mixins.core.vanilla.json diff --git a/.github/workflows/build_and_publish.yml b/.github/workflows/build_and_publish.yml index e35dad011..ea01748c4 100644 --- a/.github/workflows/build_and_publish.yml +++ b/.github/workflows/build_and_publish.yml @@ -8,8 +8,8 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/cache@v2 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: path: | ~/.gradle/caches @@ -20,7 +20,7 @@ jobs: - name: Set up git submodules run: git submodule init && git submodule update - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: java-version: 1.8 - name: Build with Gradle @@ -28,7 +28,7 @@ jobs: sonatypeUsername: ${{ secrets.OSSRH_USERNAME }} sonatypePassword: ${{ secrets.OSSRH_PASSWORD }} run: ./gradlew build publish - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: Compiled jars path: build/libs/* \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 9b0ec6f83..0dc0ce464 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -121,6 +121,9 @@ repositories { maven { setUrl("https://repo.spongepowered.org/maven") } + maven { + setUrl("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") + } } dependencies { @@ -130,6 +133,7 @@ dependencies { compileOnly(sourceSets["optifine_dummy"].output) + compileOnly("org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT") // Spigot API - used for Bukkit sided mixins testImplementation("junit:junit:4.13.2") testImplementation("org.hamcrest:hamcrest-junit:2.0.0.0") testImplementation("it.ozimov:java7-hamcrest-matchers:1.3.0") diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java index 019715d31..bab7d050b 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java @@ -24,6 +24,7 @@ */ package io.github.opencubicchunks.cubicchunks.core.asm.coremod; +import io.github.opencubicchunks.cubicchunks.core.util.PlatformCompatUtils; import mcp.MethodsReturnNonnullByDefault; import net.minecraftforge.common.ForgeVersion; import net.minecraftforge.fml.common.Loader; @@ -104,6 +105,12 @@ public String getAccessTransformerClass() { public static void initMixin() { MixinBootstrap.init(); Mixins.addConfiguration("cubicchunks.mixins.core.json"); + if (PlatformCompatUtils.isHybridEnv()) { + Mixins.addConfiguration("cubicchunks.mixins.core.bukkit.json"); + System.out.println("Running in Forge+Bukkit hybrid environment, using compatibility mixins"); + } else { + Mixins.addConfiguration("cubicchunks.mixins.core.vanilla.json"); + } Mixins.addConfiguration("cubicchunks.mixins.fixes.json"); Mixins.addConfiguration("cubicchunks.mixins.selectable.json"); Mixins.addConfiguration("cubicchunks.mixins.noncritical.json"); diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Column.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Column.java index 3bf426a7d..ec6c55bd4 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Column.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Column.java @@ -88,7 +88,7 @@ public abstract class MixinChunk_Column { if (cachedCube != null && cachedCube.getY() == cubeY) { return cachedCube; } - return getWorld().getCubeCache().getLoadedCube(x, cubeY, z); + return getCubicWorld().getCubeCache().getLoadedCube(x, cubeY, z); } @@ -96,7 +96,7 @@ public abstract class MixinChunk_Column { if (cachedCube != null && cachedCube.getY() == cubeY) { return cachedCube; } - return getWorld().getCubeCache().getCube(x, cubeY, z); + return getCubicWorld().getCubeCache().getCube(x, cubeY, z); } @@ -138,7 +138,7 @@ public abstract class MixinChunk_Column { } @Unique @SuppressWarnings({"unchecked", "AddedMixinMembersNamePattern"}) - public T getWorld() { + public T getCubicWorld() { return (T) this.world; } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java new file mode 100644 index 000000000..b66131317 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java @@ -0,0 +1,1007 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import static io.github.opencubicchunks.cubicchunks.api.util.Coords.blockToCube; +import static io.github.opencubicchunks.cubicchunks.api.util.Coords.blockToLocal; + +import com.google.common.base.Predicate; +import io.github.opencubicchunks.cubicchunks.api.util.Coords; +import io.github.opencubicchunks.cubicchunks.api.util.CubePos; +import io.github.opencubicchunks.cubicchunks.api.world.IColumn; +import io.github.opencubicchunks.cubicchunks.api.world.ICube; +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import io.github.opencubicchunks.cubicchunks.api.world.IHeightMap; +import io.github.opencubicchunks.cubicchunks.api.world.IMinMaxHeight; +import io.github.opencubicchunks.cubicchunks.core.CubicChunksConfig; +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; +import io.github.opencubicchunks.cubicchunks.core.world.ClientHeightMap; +import io.github.opencubicchunks.cubicchunks.core.world.IColumnInternal; +import io.github.opencubicchunks.cubicchunks.core.world.ServerHeightMap; +import io.github.opencubicchunks.cubicchunks.core.world.StagingHeightMap; +import io.github.opencubicchunks.cubicchunks.core.world.column.ColumnTileEntityMap; +import io.github.opencubicchunks.cubicchunks.core.world.column.CubeMap; +import io.github.opencubicchunks.cubicchunks.core.world.cube.BlankCube; +import io.github.opencubicchunks.cubicchunks.core.world.cube.Cube; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ClassInheritanceMultiMap; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.ChunkEvent.Load; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +/** + * Modifies vanilla code in Chunk to use Cubes [Copied from {@link io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinChunk_Cubes}] + */ +// TODO: redirect isChunkLoaded where needed +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@Mixin(value = Chunk.class, priority = 999) +// soft implements for IColumn and IColumnInternal +// we can't implement them directly as that causes FG6+ to reobfuscate IColumn#getHeightValue(int, int) +// into vanilla SRG name, which breaks API and mixins +@Implements({ + @Interface(iface = IColumn.class, prefix = "chunk$"), + @Interface(iface = IColumnInternal.class, prefix = "chunk_internal$") +}) +public abstract class MixinChunk_Cubes_Bukkit { + + @Shadow @Final private ExtendedBlockStorage[] storageArrays; + @Shadow @Final public static ExtendedBlockStorage NULL_BLOCK_STORAGE; + + @Shadow private boolean hasEntities; + @Shadow @Final public int x; + @Shadow @Final public int z; + @Shadow @Final private ClassInheritanceMultiMap[] entityLists; + + @Shadow @Final @Mutable private Map tileEntities; + + @Shadow @Final private int[] heightMap; + @Shadow @Final private World world; + @Shadow private boolean loaded; + @Shadow private boolean ticked; + @Shadow private boolean isLightPopulated; + @Shadow private boolean dirty; + /* + * WARNING: WHEN YOU RENAME ANY OF THESE 3 FIELDS RENAME CORRESPONDING + * FIELDS IN "cubicchunks.asm.mixin.core.client.MixinChunk_Cubes" and + * "cubicchunks.asm.mixin.core.common.MixinChunk_Columns". + */ + private CubeMap cubeMap; + private IHeightMap opacityIndex; + private Cube cachedCube; // todo: make it always nonnull using BlankCube + private StagingHeightMap stagingHeightMap; + private boolean isColumn = false; + + private ChunkPrimer compatGenerationPrimer; + + @Shadow public abstract byte[] getBiomeArray(); + + @SuppressWarnings({"deprecation", "RedundantSuppression"}) + @Shadow public abstract int getHeightValue(int x, int z); + + @Shadow public abstract int getLightFor(EnumSkyBlock type, BlockPos pos); + + @Unique @SuppressWarnings({"unchecked", "AddedMixinMembersNamePattern"}) + public T getWorld() { + return (T) this.world; + } + + // TODO: make it go through cube raw access methods + // TODO: make cube an interface, use the implementation only here + @Unique @Nullable + private ExtendedBlockStorage getEBS_CubicChunks(int index) { + if (!isColumn) { + // vanilla case, subtract minHeight for extended height support + return storageArrays[index - Coords.blockToCube(getWorld().getMinHeight())]; + } + if (cachedCube != null && cachedCube.getY() == index) { + return cachedCube.getStorage(); + } + Cube cube = getWorld().getCubeCache().getCube(this.x, index, this.z); + if (!(cube instanceof BlankCube)) { + cachedCube = cube; + } + return cube.getStorage(); + } + + // setEBS is unlikely to be used extremely frequently, no caching + @Unique private void setEBS_CubicChunks(int index, ExtendedBlockStorage ebs) { + if (!isColumn) { + // vanilla case, subtract minHeight for extended height support + storageArrays[index - Coords.blockToCube(getWorld().getMinHeight())] = ebs; + return; + } + if (index >= 0 && index < 16) { + storageArrays[index] = ebs; + } + if (cachedCube != null && cachedCube.getY() == index) { + cachedCube.setStorage(ebs); + return; + } + Cube loaded = getWorld().getCubeCache().getLoadedCube(this.x, index, this.z); + if (loaded == null) { + // BlankCube clientside. This is the only case where getEBS doesn't create cube + return; + } + if (loaded.getStorage() == null) { + loaded.setStorage(ebs); + } else { + throw new IllegalStateException(String.format( + "Attempted to set a Cube ExtendedBlockStorage that already exists. " + + "This is not supported. " + + "CubePos(%d, %d, %d), loadedCube(%s), loadedCubeStorage(%s)", + this.x, index, this.z, + loaded, loaded.getStorage())); + } + } + + // modify vanilla: + + @Inject(method = "(Lnet/minecraft/world/World;II)V", at = @At(value = "RETURN")) + private void cubicChunkColumn_construct(World world, int x, int z, CallbackInfo cbi) { + if (world == null) { + // Some mods construct chunks with null world, ignore them + return; + } + if (!((ICubicWorld) world).isCubicWorld()) { + return; + } + this.isColumn = true; + // this.lightManager = world.getLightingManager(); + + this.cubeMap = new CubeMap(); + //clientside we don't really need that much data. we actually only need top and bottom block Y positions + if (world.isRemote) { + this.opacityIndex = new ClientHeightMap((Chunk) (Object) this, heightMap); + } else { + this.opacityIndex = new ServerHeightMap(heightMap); + } + this.stagingHeightMap = new StagingHeightMap(); + // instead of redirecting access to this map, just make the map do the work + this.tileEntities = new ColumnTileEntityMap((IColumn) this); + + // this.chunkSections = null; + // this.skylightUpdateMap = null; + + Arrays.fill(getBiomeArray(), (byte) -1); + } + + @ModifyConstant(method = "(Lnet/minecraft/world/World;II)V", constant = @Constant(intValue = 16), + slice = @Slice( + from = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;neighbors:I" // Add from to avoid expected changes + ), + to = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + opcode = Opcodes.PUTFIELD + ))) + private int modifySectionArrayLength(int sixteen, World worldIn, int x, int z) { + if (worldIn == null) { + // Some mods construct chunks with null world, ignore them + return sixteen; + } + if (!((ICubicWorld) worldIn).isCubicWorld()) { + IMinMaxHeight y = (IMinMaxHeight) worldIn; + return Coords.blockToCube(y.getMaxHeight()) - Coords.blockToCube(y.getMinHeight()); + } + return sixteen; + } + + @Redirect(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", + at = @At( + value = "FIELD", + args = "array=get", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" + )) + private ExtendedBlockStorage init_getStorage(ExtendedBlockStorage[] ebs, int y) { + return ebs[y - (this.isColumn ? 0 : Coords.blockToCube(((IMinMaxHeight) world).getMinHeight()))]; + } + + @Redirect(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", + at = @At( + value = "FIELD", + args = "array=set", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" + )) + private void getBlockState_getMaxHeight(ExtendedBlockStorage[] ebs, int y, ExtendedBlockStorage val) { + ebs[y - (this.isColumn ? 0 : Coords.blockToCube(((IMinMaxHeight) world).getMinHeight()))] = val; + } + + @ModifyConstant(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", + constant = @Constant(intValue = 16, ordinal = 0), require = 1) + private int getInitChunkLoopEnd(int _16, World world, ChunkPrimer primer, int x, int z) { + if (((ICubicWorldInternal.Server) world).isCompatGenerationScope()) { + this.compatGenerationPrimer = primer; + return -1; + } + return _16; + } + + public ChunkPrimer chunk_internal$getCompatGenerationPrimer() { + return compatGenerationPrimer; + } + + // private ExtendedBlockStorage getLastExtendedBlockStorage() - shouldn't be used by anyone + + // this method can't be saved by just redirecting EBS access + @Inject(method = "getTopFilledSegment", at = @At(value = "HEAD"), cancellable = true) + private void getTopFilledSegment_CubicChunks(CallbackInfoReturnable cbi) { + if (!isColumn) { + return; + } + int blockY = Coords.NO_HEIGHT; + for (int localX = 0; localX < Cube.SIZE; localX++) { + for (int localZ = 0; localZ < Cube.SIZE; localZ++) { + int y = this.opacityIndex.getTopBlockY(localX, localZ); + if (y > blockY) { + blockY = y; + } + } + } + if (blockY < getWorld().getMinHeight()) { + // PANIC! + // this column doesn't have any blocks in it that aren't air! + // but we can't return null here because vanilla code expects there to be a surface down there somewhere + // we don't actually know where the surface is yet, because maybe it hasn't been generated + // but we do know that the surface has to be at least at sea level, + // so let's go with that for now and hope for the best + + int ret = Coords.cubeToMinBlock(Coords.blockToCube(this.getWorld().provider.getAverageGroundLevel())); + cbi.setReturnValue(ret); + return; + } + int ret = Coords.cubeToMinBlock(Coords.blockToCube(blockY)); // return the lowest block in the Cube (kinda weird I know) + cbi.setReturnValue(ret); + } + + /* + Light update code called from this: + + if (addedNewCube) { + generateSkylightMap(); + } else { + if (placingOpaque) { + if (placingNewTopBlock) { + relightBlock(x, y + 1, z); + } else if (removingTopBlock) { + relightBlock(x, y, z); + } + } + // equivalent to opacityDecreased || (opacityChanged && receivesLight) + // which means: propagateSkylight if it lets more light through, or (it receives any light and opacity changed) + if (opacityChanged && (opacityDecreased || blockReceivesLight)) { + propagateSkylightOcclusion(x, z); + } + } + */ + // ============================================== + // generateSkylightMap + // ============================================== + + @Inject(method = "generateSkylightMap", at = @At(value = "HEAD"), cancellable = true) + private void generateSkylightMap_CubicChunks_Replace(CallbackInfo cbi) { + if (isColumn) { + // TODO: update skylight in cubes marked for update + cbi.cancel(); + } + } + + + @Nullable + @Redirect(method = "generateSkylightMap", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=get" + )) + private ExtendedBlockStorage generateSkylightMapRedirectEBSAccess(ExtendedBlockStorage[] array, int index) { + return getEBS_CubicChunks(index); + } + + // ============================================== + // propagateSkylightOcclusion + // ============================================== + + @Inject(method = "propagateSkylightOcclusion", at = @At(value = "HEAD"), cancellable = true) + private void propagateSkylightOcclusion_CubicChunks_Replace(int x, int z, CallbackInfo cbi) { + if (isColumn) { + cbi.cancel(); + } + } + + // ============================================== + // recheckGaps + // ============================================== + + @Inject(method = "recheckGaps", at = @At(value = "HEAD"), cancellable = true) + private void recheckGaps_CubicChunks_Replace(boolean p_150803_1_, CallbackInfo cbi) { + if (isColumn) { + cbi.cancel(); + } + } + + // private void checkSkylightNeighborHeight(int x, int z, int maxValue) - shouldn't be used by anyone + + // private void updateSkylightNeighborHeight(int x, int z, int startY, int endY) - shouldn't be used by anyone + + // ============================================== + // relightBlock + // ============================================== + + /** + * Modifies the flag variable so that the code always gets into the branch with Chunk.relightBlock redirected below + */ + @ModifyVariable( + method = "setBlockState", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;set(IIILnet/minecraft/block/state/IBlockState;)V" + ), + index = 13, + name = "flag" + ) + private boolean setBlockStateInjectGenerateSkylightMapVanilla(boolean generateSkylight) { + if (!isColumn) { + return generateSkylight; + } + return false; + } + + @Inject(method = "setBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;relightBlock(III)V"), + locals = LocalCapture.CAPTURE_FAILHARD) + private void setBlockState_CubicChunks_relightBlockReplace(BlockPos pos, IBlockState state, CallbackInfoReturnable cir, + int localX, int y, int localZ, int packedXZ, int oldHeightValue, IBlockState oldState, Block newBlock, Block oldBlock, + int oldOpacity, ExtendedBlockStorage ebs, boolean createdNewEbsAboveTop, int newOpacity) { + + if (isColumn && ((IColumn) this).getCube(blockToCube(y)).isInitialLightingDone()) { + if (oldHeightValue == y + 1) { // oldHeightValue is the previous block Y above the top block, so this is the "removing to block" case + getWorld().getLightingManager().doOnBlockSetLightUpdates((Chunk) (Object) this, localX, getHeightValue(localX, localZ), y, localZ); + } else { + getWorld().getLightingManager().doOnBlockSetLightUpdates((Chunk) (Object) this, localX, oldHeightValue, y, localZ); + } + } + } + + @Redirect(method = "setBlockState", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/chunk/Chunk;getLightFor(Lnet/minecraft/world/EnumSkyBlock;Lnet/minecraft/util/math/BlockPos;)I")) + private int setBlockState_CubicChunks_noGetLightFor(Chunk instance, EnumSkyBlock type, BlockPos pos) { + if (!isColumn) { + return instance.getLightFor(type, pos); + } + return 0; + } + + // make relightBlock no-op for cubic chunks, handles by injection above + @Inject(method = "relightBlock", at = @At(value = "HEAD"), cancellable = true) + private void relightBlock_CubicChunks_Replace(int x, int y, int z, CallbackInfo cbi) { + if (isColumn) { + cbi.cancel(); + } + } + + // ============================================== + // getBlockLightOpacity + // ============================================== + + @Redirect(method = "getBlockLightOpacity(III)I", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) + private boolean getBlockLightOpacity_isChunkLoadedCubeRedirect(Chunk chunk, int x, int y, int z) { + if (!isColumn) { + return loaded; + } + ICube cube = ((IColumn) this).getLoadedCube(blockToCube(y)); + return cube != null && cube.isCubeLoaded(); + } + + // ============================================== + // getBlockState + // ============================================== + + @ModifyConstant(method = "getBlockState(III)Lnet/minecraft/block/state/IBlockState;", + constant = @Constant(expandZeroConditions = Constant.Condition.GREATER_THAN_OR_EQUAL_TO_ZERO), + require = 1) + private int getBlockState_getMinHeight(int zero) { + return isColumn ? Integer.MIN_VALUE : getWorld().getMinHeight(); // this one is in block coords, max is in cube coords. Mojang logic. + } + + @Redirect(method = "getBlockState(III)Lnet/minecraft/block/state/IBlockState;", + at = @At( + value = "FIELD", + args = "array=length", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" + )) + private int getBlockState_getMaxHeight(ExtendedBlockStorage[] ebs) { + return isColumn ? Integer.MAX_VALUE : (ebs.length - Coords.blockToCube(getWorld().getMinHeight())); + } + + @Redirect(method = "getBlockState(III)Lnet/minecraft/block/state/IBlockState;", + at = @At( + value = "FIELD", + args = "array=get", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" + )) + private ExtendedBlockStorage getBlockState_getStorage(ExtendedBlockStorage[] ebs, int y) { + return getEBS_CubicChunks(y); + } + + // ============================================== + // setBlockState + // ============================================== + + @Inject(method = "setBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;set" + + "(IIILnet/minecraft/block/state/IBlockState;)V", shift = At.Shift.AFTER)) + private void onEBSSet_setBlockState_setOpacity(BlockPos pos, IBlockState state, CallbackInfoReturnable cir) { + if (!isColumn) { + return; + } + this.dirty = true; + if (((IColumn) this).getCube(blockToCube(pos.getY())).isSurfaceTracked()) { + opacityIndex.onOpacityChange(blockToLocal(pos.getX()), pos.getY(), blockToLocal(pos.getZ()), state.getLightOpacity(world, pos)); + getWorld().getLightingManager().onHeightUpdate(pos); + } else { + stagingHeightMap.onOpacityChange(blockToLocal(pos.getX()), pos.getY(), blockToLocal(pos.getZ()), state.getLightOpacity(world, pos)); + } + } + + @Redirect(method = "setBlockState", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=get" + )) + private ExtendedBlockStorage setBlockState_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { + return getEBS_CubicChunks(index); + } + + @Redirect(method = "setBlockState", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=set" + )) + private void setBlockState_CubicChunks_EBSSetRedirect(ExtendedBlockStorage[] array, int index, ExtendedBlockStorage val) { + setEBS_CubicChunks(index, val); + } + + @Inject(method = "setBlockState", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=set" + ), cancellable = true) + private void setBlockState_CubicChunks_EBSSetInject(BlockPos pos, IBlockState state, CallbackInfoReturnable cir) { + if (isColumn && getWorld().getCubeCache().getLoadedCube(CubePos.fromBlockCoords(pos)) == null) { + cir.setReturnValue(null); + } + } + + @Redirect(method = "setBlockState", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;dirty:Z")) + private void setIsModifiedFromSetBlockState_Field(Chunk chunk, boolean isModifiedIn, BlockPos pos, IBlockState state) { + if (isColumn) { + getWorld().getCubeFromBlockCoords(pos).markDirty(); + } else { + dirty = isModifiedIn; + } + } + + // ============================================== + // getLightFor + // ============================================== + + @Inject(method = "getLightFor", at = @At("HEAD"), cancellable = true) + private void replacedGetLightForCC(EnumSkyBlock type, BlockPos pos, CallbackInfoReturnable cir) { + if (!isColumn) { + return; + } + ((ICubicWorldInternal) world).getLightingManager().onGetLight(type, pos); + cir.setReturnValue(((Cube) ((IColumn) this).getCube(blockToCube(pos.getY()))).getCachedLightFor(type, pos)); + } + + @Nullable + @Redirect(method = "getLightFor", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=get" + )) + private ExtendedBlockStorage getLightFor_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { + return getEBS_CubicChunks(index); + } + + // ============================================== + // LIGHTING HOOKS + // ============================================== + + @Inject(method = "getLightSubtracted", at = @At("HEAD")) + private void onGetLightSubtracted(BlockPos pos, int amount, CallbackInfoReturnable cir) { + if (!isColumn) { + return; + } + getWorld().getLightingManager().onGetLightSubtracted(pos); + } + + + // ============================================== + // setLightFor + // ============================================== + + @Redirect(method = "setLightFor", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=get" + )) + @Nullable + private ExtendedBlockStorage setLightFor_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { + return getEBS_CubicChunks(index); + } + + @Redirect(method = "setLightFor", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=set" + )) + private void setLightFor_CubicChunks_EBSSetRedirect(ExtendedBlockStorage[] array, int index, ExtendedBlockStorage ebs) { + setEBS_CubicChunks(index, ebs); + } + + @Redirect(method = "setLightFor", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;dirty:Z")) + private void setIsModifiedFromSetLightFor_Field(Chunk chunk, boolean isModifiedIn, EnumSkyBlock type, BlockPos pos, int value) { + if (isColumn) { + getWorld().getCubeFromBlockCoords(pos).markDirty(); + } else { + dirty = isModifiedIn; + } + } + + // ============================================== + // getLightSubtracted + // ============================================== + + @Nullable + @Redirect(method = "getLightSubtracted", at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + args = "array=get" + )) + private ExtendedBlockStorage getLightSubtracted_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { + return getEBS_CubicChunks(index); + } + + // ============================================== + // addEntity + // ============================================== + + @ModifyConstant(method = "addEntity", + constant = @Constant(expandZeroConditions = Constant.Condition.LESS_THAN_ZERO, intValue = 0), + slice = @Slice( + from = @At( + value = "INVOKE:LAST", + target = "Lnet/minecraft/util/math/MathHelper;floor(D)I"), + to = @At( + value = "FIELD:FIRST", + target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;") + ), + require = 1 + ) + private int addEntity_getMinY(int zero) { + return blockToCube(getWorld().getMinHeight()); + } + + @Redirect(method = "addEntity", + at = @At( + value = "FIELD", + args = "array=length", + target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" + ), + require = 2) + private int addEntity_getMaxHeight(ClassInheritanceMultiMap[] entityLists) { + return isColumn ? blockToCube(getWorld().getMaxHeight()) : (entityLists.length - Coords.blockToCube(getWorld().getMinHeight())); + } + + @Redirect(method = "addEntity", + at = @At( + value = "FIELD", + args = "array=get", + target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" + ), + require = 1) + private ClassInheritanceMultiMap addEntity_getEntityList(ClassInheritanceMultiMap[] entityLists, int idx, Entity entity) { + if (!isColumn) { + return entityLists[idx - Coords.blockToCube(getWorld().getMinHeight())]; + } else if (cachedCube != null && cachedCube.getY() == idx) { + cachedCube.getEntityContainer().addEntity(entity); + return null; + } else { + getWorld().getCubeCache().getCube(this.x, idx, this.z).getEntityContainer().addEntity(entity); + return null; + } + } + + @Redirect(method = "addEntity", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/util/ClassInheritanceMultiMap;add(Ljava/lang/Object;)Z" + ), + require = 1) + private boolean addEntity_getEntityList(ClassInheritanceMultiMap obj, Object entity) { + if (!isColumn) { + return obj.add(entity); + } + assert obj == null; + return true; // ignored + } + + // ============================================== + // removeEntityAtIndex + // ============================================== + + @ModifyConstant(method = "removeEntityAtIndex", + constant = @Constant(expandZeroConditions = Constant.Condition.LESS_THAN_ZERO, intValue = 0), + require = 2, + slice = @Slice( + from = @At("HEAD"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/util/ClassInheritanceMultiMap;remove(Ljava/lang/Object;)Z") + ) + ) + private int removeEntityAtIndex_getMinY(int zero) { + return blockToCube(getWorld().getMinHeight()); + } + + @Redirect(method = "removeEntityAtIndex", + at = @At( + value = "FIELD", + args = "array=length", + target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" + ), + require = 2) + private int removeEntityAtIndex_getMaxHeight(ClassInheritanceMultiMap[] entityLists) { + return isColumn ? blockToCube(getWorld().getMaxHeight()) : (entityLists.length - Coords.blockToCube(getWorld().getMinHeight())); + } + + @Redirect(method = "removeEntityAtIndex", + at = @At( + value = "FIELD", + args = "array=get", + target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" + ), + require = 1) + private ClassInheritanceMultiMap removeEntityAtIndex_getEntityList(ClassInheritanceMultiMap[] entityLists, int idx, Entity entity, + int index) { + if (!isColumn) { + return entityLists[idx - Coords.blockToCube(getWorld().getMinHeight())]; + } else if (cachedCube != null && cachedCube.getY() == idx) { + cachedCube.getEntityContainer().remove(entity); + return null; + } else { + getWorld().getCubeCache().getCube(this.x, idx, this.z).getEntityContainer().remove(entity); + return null; + } + } + + @Redirect(method = "removeEntityAtIndex", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/util/ClassInheritanceMultiMap;remove(Ljava/lang/Object;)Z" + ), + require = 1) + private boolean removeEntityAtIndex_getEntityList(ClassInheritanceMultiMap obj, Object entity) { + if (!isColumn) { + return obj.remove(entity); + } + assert obj == null; + return true; // ignored + } + + // ============================================== + // addTileEntity + // ============================================== + + @Redirect(method = "addTileEntity(Lnet/minecraft/tileentity/TileEntity;)V", + at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) + private boolean addTileEntity_isChunkLoadedCubeRedirect(Chunk chunk, TileEntity te) { + if (!isColumn) { + return loaded; + } + ICube cube = ((IColumn) this).getLoadedCube(blockToCube(te.getPos().getY())); + return cube != null && cube.isCubeLoaded(); + } + + // ============================================== + // removeTileEntity + // ============================================== + + @Redirect(method = "removeTileEntity", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) + private boolean removeTileEntity_isChunkLoadedCubeRedirect(Chunk chunk, BlockPos pos) { + if (!isColumn) { + return loaded; + } + ICube cube = ((IColumn) this).getLoadedCube(blockToCube(pos.getY())); + return cube != null && cube.isCubeLoaded(); + } + + // ============================================== + // onLoad + // ============================================== + + @Inject(method = "onLoad", at = @At("HEAD"), cancellable = true) + private void onChunkLoad_CubicChunks(CallbackInfo cbi) { + if (!isColumn) { + return; + } + cbi.cancel(); + this.loaded = true; + for (Cube cube : cubeMap) { + cube.onLoad(); + } + MinecraftForge.EVENT_BUS.post(new Load((Chunk) (Object) this)); + } + + // ============================================== + // onUnload + // ============================================== + + @Inject(method = "onUnload", at = @At("HEAD"), cancellable = true) + private void onChunkUnload_CubicChunks(CallbackInfo cbi) { + if (!isColumn) { + return; + } + cbi.cancel(); + this.loaded = false; + + for (Cube cube : cubeMap) { + cube.onUnload(); + } + MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkEvent.Unload((Chunk) (Object) this)); + } + + // ============================================== + // getEntitiesWithinAABBForEntity + // ============================================== + + @Inject(method = "getEntitiesWithinAABBForEntity", at = @At("HEAD"), cancellable = true) + private void getEntitiesWithinAABBForEntity_CubicChunks(@Nullable Entity entityIn, AxisAlignedBB aabb, + List listToFill, Predicate filter, CallbackInfo cbi) { + if (!isColumn) { + return; + } + cbi.cancel(); + + int minY = MathHelper.floor((aabb.minY - World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); + int maxY = MathHelper.floor((aabb.maxY + World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); + minY = MathHelper.clamp(minY, + blockToCube(getWorld().getMinHeight()), + blockToCube(getWorld().getMaxHeight())); + maxY = MathHelper.clamp(maxY, + blockToCube(getWorld().getMinHeight()), + blockToCube(getWorld().getMaxHeight())); + + for (Cube cube : cubeMap.cubes(minY, maxY)) { + if (cube.getEntityContainer().getEntitySet().isEmpty()) { + continue; + } + for (Entity entity : cube.getEntityContainer().getEntitySet()) { + if (!entity.getEntityBoundingBox().intersects(aabb) || entity == entityIn) { + continue; + } + if (filter == null || filter.apply(entity)) { + listToFill.add(entity); + } + + Entity[] parts = entity.getParts(); + + if (parts != null) { + for (Entity part : parts) { + if (part != entityIn && part.getEntityBoundingBox().intersects(aabb) + && (filter == null || filter.apply(part))) { + listToFill.add(part); + } + } + } + } + } + } + + // ============================================== + // getEntitiesOfTypeWithinAABB + // ============================================== + + @Inject(method = "getEntitiesOfTypeWithinAABB", at = @At("HEAD"), cancellable = true) + private void getEntitiesOfTypeWithinAAAB_CubicChunks(Class entityClass, + AxisAlignedBB aabb, List listToFill, Predicate filter, CallbackInfo cbi) { + if (!isColumn) { + return; + } + cbi.cancel(); + + int minY = MathHelper.floor((aabb.minY - World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); + int maxY = MathHelper.floor((aabb.maxY + World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); + minY = MathHelper.clamp(minY, + blockToCube(getWorld().getMinHeight()), + blockToCube(getWorld().getMaxHeight())); + maxY = MathHelper.clamp(maxY, + blockToCube(getWorld().getMinHeight()), + blockToCube(getWorld().getMaxHeight())); + + for (Cube cube : cubeMap.cubes(minY, maxY)) { + for (T t : cube.getEntityContainer().getEntitySet().getByClass(entityClass)) { + if (t.getEntityBoundingBox().intersects(aabb) && (filter == null || filter.apply(t))) { + listToFill.add(t); + } + } + } + } + + // public boolean needsSaving(boolean p_76601_1_) - TODO: needsSaving + + // ============================================== + // getPrecipitationHeight + // ============================================== + + @Inject(method = "getPrecipitationHeight", at = @At(value = "HEAD"), cancellable = true) + private void getPrecipitationHeight_CubicChunks_Replace(BlockPos pos, CallbackInfoReturnable cbi) { + if (isColumn) { + // TODO: precipitationHeightMap + BlockPos ret = new BlockPos(pos.getX(), ((IColumn) this).getHeightValue(blockToLocal(pos.getX()), pos.getY(), blockToLocal(pos.getZ())), pos.getZ()); + cbi.setReturnValue(ret); + } + } + + // ============================================== + // onTick + // ============================================== + + // TODO: check if we are out of time earlier? + @Inject(method = "onTick", at = @At(value = "RETURN")) + private void onTick_CubicChunks_TickCubes(boolean tryToTickFaster, CallbackInfo cbi) { + if (!isColumn) { + return; + } + this.ticked = true; + this.isLightPopulated = true; + // do nothing, we tick cubes directly + } + + // ============================================== + // isEmptyBetween + // ============================================== + + /** + * @param startY bottom Y coordinate + * @param endY top Y coordinate + * @return true if the specified height range is empty + * @author Barteks2x + * @reason original function limited to storage arrays. + */ + @Overwrite + public boolean isEmptyBetween(int startY, int endY) { + if (startY < getWorld().getMinHeight()) { + startY = getWorld().getMinHeight(); + } + + if (endY >= getWorld().getMaxHeight()) { + endY = getWorld().getMaxHeight() - 1; + } + + for (int i = startY; i <= endY; i += Cube.SIZE) { + ExtendedBlockStorage extendedblockstorage = getEBS_CubicChunks(blockToCube(i)); + + if (extendedblockstorage != NULL_BLOCK_STORAGE && !extendedblockstorage.isEmpty()) { + return false; + } + } + + return true; + } + + // ============================================== + // setStorageArrays + // ============================================== + + @Inject(method = "setStorageArrays", at = @At(value = "HEAD")) + private void setStorageArrays_CubicChunks_NotSupported(ExtendedBlockStorage[] newStorageArrays, CallbackInfo cbi) { + if (isColumn) { + throw new UnsupportedOperationException("setting storage arrays it not supported with cubic chunks"); + } + } + + // ============================================== + // checkLight + // ============================================== + + @Inject(method = "checkLight()V", at = @At(value = "HEAD"), cancellable = true) + private void checkLight_CubicChunks_NotSupported(CallbackInfo cbi) { + if (isColumn) { + // we use FirstLightProcessor instead + cbi.cancel(); + } + } + + // private void setSkylightUpdated() - noone should use it + + // private void checkLightSide(EnumFacing facing) - noone should use it + + // private boolean checkLight(int x, int z) - TODO: checkLight + + // ============================================== + // removeInvalidTileEntity + // ============================================== + + @Redirect(method = "removeInvalidTileEntity", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) + private boolean removeInvalidTileEntity_isChunkLoadedCubeRedirect(Chunk chunk, BlockPos pos) { + if (!isColumn) { + return loaded; + } + ICube cube = ((IColumn) this).getLoadedCube(blockToCube(pos.getY())); + return cube != null && cube.isCubeLoaded(); + } + + // ============================================== + // enqueueRelightChecks + // ============================================== + + @Inject(method = "enqueueRelightChecks", at = @At(value = "HEAD"), cancellable = true) + private void enqueueRelightChecks_CubicChunks(CallbackInfo cbi) { + if (!isColumn) { + return; + } + cbi.cancel(); + if (CubicChunksConfig.relightChecksPerTickPerColumn > 0 && (!world.isRemote || CubicChunksConfig.doClientLightFixes)) { + cubeMap.enqueueRelightChecks(); + } + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit.java new file mode 100644 index 000000000..b4e39c126 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit.java @@ -0,0 +1,112 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import io.github.opencubicchunks.cubicchunks.api.util.Coords; +import io.github.opencubicchunks.cubicchunks.core.entity.ICubicEntityTracker; +import io.github.opencubicchunks.cubicchunks.core.server.ICubicPlayerList; +import io.github.opencubicchunks.cubicchunks.core.server.PlayerCubeMap; +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.management.PlayerList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import javax.annotation.ParametersAreNonnullByDefault; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +@Mixin(PlayerList.class) +public abstract class MixinPlayerList_Bukkit implements ICubicPlayerList { + + @Shadow private int viewDistance; + + @Shadow @Final private MinecraftServer server; + protected int verticalViewDistance = -1; + + @Redirect(method = "playerLoggedOut(Lnet/minecraft/entity/player/EntityPlayerMP;)Ljava/lang/String;", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;markDirty()V", ordinal = 0), + require = 1) // CB method has a different return value + private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP playerIn) { + ICubicWorldInternal world = (ICubicWorldInternal) playerIn.getServerWorld(); + if (world.isCubicWorld()) { + world.getCubeFromCubeCoords(playerIn.chunkCoordX, playerIn.chunkCoordY, playerIn.chunkCoordZ).markDirty(); + } else { + ((World) world).getChunk(playerIn.chunkCoordX, playerIn.chunkCoordZ).markDirty(); + } + } + + @Override public int getVerticalViewDistance() { + return verticalViewDistance < 0 ? viewDistance : verticalViewDistance; + } + + @Override public int getRawVerticalViewDistance() { + return verticalViewDistance; + } + + @Override public void setVerticalViewDistance(int dist) { + this.verticalViewDistance = dist; + + if (this.server.worlds != null) { + for (WorldServer worldserver : this.server.worlds) { + if (worldserver != null && ((ICubicWorld) worldserver).isCubicWorld()) { + ((PlayerCubeMap) worldserver.getPlayerChunkMap()).setPlayerViewDistance(viewDistance, dist); + ((ICubicEntityTracker) worldserver.getEntityTracker()).setVertViewDistance(dist); + } + } + } + } + + @Inject(method = "recreatePlayerEntity", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/gen/ChunkProviderServer;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;")) + private void createPlayerChunk(EntityPlayerMP playerIn, int dimension, boolean conqueredEnd, CallbackInfoReturnable cir) { + if (!((ICubicWorld) playerIn.world).isCubicWorld()) { + return; + } + for (int dCubeY = -8; dCubeY <= 8; dCubeY++) { + ((ICubicWorld) playerIn.world).getCubeFromBlockCoords(playerIn.getPosition().up(Coords.cubeToMinBlock(dCubeY))); + } + } + + @ModifyConstant(method = "recreatePlayerEntity", + constant = @Constant(doubleValue = 256)) + private double getMaxHeight(double _256, EntityPlayerMP playerIn, int dimension, boolean conqueredEnd) { + // +/- 8 chunks around the original position are loaded because of an inject above + if (!playerIn.world.isBlockLoaded(new BlockPos(playerIn))) { + return Double.NEGATIVE_INFINITY; + } + return ((ICubicWorld) playerIn.world).getMaxHeight(); + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java new file mode 100644 index 000000000..73052cc33 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java @@ -0,0 +1,434 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import static io.github.opencubicchunks.cubicchunks.api.util.Coords.cubeToMinBlock; +import static io.github.opencubicchunks.cubicchunks.core.util.ReflectionUtil.cast; + +import io.github.opencubicchunks.cubicchunks.api.util.Coords; +import io.github.opencubicchunks.cubicchunks.api.util.CubePos; +import io.github.opencubicchunks.cubicchunks.api.util.IntRange; +import io.github.opencubicchunks.cubicchunks.api.util.NotCubicChunksWorldException; +import io.github.opencubicchunks.cubicchunks.api.util.XYZMap; +import io.github.opencubicchunks.cubicchunks.api.util.XZMap; +import io.github.opencubicchunks.cubicchunks.api.world.IColumn; +import io.github.opencubicchunks.cubicchunks.api.world.ICube; +import io.github.opencubicchunks.cubicchunks.api.world.ICubeProviderServer; +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorldServer; +import io.github.opencubicchunks.cubicchunks.api.worldgen.ICubeGenerator; +import io.github.opencubicchunks.cubicchunks.core.CubicChunks; +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; +import io.github.opencubicchunks.cubicchunks.core.lighting.LightingManager; +import io.github.opencubicchunks.cubicchunks.core.server.ChunkGc; +import io.github.opencubicchunks.cubicchunks.core.server.CubeProviderServer; +import io.github.opencubicchunks.cubicchunks.core.server.PlayerCubeMap; +import io.github.opencubicchunks.cubicchunks.core.server.SpawnCubes; +import io.github.opencubicchunks.cubicchunks.core.server.VanillaNetworkHandler; +import io.github.opencubicchunks.cubicchunks.core.util.world.CubeSplitTickList; +import io.github.opencubicchunks.cubicchunks.core.util.world.CubeSplitTickSet; +import io.github.opencubicchunks.cubicchunks.core.world.CubeWorldEntitySpawner; +import io.github.opencubicchunks.cubicchunks.core.world.IWorldEntitySpawner; +import io.github.opencubicchunks.cubicchunks.core.world.chunkloader.CubicChunkManager; +import io.github.opencubicchunks.cubicchunks.core.world.cube.Cube; +import io.github.opencubicchunks.cubicchunks.core.world.provider.ICubicWorldProvider; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.EntityTracker; +import net.minecraft.entity.effect.EntityLightningBolt; +import net.minecraft.entity.passive.EntitySkeletonHorse; +import net.minecraft.init.Blocks; +import net.minecraft.server.management.PlayerChunkMap; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.NextTickListEntry; +import net.minecraft.world.World; +import net.minecraft.world.WorldEntitySpawner; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import net.minecraftforge.common.ForgeChunkManager; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +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 java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +/** + * Implementation of {@link ICubicWorldServer} interface. + */ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +@Mixin(WorldServer.class) +@Implements(@Interface(iface = ICubicWorldServer.class, prefix = "world$")) +public abstract class MixinWorldServer_Bukkit extends MixinWorld implements ICubicWorldInternal.Server { + + @Shadow @Mutable @Final private PlayerChunkMap playerChunkMap; + @Shadow @Mutable @Final private WorldEntitySpawner entitySpawner; + @Shadow @Mutable @Final private EntityTracker entityTracker; + @Shadow public boolean disableLevelSaving; + private Map> forcedChunksCubes; + private XYZMap forcedCubes; + private XZMap forcedColumns; + + private ChunkGc worldChunkGc; + private SpawnCubes spawnArea; + private boolean runningCompatibilityGenerator; + private VanillaNetworkHandler vanillaNetworkHandler; + + @Shadow protected abstract void playerCheckLight(); + + @Shadow(remap = false) public abstract boolean addEntity(Entity entityIn, CreatureSpawnEvent.SpawnReason reason); // CB renamed method + + @Shadow public abstract boolean addWeatherEffect(Entity entityIn); + + @Shadow @Mutable @Final private Set pendingTickListEntriesHashSet; + @Shadow @Mutable @Final private List pendingTickListEntriesThisTick; + + @Shadow public abstract PlayerChunkMap getPlayerChunkMap(); + + @Override public void initCubicWorldServer(IntRange heightRange, IntRange generationRange) { + super.initCubicWorld(heightRange, generationRange); + this.isCubicWorld = true; + IWorldEntitySpawner spawner = new CubeWorldEntitySpawner(); + IWorldEntitySpawner.Handler spawnHandler = cast(entitySpawner); + spawnHandler.setEntitySpawner(spawner); + + this.chunkProvider = new CubeProviderServer((WorldServer) (Object) this, + ((ICubicWorldProvider) this.provider).createCubeGenerator()); + + this.vanillaNetworkHandler = new VanillaNetworkHandler((WorldServer) (Object) this); + this.playerChunkMap = new PlayerCubeMap((WorldServer) (Object) this); + + this.forcedChunksCubes = new HashMap<>(); + this.forcedCubes = new XYZMap<>(0.75f, 64*1024); + this.forcedColumns = new XZMap<>(0.75f, 2048); + + this.pendingTickListEntriesHashSet = new CubeSplitTickSet(); + this.pendingTickListEntriesThisTick = new CubeSplitTickList(); + this.worldChunkGc = new ChunkGc(getCubeCache()); + + this.lightingManager = new LightingManager((World) (Object) this); + } + + @Override public VanillaNetworkHandler getVanillaNetworkHandler() { + return vanillaNetworkHandler; + } + + @Override public void setSpawnArea(SpawnCubes spawn) { + this.spawnArea = spawn; + } + + @Override public SpawnCubes getSpawnArea() { + return spawnArea; + } + + @Override public CubeSplitTickSet getScheduledTicks() { + return (CubeSplitTickSet) pendingTickListEntriesHashSet; + } + + @Override public CubeSplitTickList getThisTickScheduledTicks() { + return (CubeSplitTickList) pendingTickListEntriesThisTick; + } + + @Override public void tickCubicWorld() { + if (!this.isCubicWorld()) { + throw new NotCubicChunksWorldException(); + } + getLightingManager().onTick(); + if (this.spawnArea != null) { + this.spawnArea.update((World) (Object) this); + } + } + + @Override public CubeProviderServer getCubeCache() { + if (!this.isCubicWorld()) { + throw new NotCubicChunksWorldException(); + } + return (CubeProviderServer) this.chunkProvider; + } + + @Override public ICubeGenerator getCubeGenerator() { + return getCubeCache().getCubeGenerator(); + } + + + @Override public void removeForcedCube(ICube cube) { + if (!forcedChunksCubes.get(cube.getColumn()).remove(cube)) { + CubicChunks.LOGGER.error("Trying to remove forced cube " + cube.getCoords() + ", but it's not forced!"); + } + forcedCubes.remove(cube); + if (forcedChunksCubes.get(cube.getColumn()).isEmpty()) { + forcedChunksCubes.remove(cube.getColumn()); + forcedColumns.remove(cube.getColumn()); + } + } + + @Override public void addForcedCube(ICube cube) { + if (!forcedChunksCubes.computeIfAbsent(cube.getColumn(), chunk -> new HashSet<>()).add(cube)) { + CubicChunks.LOGGER.error("Trying to add forced cube " + cube.getCoords() + ", but it's already forced!"); + } + forcedCubes.put(cube); + forcedColumns.put(cube.getColumn()); + } + + @Override public XYZMap getForcedCubes() { + return forcedCubes; + } + + @Override public XZMap getForcedColumns() { + return forcedColumns; + } + + @Override public void unloadOldCubes() { + worldChunkGc.chunkGc(); + } + + + /** + * CubicChunks equivalent of {@link ForgeChunkManager#forceChunk(ForgeChunkManager.Ticket, ChunkPos)}. + * + * Can accept tickets from different worlds. + */ + @Override + public void forceChunk(ForgeChunkManager.Ticket ticket, CubePos chunk) { + CubicChunkManager.forceChunk(ticket, chunk); + } + + /** + * CubicChunks equivalent of {@link ForgeChunkManager#reorderChunk(ForgeChunkManager.Ticket, ChunkPos)} + * + * Can accept tickets from different worlds. + */ + @Override + public void reorderChunk(ForgeChunkManager.Ticket ticket, CubePos chunk) { + CubicChunkManager.reorderChunk(ticket, chunk); + } + + /** + * CubicChunks equivalent of {@link ForgeChunkManager#unforceChunk(ForgeChunkManager.Ticket, ChunkPos)} + * + * Can accept tickets from different worlds. + */ + @Override + public void unforceChunk(ForgeChunkManager.Ticket ticket, CubePos chunk) { + CubicChunkManager.unforceChunk(ticket, chunk); + } + + + @Override + public CompatGenerationScope doCompatibilityGeneration() { + runningCompatibilityGenerator = true; + return () -> runningCompatibilityGenerator = false; + } + + @Override + public boolean isCompatGenerationScope() { + return runningCompatibilityGenerator; + } + + /** + * Handles cubic chunks world block updates. + * + * @param cbi callback info + * @author Barteks2x + */ + @Inject(method = "updateBlocks", at = @At("HEAD"), cancellable = true) + private void updateBlocksCubicChunks(CallbackInfo cbi) { + if (!isCubicWorld()) { + return; + } + cbi.cancel(); + this.playerCheckLight(); + + int tickSpeed = this.getGameRules().getInt("randomTickSpeed"); + boolean raining = this.isRaining(); + boolean thundering = this.isThundering(); + this.profiler.startSection("pollingChunks"); + + // CubicChunks - iterate over PlayerCubeMap.TickableChunkContainer instead of Chunks, getTickableChunks already includes forced chunks + PlayerCubeMap.TickableChunkContainer chunks = ((PlayerCubeMap) this.playerChunkMap).getTickableChunks(); + for (Chunk chunk : chunks.columns()) { + tickColumn(raining, thundering, chunk); + } + this.profiler.endStartSection("pollingCubes"); + + if (tickSpeed > 0) { + long worldTime = worldInfo.getWorldTotalTime(); + // CubicChunks - iterate over cubes instead of storage array from Chunk + for (ICube cube : chunks.forcedCubes()) { + tickCube(tickSpeed, cube, worldTime); + } + for (ICube cube : chunks.playerTickableCubes()) { + if (cube == null) { // this is the internal array from the arraylist, anything beyond the size is null + break; + } + tickCube(tickSpeed, cube, worldTime); + } + } + + this.profiler.endSection(); + } + + private void tickCube(int tickSpeed, ICube cube, long worldTime) { + if (!((Cube) cube).checkAndUpdateTick(worldTime)) { + return; + } + int chunkBlockX = cubeToMinBlock(cube.getX()); + int chunkBlockZ = cubeToMinBlock(cube.getZ()); + + this.profiler.startSection("tickBlocks"); + ExtendedBlockStorage ebs = cube.getStorage(); + if (ebs != Chunk.NULL_BLOCK_STORAGE && ebs.needsRandomTick()) { + for (int i = 0; i < tickSpeed; ++i) { + tickNextBlock(chunkBlockX, chunkBlockZ, ebs); + } + } + this.profiler.endSection(); + } + + private void tickNextBlock(int chunkBlockX, int chunkBlockZ, ExtendedBlockStorage ebs) { + this.updateLCG = this.updateLCG * 3 + 1013904223; + int rand = this.updateLCG >> 2; + int localX = rand & 15; + int localZ = rand >> 8 & 15; + int localY = rand >> 16 & 15; + IBlockState state = ebs.get(localX, localY, localZ); + Block block = state.getBlock(); + this.profiler.startSection("randomTick"); + + if (block.getTickRandomly()) { + block.randomTick((World) (Object) this, + new BlockPos(localX + chunkBlockX, localY + ebs.getYLocation(), localZ + chunkBlockZ), state, this.rand); + } + + this.profiler.endSection(); + } + + private void tickColumn(boolean raining, boolean thundering, Chunk chunk) { + int chunkBlockX = chunk.x * 16; + int chunkBlockZ = chunk.z * 16; + this.profiler.startSection("checkNextLight"); + chunk.enqueueRelightChecks(); + this.profiler.endStartSection("tickChunk"); + chunk.onTick(false); + this.profiler.endStartSection("thunder"); + + if (this.provider.canDoLightning(chunk) && raining && thundering && this.rand.nextInt(100000) == 0) { + this.updateLCG = this.updateLCG * 3 + 1013904223; + int rand = this.updateLCG >> 2; + BlockPos strikePos = + this.adjustPosToNearbyEntityCubicChunks(new BlockPos(chunkBlockX + (rand & 15), 0, chunkBlockZ + (rand >> 8 & 15))); + + if (strikePos != null && this.isRainingAt(strikePos)) { + DifficultyInstance difficultyinstance = this.getDifficultyForLocation(strikePos); + + if (this.getGameRules().getBoolean("doMobSpawning") + && this.rand.nextDouble() < (double) difficultyinstance.getAdditionalDifficulty() * 0.01D) { + EntitySkeletonHorse skeletonHorse = new EntitySkeletonHorse((World) (Object) this); + skeletonHorse.setTrap(true); + skeletonHorse.setGrowingAge(0); + skeletonHorse.setPosition((double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ()); + this.addEntity(skeletonHorse, CreatureSpawnEvent.SpawnReason.DEFAULT); // Use default spawn reason + this.addWeatherEffect(new EntityLightningBolt((World) (Object) this, + (double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ(), true)); + } else { + this.addWeatherEffect(new EntityLightningBolt((World) (Object) this, + (double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ(), false)); + } + } + } + + this.profiler.endStartSection("iceandsnow"); + + if (this.provider.canDoRainSnowIce(chunk) && this.rand.nextInt(16) == 0) { + this.updateLCG = this.updateLCG * 3 + 1013904223; + int j2 = this.updateLCG >> 2; + BlockPos block = this.getPrecipitationHeight(new BlockPos(chunkBlockX + (j2 & 15), 0, chunkBlockZ + (j2 >> 8 & 15))); + BlockPos blockBelow = block.down(); + + if (this.isAreaLoaded(blockBelow, 1)) { // Forge: check area to avoid loading neighbors in unloaded chunks + if (this.canBlockFreezeNoWater(blockBelow)) { + this.setBlockState(blockBelow, Blocks.ICE.getDefaultState()); + } + } + + // CubicChunks - isBlockLoaded check + if (raining && isBlockLoaded(block) && this.canSnowAt(block, true)) { + this.setBlockState(block, Blocks.SNOW_LAYER.getDefaultState()); + } + + // CubicChunks - isBlockLoaded check + if (raining && isBlockLoaded(blockBelow) && this.getBiome(blockBelow).canRain()) { + this.getBlockState(blockBelow).getBlock().fillWithRain((World) (Object) this, blockBelow); + } + } + this.profiler.endSection(); + } + + private BlockPos adjustPosToNearbyEntityCubicChunks(BlockPos strikeTarget) { + Chunk column = this.getCubeCache().getColumn(Coords.blockToCube(strikeTarget.getX()), Coords.blockToCube(strikeTarget.getZ()), + ICubeProviderServer.Requirement.GET_CACHED); + strikeTarget = column.getPrecipitationHeight(strikeTarget); + Cube cube = this.getCubeCache().getLoadedCube(CubePos.fromBlockCoords(strikeTarget)); + if (cube == null) { + return null; + } + AxisAlignedBB aabb = (new AxisAlignedBB(strikeTarget)).grow(3.0D); + + Iterable setOfLiving = cube.getEntityContainer().getEntitySet().getByClass(EntityLivingBase.class); + for (EntityLivingBase entity : setOfLiving) { + if (!entity.isEntityAlive()) { + continue; + } + BlockPos entityPos = entity.getPosition(); + if (entityPos.getY() < column.getHeightValue(Coords.blockToLocal(entityPos.getX()), Coords.blockToLocal(entityPos.getZ()))) { + continue; + } + if (entity.getEntityBoundingBox().intersects(aabb)) { + return entityPos; + } + } + return strikeTarget; + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits.java index a8e70c8a0..36c40949a 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits.java @@ -216,16 +216,6 @@ private void isBlockLoaded(BlockPos pos, boolean allowEmpty, CallbackInfoReturna } } - @Redirect(method = "spawnEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;isChunkLoaded(IIZ)Z")) - private boolean spawnEntity_isChunkLoaded(World world, int chunkX, int chunkZ, boolean allowEmpty, Entity ent) { - assert this == (Object) world; - if (isCubicWorld()) { - return this.isBlockLoaded(new BlockPos(cubeToMinBlock(chunkX), ent.posY, cubeToMinBlock(chunkZ)), allowEmpty); - } else { - return this.isChunkLoaded(chunkX, chunkZ, allowEmpty); - } - } - @Redirect(method = "updateEntityWithOptionalForce", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;isChunkLoaded(IIZ)Z", ordinal = 0)) private boolean updateEntityWithOptionalForce_isChunkLoaded0(World world, int chunkX, int chunkZ, boolean allowEmpty, Entity ent, boolean force) { diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java new file mode 100644 index 000000000..72b2c0874 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java @@ -0,0 +1,58 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import static io.github.opencubicchunks.cubicchunks.api.util.Coords.cubeToMinBlock; + +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +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.Redirect; + +/** + * CraftBukkit renamed the {@link World#spawnEntity(Entity)} method, make another injection for it. + */ +@Mixin(World.class) +public abstract class MixinWorld_HeightLimits_Bukkit_Sided implements ICubicWorld { + + @Shadow protected abstract boolean isChunkLoaded(int x, int z, boolean allowEmpty); + + @Shadow public abstract boolean isBlockLoaded(BlockPos pos, boolean allowEmpty); + + // Error is fine here, disabled remap as it's a CB method. + @Redirect(method = "addEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;isChunkLoaded(IIZ)Z"), remap = false) + private boolean addEntity_isChunkLoaded(World world, int chunkX, int chunkZ, boolean allowEmpty, Entity ent) { + assert this == (Object) world; + if (isCubicWorld()) { + return this.isBlockLoaded(new BlockPos(cubeToMinBlock(chunkX), ent.posY, cubeToMinBlock(chunkZ)), allowEmpty); + } else { + return this.isChunkLoaded(chunkX, chunkZ, allowEmpty); + } + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Vanilla_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Vanilla_Sided.java new file mode 100644 index 000000000..990ba1ce0 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Vanilla_Sided.java @@ -0,0 +1,57 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import static io.github.opencubicchunks.cubicchunks.api.util.Coords.cubeToMinBlock; + +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +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.Redirect; + +/** + * Split from {@link MixinWorld_HeightLimits} for compatibility. + */ +@Mixin(World.class) +public abstract class MixinWorld_HeightLimits_Vanilla_Sided implements ICubicWorld { + + @Shadow protected abstract boolean isChunkLoaded(int x, int z, boolean allowEmpty); + + @Shadow public abstract boolean isBlockLoaded(BlockPos pos, boolean allowEmpty); + + @Redirect(method = "spawnEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;isChunkLoaded(IIZ)Z")) + private boolean spawnEntity_isChunkLoaded(World world, int chunkX, int chunkZ, boolean allowEmpty, Entity ent) { + assert this == (Object) world; + if (isCubicWorld()) { + return this.isBlockLoaded(new BlockPos(cubeToMinBlock(chunkX), ent.posY, cubeToMinBlock(chunkZ)), allowEmpty); + } else { + return this.isChunkLoaded(chunkX, chunkZ, allowEmpty); + } + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java new file mode 100644 index 000000000..0440f0d74 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java @@ -0,0 +1,44 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.server; + +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinPlayerList; +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinPlayerList_Bukkit; +import net.minecraft.server.dedicated.DedicatedPlayerList; +import net.minecraft.server.dedicated.DedicatedServer; +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(DedicatedPlayerList.class) +public class MixinDedicatedPlayerList_Bukkit extends MixinPlayerList_Bukkit { + + @Inject(method = "", at = @At(value = "RETURN")) + private void setVerticalViewDistance(DedicatedServer server, CallbackInfo cbi) { + this.setVerticalViewDistance(server.getIntProperty("vertical-view-distance", -1)); + + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java new file mode 100644 index 000000000..0040476f3 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java @@ -0,0 +1,45 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.util; + +public class PlatformCompatUtils { + private PlatformCompatUtils() { + } + + private static final boolean isHybridEnv = isClassLoaded("org.bukkit.Bukkit"); + + public static boolean isClassLoaded(String name) { + try { + Class.forName(name); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + public static boolean isHybridEnv() { + return isHybridEnv; + } +} diff --git a/src/main/resources/cubicchunks.mixins.core.bukkit.json b/src/main/resources/cubicchunks.mixins.core.bukkit.json new file mode 100644 index 000000000..b1b4acf7c --- /dev/null +++ b/src/main/resources/cubicchunks.mixins.core.bukkit.json @@ -0,0 +1,19 @@ +{ + "required": false, + "package": "io.github.opencubicchunks.cubicchunks.core.asm.mixin.core", + "refmap": "cubicchunks.mixins.refmap.json", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.7.10", + "overwrites": { + "conformVisibility": true + }, + "mixins": [], + "client": [], + "server": [ + "common.MixinWorld_HeightLimits_Bukkit_Sided", + "common.MixinPlayerList_Bukkit", + "common.MixinChunk_Cubes_Bukkit", + "server.MixinDedicatedPlayerList_Bukkit", + "common.MixinWorldServer_Bukkit" + ] +} \ No newline at end of file diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 0c44e93c7..0dffbce7e 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -20,7 +20,6 @@ "common.IPlayerChunkMapEntry", "common.MixinAnvilSaveHandler", "common.MixinChunk_Column", - "common.MixinChunk_Cubes", "common.MixinChunkCache_HeightLimits", "common.MixinDerivedWorldInfo", "common.MixinEntity_DeathFix", @@ -28,7 +27,6 @@ "common.MixinEntityTrackerEntry", "common.MixinIBlockAccess_MinMaxHeight", "common.MixinMinecraftServer", - "common.MixinPlayerList", "common.MixinRegionFileCache", "common.MixinStructureStart", "common.MixinWorld", @@ -37,7 +35,6 @@ "common.MixinWorldEntitySpawner", "common.MixinWorldInfo", "common.MixinWorldProvider", - "common.MixinWorldServer", "common.MixinWorldSettings", "common.vanillaclient.ICPacketPlayer", "common.vanillaclient.ICPacketPlayerDigging", @@ -67,7 +64,6 @@ "client.MixinWorldProvider" ], "server": [ - "server.MixinDedicatedPlayerList", "server.MixinDedicatedServer_HeightLimits" ] } \ No newline at end of file diff --git a/src/main/resources/cubicchunks.mixins.core.vanilla.json b/src/main/resources/cubicchunks.mixins.core.vanilla.json new file mode 100644 index 000000000..57386994b --- /dev/null +++ b/src/main/resources/cubicchunks.mixins.core.vanilla.json @@ -0,0 +1,20 @@ +{ + "required": false, + "package": "io.github.opencubicchunks.cubicchunks.core.asm.mixin.core", + "refmap": "cubicchunks.mixins.refmap.json", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.7.10", + "overwrites": { + "conformVisibility": true + }, + "mixins": [ + "common.MixinChunk_Cubes", + "common.MixinWorld_HeightLimits_Vanilla_Sided", + "common.MixinWorldServer", + "common.MixinPlayerList" + ], + "client": [], + "server": [ + "server.MixinDedicatedPlayerList" + ] +} \ No newline at end of file From cbdbbd37c361d960ac334413536add1117a3e9f2 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Thu, 2 Jan 2025 08:23:14 -0800 Subject: [PATCH 02/13] Fix workflow --- .github/workflows/build_and_publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_and_publish.yml b/.github/workflows/build_and_publish.yml index ea01748c4..e765b7d2f 100644 --- a/.github/workflows/build_and_publish.yml +++ b/.github/workflows/build_and_publish.yml @@ -22,6 +22,7 @@ jobs: - name: Set up JDK 1.8 uses: actions/setup-java@v4 with: + distribution: 'temurin' java-version: 1.8 - name: Build with Gradle env: From def8ef2207c3f00ec1397d89a03dbf90b02f92d8 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Thu, 2 Jan 2025 08:24:08 -0800 Subject: [PATCH 03/13] Fix workflow --- .github/workflows/build_and_publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_publish.yml b/.github/workflows/build_and_publish.yml index e765b7d2f..0bb6f1a1a 100644 --- a/.github/workflows/build_and_publish.yml +++ b/.github/workflows/build_and_publish.yml @@ -23,7 +23,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: 1.8 + java-version: '8' - name: Build with Gradle env: sonatypeUsername: ${{ secrets.OSSRH_USERNAME }} From ee2fc233dc2eb581d153288f1ef793ec259d3128 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:09:05 -0800 Subject: [PATCH 04/13] Javadoc comment --- .../mixin/selectable/common/MixinWorldServer_UpdateBlocks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/selectable/common/MixinWorldServer_UpdateBlocks.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/selectable/common/MixinWorldServer_UpdateBlocks.java index 77fa0340c..ae5f2e51f 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/selectable/common/MixinWorldServer_UpdateBlocks.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/selectable/common/MixinWorldServer_UpdateBlocks.java @@ -36,7 +36,7 @@ @Mixin(value = WorldServer.class, priority = 1001) public abstract class MixinWorldServer_UpdateBlocks implements ICubicWorldServer { - /* + /** * This redirection (if selected by {@link io.github.opencubicchunks.cubicchunks.core.asm.CubicChunksMixinConfig}) * will return value {@code 0} instead of {@code getGameRules().getInt("randomTickSpeed")} for cubic type worlds. * Redirected function is located inside WorldServer.updateBlocks() function at a line 404. From fc4a3775866149d57afb528c3c75bc7d6806838a Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Fri, 3 Jan 2025 00:33:53 -0800 Subject: [PATCH 05/13] Deduplicate code --- .../mixin/core/common/MixinChunk_Cubes.java | 2 + .../core/common/MixinChunk_Cubes_Bukkit.java | 1007 ----------------- .../common/MixinChunk_Cubes_Bukkit_Sided.java | 66 ++ .../MixinChunk_Cubes_Vanilla_Sided.java | 59 + .../MixinDedicatedPlayerList_Bukkit.java | 1 - .../cubicchunks.mixins.core.bukkit.json | 2 +- .../resources/cubicchunks.mixins.core.json | 1 + .../cubicchunks.mixins.core.vanilla.json | 2 +- 8 files changed, 130 insertions(+), 1010 deletions(-) delete mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Vanilla_Sided.java diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java index e7ffd3d46..c805c5546 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java @@ -225,6 +225,7 @@ private void cubicChunkColumn_construct(World world, int x, int z, CallbackInfo Arrays.fill(getBiomeArray(), (byte) -1); } + /* @ModifyConstant(method = "(Lnet/minecraft/world/World;II)V", constant = @Constant(intValue = 16), slice = @Slice(to = @At( value = "FIELD", @@ -243,6 +244,7 @@ private int modifySectionArrayLength(int sixteen, World worldIn, int x, int z) { } return sixteen; } + */ // Now moved to MixinChunk_Cubes_Vanilla_Sided @Redirect(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", at = @At( diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java deleted file mode 100644 index b66131317..000000000 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit.java +++ /dev/null @@ -1,1007 +0,0 @@ -/* - * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). - * - * Copyright (c) 2015-2021 OpenCubicChunks - * Copyright (c) 2015-2021 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; - -import static io.github.opencubicchunks.cubicchunks.api.util.Coords.blockToCube; -import static io.github.opencubicchunks.cubicchunks.api.util.Coords.blockToLocal; - -import com.google.common.base.Predicate; -import io.github.opencubicchunks.cubicchunks.api.util.Coords; -import io.github.opencubicchunks.cubicchunks.api.util.CubePos; -import io.github.opencubicchunks.cubicchunks.api.world.IColumn; -import io.github.opencubicchunks.cubicchunks.api.world.ICube; -import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; -import io.github.opencubicchunks.cubicchunks.api.world.IHeightMap; -import io.github.opencubicchunks.cubicchunks.api.world.IMinMaxHeight; -import io.github.opencubicchunks.cubicchunks.core.CubicChunksConfig; -import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; -import io.github.opencubicchunks.cubicchunks.core.world.ClientHeightMap; -import io.github.opencubicchunks.cubicchunks.core.world.IColumnInternal; -import io.github.opencubicchunks.cubicchunks.core.world.ServerHeightMap; -import io.github.opencubicchunks.cubicchunks.core.world.StagingHeightMap; -import io.github.opencubicchunks.cubicchunks.core.world.column.ColumnTileEntityMap; -import io.github.opencubicchunks.cubicchunks.core.world.column.CubeMap; -import io.github.opencubicchunks.cubicchunks.core.world.cube.BlankCube; -import io.github.opencubicchunks.cubicchunks.core.world.cube.Cube; -import mcp.MethodsReturnNonnullByDefault; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.Entity; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ClassInheritanceMultiMap; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.ChunkPrimer; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.world.ChunkEvent.Load; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyConstant; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -/** - * Modifies vanilla code in Chunk to use Cubes [Copied from {@link io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinChunk_Cubes}] - */ -// TODO: redirect isChunkLoaded where needed -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -@Mixin(value = Chunk.class, priority = 999) -// soft implements for IColumn and IColumnInternal -// we can't implement them directly as that causes FG6+ to reobfuscate IColumn#getHeightValue(int, int) -// into vanilla SRG name, which breaks API and mixins -@Implements({ - @Interface(iface = IColumn.class, prefix = "chunk$"), - @Interface(iface = IColumnInternal.class, prefix = "chunk_internal$") -}) -public abstract class MixinChunk_Cubes_Bukkit { - - @Shadow @Final private ExtendedBlockStorage[] storageArrays; - @Shadow @Final public static ExtendedBlockStorage NULL_BLOCK_STORAGE; - - @Shadow private boolean hasEntities; - @Shadow @Final public int x; - @Shadow @Final public int z; - @Shadow @Final private ClassInheritanceMultiMap[] entityLists; - - @Shadow @Final @Mutable private Map tileEntities; - - @Shadow @Final private int[] heightMap; - @Shadow @Final private World world; - @Shadow private boolean loaded; - @Shadow private boolean ticked; - @Shadow private boolean isLightPopulated; - @Shadow private boolean dirty; - /* - * WARNING: WHEN YOU RENAME ANY OF THESE 3 FIELDS RENAME CORRESPONDING - * FIELDS IN "cubicchunks.asm.mixin.core.client.MixinChunk_Cubes" and - * "cubicchunks.asm.mixin.core.common.MixinChunk_Columns". - */ - private CubeMap cubeMap; - private IHeightMap opacityIndex; - private Cube cachedCube; // todo: make it always nonnull using BlankCube - private StagingHeightMap stagingHeightMap; - private boolean isColumn = false; - - private ChunkPrimer compatGenerationPrimer; - - @Shadow public abstract byte[] getBiomeArray(); - - @SuppressWarnings({"deprecation", "RedundantSuppression"}) - @Shadow public abstract int getHeightValue(int x, int z); - - @Shadow public abstract int getLightFor(EnumSkyBlock type, BlockPos pos); - - @Unique @SuppressWarnings({"unchecked", "AddedMixinMembersNamePattern"}) - public T getWorld() { - return (T) this.world; - } - - // TODO: make it go through cube raw access methods - // TODO: make cube an interface, use the implementation only here - @Unique @Nullable - private ExtendedBlockStorage getEBS_CubicChunks(int index) { - if (!isColumn) { - // vanilla case, subtract minHeight for extended height support - return storageArrays[index - Coords.blockToCube(getWorld().getMinHeight())]; - } - if (cachedCube != null && cachedCube.getY() == index) { - return cachedCube.getStorage(); - } - Cube cube = getWorld().getCubeCache().getCube(this.x, index, this.z); - if (!(cube instanceof BlankCube)) { - cachedCube = cube; - } - return cube.getStorage(); - } - - // setEBS is unlikely to be used extremely frequently, no caching - @Unique private void setEBS_CubicChunks(int index, ExtendedBlockStorage ebs) { - if (!isColumn) { - // vanilla case, subtract minHeight for extended height support - storageArrays[index - Coords.blockToCube(getWorld().getMinHeight())] = ebs; - return; - } - if (index >= 0 && index < 16) { - storageArrays[index] = ebs; - } - if (cachedCube != null && cachedCube.getY() == index) { - cachedCube.setStorage(ebs); - return; - } - Cube loaded = getWorld().getCubeCache().getLoadedCube(this.x, index, this.z); - if (loaded == null) { - // BlankCube clientside. This is the only case where getEBS doesn't create cube - return; - } - if (loaded.getStorage() == null) { - loaded.setStorage(ebs); - } else { - throw new IllegalStateException(String.format( - "Attempted to set a Cube ExtendedBlockStorage that already exists. " - + "This is not supported. " - + "CubePos(%d, %d, %d), loadedCube(%s), loadedCubeStorage(%s)", - this.x, index, this.z, - loaded, loaded.getStorage())); - } - } - - // modify vanilla: - - @Inject(method = "(Lnet/minecraft/world/World;II)V", at = @At(value = "RETURN")) - private void cubicChunkColumn_construct(World world, int x, int z, CallbackInfo cbi) { - if (world == null) { - // Some mods construct chunks with null world, ignore them - return; - } - if (!((ICubicWorld) world).isCubicWorld()) { - return; - } - this.isColumn = true; - // this.lightManager = world.getLightingManager(); - - this.cubeMap = new CubeMap(); - //clientside we don't really need that much data. we actually only need top and bottom block Y positions - if (world.isRemote) { - this.opacityIndex = new ClientHeightMap((Chunk) (Object) this, heightMap); - } else { - this.opacityIndex = new ServerHeightMap(heightMap); - } - this.stagingHeightMap = new StagingHeightMap(); - // instead of redirecting access to this map, just make the map do the work - this.tileEntities = new ColumnTileEntityMap((IColumn) this); - - // this.chunkSections = null; - // this.skylightUpdateMap = null; - - Arrays.fill(getBiomeArray(), (byte) -1); - } - - @ModifyConstant(method = "(Lnet/minecraft/world/World;II)V", constant = @Constant(intValue = 16), - slice = @Slice( - from = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;neighbors:I" // Add from to avoid expected changes - ), - to = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - opcode = Opcodes.PUTFIELD - ))) - private int modifySectionArrayLength(int sixteen, World worldIn, int x, int z) { - if (worldIn == null) { - // Some mods construct chunks with null world, ignore them - return sixteen; - } - if (!((ICubicWorld) worldIn).isCubicWorld()) { - IMinMaxHeight y = (IMinMaxHeight) worldIn; - return Coords.blockToCube(y.getMaxHeight()) - Coords.blockToCube(y.getMinHeight()); - } - return sixteen; - } - - @Redirect(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", - at = @At( - value = "FIELD", - args = "array=get", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" - )) - private ExtendedBlockStorage init_getStorage(ExtendedBlockStorage[] ebs, int y) { - return ebs[y - (this.isColumn ? 0 : Coords.blockToCube(((IMinMaxHeight) world).getMinHeight()))]; - } - - @Redirect(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", - at = @At( - value = "FIELD", - args = "array=set", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" - )) - private void getBlockState_getMaxHeight(ExtendedBlockStorage[] ebs, int y, ExtendedBlockStorage val) { - ebs[y - (this.isColumn ? 0 : Coords.blockToCube(((IMinMaxHeight) world).getMinHeight()))] = val; - } - - @ModifyConstant(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", - constant = @Constant(intValue = 16, ordinal = 0), require = 1) - private int getInitChunkLoopEnd(int _16, World world, ChunkPrimer primer, int x, int z) { - if (((ICubicWorldInternal.Server) world).isCompatGenerationScope()) { - this.compatGenerationPrimer = primer; - return -1; - } - return _16; - } - - public ChunkPrimer chunk_internal$getCompatGenerationPrimer() { - return compatGenerationPrimer; - } - - // private ExtendedBlockStorage getLastExtendedBlockStorage() - shouldn't be used by anyone - - // this method can't be saved by just redirecting EBS access - @Inject(method = "getTopFilledSegment", at = @At(value = "HEAD"), cancellable = true) - private void getTopFilledSegment_CubicChunks(CallbackInfoReturnable cbi) { - if (!isColumn) { - return; - } - int blockY = Coords.NO_HEIGHT; - for (int localX = 0; localX < Cube.SIZE; localX++) { - for (int localZ = 0; localZ < Cube.SIZE; localZ++) { - int y = this.opacityIndex.getTopBlockY(localX, localZ); - if (y > blockY) { - blockY = y; - } - } - } - if (blockY < getWorld().getMinHeight()) { - // PANIC! - // this column doesn't have any blocks in it that aren't air! - // but we can't return null here because vanilla code expects there to be a surface down there somewhere - // we don't actually know where the surface is yet, because maybe it hasn't been generated - // but we do know that the surface has to be at least at sea level, - // so let's go with that for now and hope for the best - - int ret = Coords.cubeToMinBlock(Coords.blockToCube(this.getWorld().provider.getAverageGroundLevel())); - cbi.setReturnValue(ret); - return; - } - int ret = Coords.cubeToMinBlock(Coords.blockToCube(blockY)); // return the lowest block in the Cube (kinda weird I know) - cbi.setReturnValue(ret); - } - - /* - Light update code called from this: - - if (addedNewCube) { - generateSkylightMap(); - } else { - if (placingOpaque) { - if (placingNewTopBlock) { - relightBlock(x, y + 1, z); - } else if (removingTopBlock) { - relightBlock(x, y, z); - } - } - // equivalent to opacityDecreased || (opacityChanged && receivesLight) - // which means: propagateSkylight if it lets more light through, or (it receives any light and opacity changed) - if (opacityChanged && (opacityDecreased || blockReceivesLight)) { - propagateSkylightOcclusion(x, z); - } - } - */ - // ============================================== - // generateSkylightMap - // ============================================== - - @Inject(method = "generateSkylightMap", at = @At(value = "HEAD"), cancellable = true) - private void generateSkylightMap_CubicChunks_Replace(CallbackInfo cbi) { - if (isColumn) { - // TODO: update skylight in cubes marked for update - cbi.cancel(); - } - } - - - @Nullable - @Redirect(method = "generateSkylightMap", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=get" - )) - private ExtendedBlockStorage generateSkylightMapRedirectEBSAccess(ExtendedBlockStorage[] array, int index) { - return getEBS_CubicChunks(index); - } - - // ============================================== - // propagateSkylightOcclusion - // ============================================== - - @Inject(method = "propagateSkylightOcclusion", at = @At(value = "HEAD"), cancellable = true) - private void propagateSkylightOcclusion_CubicChunks_Replace(int x, int z, CallbackInfo cbi) { - if (isColumn) { - cbi.cancel(); - } - } - - // ============================================== - // recheckGaps - // ============================================== - - @Inject(method = "recheckGaps", at = @At(value = "HEAD"), cancellable = true) - private void recheckGaps_CubicChunks_Replace(boolean p_150803_1_, CallbackInfo cbi) { - if (isColumn) { - cbi.cancel(); - } - } - - // private void checkSkylightNeighborHeight(int x, int z, int maxValue) - shouldn't be used by anyone - - // private void updateSkylightNeighborHeight(int x, int z, int startY, int endY) - shouldn't be used by anyone - - // ============================================== - // relightBlock - // ============================================== - - /** - * Modifies the flag variable so that the code always gets into the branch with Chunk.relightBlock redirected below - */ - @ModifyVariable( - method = "setBlockState", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;set(IIILnet/minecraft/block/state/IBlockState;)V" - ), - index = 13, - name = "flag" - ) - private boolean setBlockStateInjectGenerateSkylightMapVanilla(boolean generateSkylight) { - if (!isColumn) { - return generateSkylight; - } - return false; - } - - @Inject(method = "setBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;relightBlock(III)V"), - locals = LocalCapture.CAPTURE_FAILHARD) - private void setBlockState_CubicChunks_relightBlockReplace(BlockPos pos, IBlockState state, CallbackInfoReturnable cir, - int localX, int y, int localZ, int packedXZ, int oldHeightValue, IBlockState oldState, Block newBlock, Block oldBlock, - int oldOpacity, ExtendedBlockStorage ebs, boolean createdNewEbsAboveTop, int newOpacity) { - - if (isColumn && ((IColumn) this).getCube(blockToCube(y)).isInitialLightingDone()) { - if (oldHeightValue == y + 1) { // oldHeightValue is the previous block Y above the top block, so this is the "removing to block" case - getWorld().getLightingManager().doOnBlockSetLightUpdates((Chunk) (Object) this, localX, getHeightValue(localX, localZ), y, localZ); - } else { - getWorld().getLightingManager().doOnBlockSetLightUpdates((Chunk) (Object) this, localX, oldHeightValue, y, localZ); - } - } - } - - @Redirect(method = "setBlockState", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/chunk/Chunk;getLightFor(Lnet/minecraft/world/EnumSkyBlock;Lnet/minecraft/util/math/BlockPos;)I")) - private int setBlockState_CubicChunks_noGetLightFor(Chunk instance, EnumSkyBlock type, BlockPos pos) { - if (!isColumn) { - return instance.getLightFor(type, pos); - } - return 0; - } - - // make relightBlock no-op for cubic chunks, handles by injection above - @Inject(method = "relightBlock", at = @At(value = "HEAD"), cancellable = true) - private void relightBlock_CubicChunks_Replace(int x, int y, int z, CallbackInfo cbi) { - if (isColumn) { - cbi.cancel(); - } - } - - // ============================================== - // getBlockLightOpacity - // ============================================== - - @Redirect(method = "getBlockLightOpacity(III)I", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) - private boolean getBlockLightOpacity_isChunkLoadedCubeRedirect(Chunk chunk, int x, int y, int z) { - if (!isColumn) { - return loaded; - } - ICube cube = ((IColumn) this).getLoadedCube(blockToCube(y)); - return cube != null && cube.isCubeLoaded(); - } - - // ============================================== - // getBlockState - // ============================================== - - @ModifyConstant(method = "getBlockState(III)Lnet/minecraft/block/state/IBlockState;", - constant = @Constant(expandZeroConditions = Constant.Condition.GREATER_THAN_OR_EQUAL_TO_ZERO), - require = 1) - private int getBlockState_getMinHeight(int zero) { - return isColumn ? Integer.MIN_VALUE : getWorld().getMinHeight(); // this one is in block coords, max is in cube coords. Mojang logic. - } - - @Redirect(method = "getBlockState(III)Lnet/minecraft/block/state/IBlockState;", - at = @At( - value = "FIELD", - args = "array=length", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" - )) - private int getBlockState_getMaxHeight(ExtendedBlockStorage[] ebs) { - return isColumn ? Integer.MAX_VALUE : (ebs.length - Coords.blockToCube(getWorld().getMinHeight())); - } - - @Redirect(method = "getBlockState(III)Lnet/minecraft/block/state/IBlockState;", - at = @At( - value = "FIELD", - args = "array=get", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;" - )) - private ExtendedBlockStorage getBlockState_getStorage(ExtendedBlockStorage[] ebs, int y) { - return getEBS_CubicChunks(y); - } - - // ============================================== - // setBlockState - // ============================================== - - @Inject(method = "setBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;set" - + "(IIILnet/minecraft/block/state/IBlockState;)V", shift = At.Shift.AFTER)) - private void onEBSSet_setBlockState_setOpacity(BlockPos pos, IBlockState state, CallbackInfoReturnable cir) { - if (!isColumn) { - return; - } - this.dirty = true; - if (((IColumn) this).getCube(blockToCube(pos.getY())).isSurfaceTracked()) { - opacityIndex.onOpacityChange(blockToLocal(pos.getX()), pos.getY(), blockToLocal(pos.getZ()), state.getLightOpacity(world, pos)); - getWorld().getLightingManager().onHeightUpdate(pos); - } else { - stagingHeightMap.onOpacityChange(blockToLocal(pos.getX()), pos.getY(), blockToLocal(pos.getZ()), state.getLightOpacity(world, pos)); - } - } - - @Redirect(method = "setBlockState", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=get" - )) - private ExtendedBlockStorage setBlockState_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { - return getEBS_CubicChunks(index); - } - - @Redirect(method = "setBlockState", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=set" - )) - private void setBlockState_CubicChunks_EBSSetRedirect(ExtendedBlockStorage[] array, int index, ExtendedBlockStorage val) { - setEBS_CubicChunks(index, val); - } - - @Inject(method = "setBlockState", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=set" - ), cancellable = true) - private void setBlockState_CubicChunks_EBSSetInject(BlockPos pos, IBlockState state, CallbackInfoReturnable cir) { - if (isColumn && getWorld().getCubeCache().getLoadedCube(CubePos.fromBlockCoords(pos)) == null) { - cir.setReturnValue(null); - } - } - - @Redirect(method = "setBlockState", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;dirty:Z")) - private void setIsModifiedFromSetBlockState_Field(Chunk chunk, boolean isModifiedIn, BlockPos pos, IBlockState state) { - if (isColumn) { - getWorld().getCubeFromBlockCoords(pos).markDirty(); - } else { - dirty = isModifiedIn; - } - } - - // ============================================== - // getLightFor - // ============================================== - - @Inject(method = "getLightFor", at = @At("HEAD"), cancellable = true) - private void replacedGetLightForCC(EnumSkyBlock type, BlockPos pos, CallbackInfoReturnable cir) { - if (!isColumn) { - return; - } - ((ICubicWorldInternal) world).getLightingManager().onGetLight(type, pos); - cir.setReturnValue(((Cube) ((IColumn) this).getCube(blockToCube(pos.getY()))).getCachedLightFor(type, pos)); - } - - @Nullable - @Redirect(method = "getLightFor", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=get" - )) - private ExtendedBlockStorage getLightFor_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { - return getEBS_CubicChunks(index); - } - - // ============================================== - // LIGHTING HOOKS - // ============================================== - - @Inject(method = "getLightSubtracted", at = @At("HEAD")) - private void onGetLightSubtracted(BlockPos pos, int amount, CallbackInfoReturnable cir) { - if (!isColumn) { - return; - } - getWorld().getLightingManager().onGetLightSubtracted(pos); - } - - - // ============================================== - // setLightFor - // ============================================== - - @Redirect(method = "setLightFor", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=get" - )) - @Nullable - private ExtendedBlockStorage setLightFor_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { - return getEBS_CubicChunks(index); - } - - @Redirect(method = "setLightFor", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=set" - )) - private void setLightFor_CubicChunks_EBSSetRedirect(ExtendedBlockStorage[] array, int index, ExtendedBlockStorage ebs) { - setEBS_CubicChunks(index, ebs); - } - - @Redirect(method = "setLightFor", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;dirty:Z")) - private void setIsModifiedFromSetLightFor_Field(Chunk chunk, boolean isModifiedIn, EnumSkyBlock type, BlockPos pos, int value) { - if (isColumn) { - getWorld().getCubeFromBlockCoords(pos).markDirty(); - } else { - dirty = isModifiedIn; - } - } - - // ============================================== - // getLightSubtracted - // ============================================== - - @Nullable - @Redirect(method = "getLightSubtracted", at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - args = "array=get" - )) - private ExtendedBlockStorage getLightSubtracted_CubicChunks_EBSGetRedirect(ExtendedBlockStorage[] array, int index) { - return getEBS_CubicChunks(index); - } - - // ============================================== - // addEntity - // ============================================== - - @ModifyConstant(method = "addEntity", - constant = @Constant(expandZeroConditions = Constant.Condition.LESS_THAN_ZERO, intValue = 0), - slice = @Slice( - from = @At( - value = "INVOKE:LAST", - target = "Lnet/minecraft/util/math/MathHelper;floor(D)I"), - to = @At( - value = "FIELD:FIRST", - target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;") - ), - require = 1 - ) - private int addEntity_getMinY(int zero) { - return blockToCube(getWorld().getMinHeight()); - } - - @Redirect(method = "addEntity", - at = @At( - value = "FIELD", - args = "array=length", - target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" - ), - require = 2) - private int addEntity_getMaxHeight(ClassInheritanceMultiMap[] entityLists) { - return isColumn ? blockToCube(getWorld().getMaxHeight()) : (entityLists.length - Coords.blockToCube(getWorld().getMinHeight())); - } - - @Redirect(method = "addEntity", - at = @At( - value = "FIELD", - args = "array=get", - target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" - ), - require = 1) - private ClassInheritanceMultiMap addEntity_getEntityList(ClassInheritanceMultiMap[] entityLists, int idx, Entity entity) { - if (!isColumn) { - return entityLists[idx - Coords.blockToCube(getWorld().getMinHeight())]; - } else if (cachedCube != null && cachedCube.getY() == idx) { - cachedCube.getEntityContainer().addEntity(entity); - return null; - } else { - getWorld().getCubeCache().getCube(this.x, idx, this.z).getEntityContainer().addEntity(entity); - return null; - } - } - - @Redirect(method = "addEntity", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/util/ClassInheritanceMultiMap;add(Ljava/lang/Object;)Z" - ), - require = 1) - private boolean addEntity_getEntityList(ClassInheritanceMultiMap obj, Object entity) { - if (!isColumn) { - return obj.add(entity); - } - assert obj == null; - return true; // ignored - } - - // ============================================== - // removeEntityAtIndex - // ============================================== - - @ModifyConstant(method = "removeEntityAtIndex", - constant = @Constant(expandZeroConditions = Constant.Condition.LESS_THAN_ZERO, intValue = 0), - require = 2, - slice = @Slice( - from = @At("HEAD"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/util/ClassInheritanceMultiMap;remove(Ljava/lang/Object;)Z") - ) - ) - private int removeEntityAtIndex_getMinY(int zero) { - return blockToCube(getWorld().getMinHeight()); - } - - @Redirect(method = "removeEntityAtIndex", - at = @At( - value = "FIELD", - args = "array=length", - target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" - ), - require = 2) - private int removeEntityAtIndex_getMaxHeight(ClassInheritanceMultiMap[] entityLists) { - return isColumn ? blockToCube(getWorld().getMaxHeight()) : (entityLists.length - Coords.blockToCube(getWorld().getMinHeight())); - } - - @Redirect(method = "removeEntityAtIndex", - at = @At( - value = "FIELD", - args = "array=get", - target = "Lnet/minecraft/world/chunk/Chunk;entityLists:[Lnet/minecraft/util/ClassInheritanceMultiMap;" - ), - require = 1) - private ClassInheritanceMultiMap removeEntityAtIndex_getEntityList(ClassInheritanceMultiMap[] entityLists, int idx, Entity entity, - int index) { - if (!isColumn) { - return entityLists[idx - Coords.blockToCube(getWorld().getMinHeight())]; - } else if (cachedCube != null && cachedCube.getY() == idx) { - cachedCube.getEntityContainer().remove(entity); - return null; - } else { - getWorld().getCubeCache().getCube(this.x, idx, this.z).getEntityContainer().remove(entity); - return null; - } - } - - @Redirect(method = "removeEntityAtIndex", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/util/ClassInheritanceMultiMap;remove(Ljava/lang/Object;)Z" - ), - require = 1) - private boolean removeEntityAtIndex_getEntityList(ClassInheritanceMultiMap obj, Object entity) { - if (!isColumn) { - return obj.remove(entity); - } - assert obj == null; - return true; // ignored - } - - // ============================================== - // addTileEntity - // ============================================== - - @Redirect(method = "addTileEntity(Lnet/minecraft/tileentity/TileEntity;)V", - at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) - private boolean addTileEntity_isChunkLoadedCubeRedirect(Chunk chunk, TileEntity te) { - if (!isColumn) { - return loaded; - } - ICube cube = ((IColumn) this).getLoadedCube(blockToCube(te.getPos().getY())); - return cube != null && cube.isCubeLoaded(); - } - - // ============================================== - // removeTileEntity - // ============================================== - - @Redirect(method = "removeTileEntity", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) - private boolean removeTileEntity_isChunkLoadedCubeRedirect(Chunk chunk, BlockPos pos) { - if (!isColumn) { - return loaded; - } - ICube cube = ((IColumn) this).getLoadedCube(blockToCube(pos.getY())); - return cube != null && cube.isCubeLoaded(); - } - - // ============================================== - // onLoad - // ============================================== - - @Inject(method = "onLoad", at = @At("HEAD"), cancellable = true) - private void onChunkLoad_CubicChunks(CallbackInfo cbi) { - if (!isColumn) { - return; - } - cbi.cancel(); - this.loaded = true; - for (Cube cube : cubeMap) { - cube.onLoad(); - } - MinecraftForge.EVENT_BUS.post(new Load((Chunk) (Object) this)); - } - - // ============================================== - // onUnload - // ============================================== - - @Inject(method = "onUnload", at = @At("HEAD"), cancellable = true) - private void onChunkUnload_CubicChunks(CallbackInfo cbi) { - if (!isColumn) { - return; - } - cbi.cancel(); - this.loaded = false; - - for (Cube cube : cubeMap) { - cube.onUnload(); - } - MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkEvent.Unload((Chunk) (Object) this)); - } - - // ============================================== - // getEntitiesWithinAABBForEntity - // ============================================== - - @Inject(method = "getEntitiesWithinAABBForEntity", at = @At("HEAD"), cancellable = true) - private void getEntitiesWithinAABBForEntity_CubicChunks(@Nullable Entity entityIn, AxisAlignedBB aabb, - List listToFill, Predicate filter, CallbackInfo cbi) { - if (!isColumn) { - return; - } - cbi.cancel(); - - int minY = MathHelper.floor((aabb.minY - World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); - int maxY = MathHelper.floor((aabb.maxY + World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); - minY = MathHelper.clamp(minY, - blockToCube(getWorld().getMinHeight()), - blockToCube(getWorld().getMaxHeight())); - maxY = MathHelper.clamp(maxY, - blockToCube(getWorld().getMinHeight()), - blockToCube(getWorld().getMaxHeight())); - - for (Cube cube : cubeMap.cubes(minY, maxY)) { - if (cube.getEntityContainer().getEntitySet().isEmpty()) { - continue; - } - for (Entity entity : cube.getEntityContainer().getEntitySet()) { - if (!entity.getEntityBoundingBox().intersects(aabb) || entity == entityIn) { - continue; - } - if (filter == null || filter.apply(entity)) { - listToFill.add(entity); - } - - Entity[] parts = entity.getParts(); - - if (parts != null) { - for (Entity part : parts) { - if (part != entityIn && part.getEntityBoundingBox().intersects(aabb) - && (filter == null || filter.apply(part))) { - listToFill.add(part); - } - } - } - } - } - } - - // ============================================== - // getEntitiesOfTypeWithinAABB - // ============================================== - - @Inject(method = "getEntitiesOfTypeWithinAABB", at = @At("HEAD"), cancellable = true) - private void getEntitiesOfTypeWithinAAAB_CubicChunks(Class entityClass, - AxisAlignedBB aabb, List listToFill, Predicate filter, CallbackInfo cbi) { - if (!isColumn) { - return; - } - cbi.cancel(); - - int minY = MathHelper.floor((aabb.minY - World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); - int maxY = MathHelper.floor((aabb.maxY + World.MAX_ENTITY_RADIUS) / Cube.SIZE_D); - minY = MathHelper.clamp(minY, - blockToCube(getWorld().getMinHeight()), - blockToCube(getWorld().getMaxHeight())); - maxY = MathHelper.clamp(maxY, - blockToCube(getWorld().getMinHeight()), - blockToCube(getWorld().getMaxHeight())); - - for (Cube cube : cubeMap.cubes(minY, maxY)) { - for (T t : cube.getEntityContainer().getEntitySet().getByClass(entityClass)) { - if (t.getEntityBoundingBox().intersects(aabb) && (filter == null || filter.apply(t))) { - listToFill.add(t); - } - } - } - } - - // public boolean needsSaving(boolean p_76601_1_) - TODO: needsSaving - - // ============================================== - // getPrecipitationHeight - // ============================================== - - @Inject(method = "getPrecipitationHeight", at = @At(value = "HEAD"), cancellable = true) - private void getPrecipitationHeight_CubicChunks_Replace(BlockPos pos, CallbackInfoReturnable cbi) { - if (isColumn) { - // TODO: precipitationHeightMap - BlockPos ret = new BlockPos(pos.getX(), ((IColumn) this).getHeightValue(blockToLocal(pos.getX()), pos.getY(), blockToLocal(pos.getZ())), pos.getZ()); - cbi.setReturnValue(ret); - } - } - - // ============================================== - // onTick - // ============================================== - - // TODO: check if we are out of time earlier? - @Inject(method = "onTick", at = @At(value = "RETURN")) - private void onTick_CubicChunks_TickCubes(boolean tryToTickFaster, CallbackInfo cbi) { - if (!isColumn) { - return; - } - this.ticked = true; - this.isLightPopulated = true; - // do nothing, we tick cubes directly - } - - // ============================================== - // isEmptyBetween - // ============================================== - - /** - * @param startY bottom Y coordinate - * @param endY top Y coordinate - * @return true if the specified height range is empty - * @author Barteks2x - * @reason original function limited to storage arrays. - */ - @Overwrite - public boolean isEmptyBetween(int startY, int endY) { - if (startY < getWorld().getMinHeight()) { - startY = getWorld().getMinHeight(); - } - - if (endY >= getWorld().getMaxHeight()) { - endY = getWorld().getMaxHeight() - 1; - } - - for (int i = startY; i <= endY; i += Cube.SIZE) { - ExtendedBlockStorage extendedblockstorage = getEBS_CubicChunks(blockToCube(i)); - - if (extendedblockstorage != NULL_BLOCK_STORAGE && !extendedblockstorage.isEmpty()) { - return false; - } - } - - return true; - } - - // ============================================== - // setStorageArrays - // ============================================== - - @Inject(method = "setStorageArrays", at = @At(value = "HEAD")) - private void setStorageArrays_CubicChunks_NotSupported(ExtendedBlockStorage[] newStorageArrays, CallbackInfo cbi) { - if (isColumn) { - throw new UnsupportedOperationException("setting storage arrays it not supported with cubic chunks"); - } - } - - // ============================================== - // checkLight - // ============================================== - - @Inject(method = "checkLight()V", at = @At(value = "HEAD"), cancellable = true) - private void checkLight_CubicChunks_NotSupported(CallbackInfo cbi) { - if (isColumn) { - // we use FirstLightProcessor instead - cbi.cancel(); - } - } - - // private void setSkylightUpdated() - noone should use it - - // private void checkLightSide(EnumFacing facing) - noone should use it - - // private boolean checkLight(int x, int z) - TODO: checkLight - - // ============================================== - // removeInvalidTileEntity - // ============================================== - - @Redirect(method = "removeInvalidTileEntity", at = @At(value = "FIELD", target = "Lnet/minecraft/world/chunk/Chunk;loaded:Z")) - private boolean removeInvalidTileEntity_isChunkLoadedCubeRedirect(Chunk chunk, BlockPos pos) { - if (!isColumn) { - return loaded; - } - ICube cube = ((IColumn) this).getLoadedCube(blockToCube(pos.getY())); - return cube != null && cube.isCubeLoaded(); - } - - // ============================================== - // enqueueRelightChecks - // ============================================== - - @Inject(method = "enqueueRelightChecks", at = @At(value = "HEAD"), cancellable = true) - private void enqueueRelightChecks_CubicChunks(CallbackInfo cbi) { - if (!isColumn) { - return; - } - cbi.cancel(); - if (CubicChunksConfig.relightChecksPerTickPerColumn > 0 && (!world.isRemote || CubicChunksConfig.doClientLightFixes)) { - cubeMap.enqueueRelightChecks(); - } - } -} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java new file mode 100644 index 000000000..dc45b8049 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java @@ -0,0 +1,66 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import io.github.opencubicchunks.cubicchunks.api.util.Coords; +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import io.github.opencubicchunks.cubicchunks.api.world.IMinMaxHeight; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.Slice; + +@Mixin(value = Chunk.class, priority = 999) +public abstract class MixinChunk_Cubes_Bukkit_Sided { + @ModifyConstant(method = "(Lnet/minecraft/world/World;II)V", constant = @Constant(intValue = 16), + slice = @Slice( + from = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;neighbors:I", // Add from to avoid expected changes + remap = false + ), + to = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + opcode = Opcodes.PUTFIELD + ) + ) + ) + private int modifySectionArrayLength(int sixteen, World worldIn, int x, int z) { + if (worldIn == null) { + // Some mods construct chunks with null world, ignore them + return sixteen; + } + if (!((ICubicWorld) worldIn).isCubicWorld()) { + IMinMaxHeight y = (IMinMaxHeight) worldIn; + return Coords.blockToCube(y.getMaxHeight()) - Coords.blockToCube(y.getMinHeight()); + } + return sixteen; + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Vanilla_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Vanilla_Sided.java new file mode 100644 index 000000000..daaa40242 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Vanilla_Sided.java @@ -0,0 +1,59 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import io.github.opencubicchunks.cubicchunks.api.util.Coords; +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import io.github.opencubicchunks.cubicchunks.api.world.IMinMaxHeight; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.Slice; + +@Mixin(value = Chunk.class, priority = 999) +public abstract class MixinChunk_Cubes_Vanilla_Sided { + @ModifyConstant(method = "(Lnet/minecraft/world/World;II)V", constant = @Constant(intValue = 16), + slice = @Slice(to = @At( + value = "FIELD", + target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", + opcode = Opcodes.PUTFIELD + )), + allow = 1, require = 1) + private int modifySectionArrayLength(int sixteen, World worldIn, int x, int z) { + if (worldIn == null) { + // Some mods construct chunks with null world, ignore them + return sixteen; + } + if (!((ICubicWorld) worldIn).isCubicWorld()) { + IMinMaxHeight y = (IMinMaxHeight) worldIn; + return Coords.blockToCube(y.getMaxHeight()) - Coords.blockToCube(y.getMinHeight()); + } + return sixteen; + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java index 0440f0d74..3b142c02c 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java @@ -24,7 +24,6 @@ */ package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.server; -import io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinPlayerList; import io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinPlayerList_Bukkit; import net.minecraft.server.dedicated.DedicatedPlayerList; import net.minecraft.server.dedicated.DedicatedServer; diff --git a/src/main/resources/cubicchunks.mixins.core.bukkit.json b/src/main/resources/cubicchunks.mixins.core.bukkit.json index b1b4acf7c..2137f65bd 100644 --- a/src/main/resources/cubicchunks.mixins.core.bukkit.json +++ b/src/main/resources/cubicchunks.mixins.core.bukkit.json @@ -12,7 +12,7 @@ "server": [ "common.MixinWorld_HeightLimits_Bukkit_Sided", "common.MixinPlayerList_Bukkit", - "common.MixinChunk_Cubes_Bukkit", + "common.MixinChunk_Cubes_Bukkit_Sided", "server.MixinDedicatedPlayerList_Bukkit", "common.MixinWorldServer_Bukkit" ] diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 0dffbce7e..d8eaa90b2 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -20,6 +20,7 @@ "common.IPlayerChunkMapEntry", "common.MixinAnvilSaveHandler", "common.MixinChunk_Column", + "common.MixinChunk_Cubes", "common.MixinChunkCache_HeightLimits", "common.MixinDerivedWorldInfo", "common.MixinEntity_DeathFix", diff --git a/src/main/resources/cubicchunks.mixins.core.vanilla.json b/src/main/resources/cubicchunks.mixins.core.vanilla.json index 57386994b..80f56ba44 100644 --- a/src/main/resources/cubicchunks.mixins.core.vanilla.json +++ b/src/main/resources/cubicchunks.mixins.core.vanilla.json @@ -8,7 +8,7 @@ "conformVisibility": true }, "mixins": [ - "common.MixinChunk_Cubes", + "common.MixinChunk_Cubes_Vanilla_Sided", "common.MixinWorld_HeightLimits_Vanilla_Sided", "common.MixinWorldServer", "common.MixinPlayerList" From d461e1e2e7b0761e686bcf7da750c0d9cdbdf843 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Fri, 3 Jan 2025 01:10:28 -0800 Subject: [PATCH 06/13] [ci skip] Deduplicate code and bug fixes --- .../mixin/core/common/MixinPlayerList.java | 43 +++------- .../common/MixinPlayerList_Bukkit_Sided.java | 80 +++++++++++++++++++ ...ava => MixinPlayerList_Vanilla_Sided.java} | 43 ++-------- .../MixinDedicatedPlayerList_Bukkit.java | 43 ---------- .../cubicchunks.mixins.core.bukkit.json | 3 +- .../resources/cubicchunks.mixins.core.json | 4 +- .../cubicchunks.mixins.core.vanilla.json | 6 +- 7 files changed, 103 insertions(+), 119 deletions(-) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java rename src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/{MixinPlayerList_Bukkit.java => MixinPlayerList_Vanilla_Sided.java} (70%) delete mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java index d450a6e70..ee02b5d72 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java @@ -56,17 +56,17 @@ public abstract class MixinPlayerList implements ICubicPlayerList { @Shadow @Final private MinecraftServer server; protected int verticalViewDistance = -1; - @Redirect(method = "playerLoggedOut", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;markDirty()V", ordinal = 0), - require = 1) - private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP playerIn) { - ICubicWorldInternal world = (ICubicWorldInternal) playerIn.getServerWorld(); - if (world.isCubicWorld()) { - world.getCubeFromCubeCoords(playerIn.chunkCoordX, playerIn.chunkCoordY, playerIn.chunkCoordZ).markDirty(); - } else { - ((World) world).getChunk(playerIn.chunkCoordX, playerIn.chunkCoordZ).markDirty(); - } - } +// @Redirect(method = "playerLoggedOut", +// at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;markDirty()V", ordinal = 0), +// require = 1) +// private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP playerIn) { +// ICubicWorldInternal world = (ICubicWorldInternal) playerIn.getServerWorld(); +// if (world.isCubicWorld()) { +// world.getCubeFromCubeCoords(playerIn.chunkCoordX, playerIn.chunkCoordY, playerIn.chunkCoordZ).markDirty(); +// } else { +// ((World) world).getChunk(playerIn.chunkCoordX, playerIn.chunkCoordZ).markDirty(); +// } +// } // Moved to MixinPlayerList_Vanilla_Sided @Override public int getVerticalViewDistance() { return verticalViewDistance < 0 ? viewDistance : verticalViewDistance; @@ -88,25 +88,4 @@ private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP pla } } } - - @Inject(method = "recreatePlayerEntity", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/gen/ChunkProviderServer;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;")) - private void createPlayerChunk(EntityPlayerMP playerIn, int dimension, boolean conqueredEnd, CallbackInfoReturnable cir) { - if (!((ICubicWorld) playerIn.world).isCubicWorld()) { - return; - } - for (int dCubeY = -8; dCubeY <= 8; dCubeY++) { - ((ICubicWorld) playerIn.world).getCubeFromBlockCoords(playerIn.getPosition().up(Coords.cubeToMinBlock(dCubeY))); - } - } - - @ModifyConstant(method = "recreatePlayerEntity", - constant = @Constant(doubleValue = 256)) - private double getMaxHeight(double _256, EntityPlayerMP playerIn, int dimension, boolean conqueredEnd) { - // +/- 8 chunks around the original position are loaded because of an inject above - if (!playerIn.world.isBlockLoaded(new BlockPos(playerIn))) { - return Double.NEGATIVE_INFINITY; - } - return ((ICubicWorld) playerIn.world).getMaxHeight(); - } } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java new file mode 100644 index 000000000..a8d680f42 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java @@ -0,0 +1,80 @@ +/* + * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2021 OpenCubicChunks + * Copyright (c) 2015-2021 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; + +import io.github.opencubicchunks.cubicchunks.api.util.Coords; +import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.management.PlayerList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.bukkit.Location; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import javax.annotation.ParametersAreNonnullByDefault; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +@Mixin(PlayerList.class) +public abstract class MixinPlayerList_Bukkit_Sided { + @Redirect(method = "playerLoggedOut(Lnet/minecraft/entity/player/EntityPlayerMP;)Ljava/lang/String;", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;markDirty()V", ordinal = 0), + require = 1) // CB method has a different return value + private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP playerIn) { + ICubicWorldInternal world = (ICubicWorldInternal) playerIn.getServerWorld(); + if (world.isCubicWorld()) { + world.getCubeFromCubeCoords(playerIn.chunkCoordX, playerIn.chunkCoordY, playerIn.chunkCoordZ).markDirty(); + } else { + ((World) world).getChunk(playerIn.chunkCoordX, playerIn.chunkCoordZ).markDirty(); + } + } + + @Inject(method = "moveToWorld(Lnet/minecraft/entity/player/EntityPlayerMP;IZLorg/bukkit/Location;Z)Lnet/minecraft/entity/player/EntityPlayerMP;", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/gen/ChunkProviderServer;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;")) + private void createPlayerChunk(EntityPlayerMP playerIn, int dimension, boolean conqueredEnd, + Location location, boolean avoidSuffocation, CallbackInfoReturnable cir) { + if (!((ICubicWorld) playerIn.world).isCubicWorld()) { + return; + } + for (int dCubeY = -8; dCubeY <= 8; dCubeY++) { + ((ICubicWorld) playerIn.world).getCubeFromBlockCoords(playerIn.getPosition().up(Coords.cubeToMinBlock(dCubeY))); + } + } + + @ModifyConstant(method = "moveToWorld(Lnet/minecraft/entity/player/EntityPlayerMP;IZLorg/bukkit/Location;Z)Lnet/minecraft/entity/player/EntityPlayerMP;", + constant = @Constant(doubleValue = 256), remap = false) + private double getMaxHeight(double _256, EntityPlayerMP playerIn, int dimension, boolean conqueredEnd, Location location, boolean avoidSuffocation) { + // +/- 8 chunks around the original position are loaded because of an inject above + if (!playerIn.world.isBlockLoaded(new BlockPos(playerIn))) { + return Double.NEGATIVE_INFINITY; + } + return ((ICubicWorld) playerIn.world).getMaxHeight(); + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Vanilla_Sided.java similarity index 70% rename from src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Vanilla_Sided.java index b4e39c126..b12ebf9f7 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Vanilla_Sided.java @@ -25,40 +25,30 @@ package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; import io.github.opencubicchunks.cubicchunks.api.util.Coords; -import io.github.opencubicchunks.cubicchunks.core.entity.ICubicEntityTracker; -import io.github.opencubicchunks.cubicchunks.core.server.ICubicPlayerList; -import io.github.opencubicchunks.cubicchunks.core.server.PlayerCubeMap; import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import javax.annotation.ParametersAreNonnullByDefault; +/** + * Split from {@link MixinPlayerList} for compatibility. + */ @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault @Mixin(PlayerList.class) -public abstract class MixinPlayerList_Bukkit implements ICubicPlayerList { - - @Shadow private int viewDistance; - - @Shadow @Final private MinecraftServer server; - protected int verticalViewDistance = -1; - - @Redirect(method = "playerLoggedOut(Lnet/minecraft/entity/player/EntityPlayerMP;)Ljava/lang/String;", +public abstract class MixinPlayerList_Vanilla_Sided { + @Redirect(method = "playerLoggedOut", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;markDirty()V", ordinal = 0), - require = 1) // CB method has a different return value + require = 1) private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP playerIn) { ICubicWorldInternal world = (ICubicWorldInternal) playerIn.getServerWorld(); if (world.isCubicWorld()) { @@ -68,27 +58,6 @@ private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP pla } } - @Override public int getVerticalViewDistance() { - return verticalViewDistance < 0 ? viewDistance : verticalViewDistance; - } - - @Override public int getRawVerticalViewDistance() { - return verticalViewDistance; - } - - @Override public void setVerticalViewDistance(int dist) { - this.verticalViewDistance = dist; - - if (this.server.worlds != null) { - for (WorldServer worldserver : this.server.worlds) { - if (worldserver != null && ((ICubicWorld) worldserver).isCubicWorld()) { - ((PlayerCubeMap) worldserver.getPlayerChunkMap()).setPlayerViewDistance(viewDistance, dist); - ((ICubicEntityTracker) worldserver.getEntityTracker()).setVertViewDistance(dist); - } - } - } - } - @Inject(method = "recreatePlayerEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/gen/ChunkProviderServer;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;")) private void createPlayerChunk(EntityPlayerMP playerIn, int dimension, boolean conqueredEnd, CallbackInfoReturnable cir) { diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java deleted file mode 100644 index 3b142c02c..000000000 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/server/MixinDedicatedPlayerList_Bukkit.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). - * - * Copyright (c) 2015-2021 OpenCubicChunks - * Copyright (c) 2015-2021 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.server; - -import io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinPlayerList_Bukkit; -import net.minecraft.server.dedicated.DedicatedPlayerList; -import net.minecraft.server.dedicated.DedicatedServer; -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(DedicatedPlayerList.class) -public class MixinDedicatedPlayerList_Bukkit extends MixinPlayerList_Bukkit { - - @Inject(method = "", at = @At(value = "RETURN")) - private void setVerticalViewDistance(DedicatedServer server, CallbackInfo cbi) { - this.setVerticalViewDistance(server.getIntProperty("vertical-view-distance", -1)); - - } -} diff --git a/src/main/resources/cubicchunks.mixins.core.bukkit.json b/src/main/resources/cubicchunks.mixins.core.bukkit.json index 2137f65bd..7591f6cf5 100644 --- a/src/main/resources/cubicchunks.mixins.core.bukkit.json +++ b/src/main/resources/cubicchunks.mixins.core.bukkit.json @@ -11,9 +11,8 @@ "client": [], "server": [ "common.MixinWorld_HeightLimits_Bukkit_Sided", - "common.MixinPlayerList_Bukkit", + "common.MixinPlayerList_Bukkit_Sided", "common.MixinChunk_Cubes_Bukkit_Sided", - "server.MixinDedicatedPlayerList_Bukkit", "common.MixinWorldServer_Bukkit" ] } \ No newline at end of file diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index d8eaa90b2..07fc9f4a2 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -28,6 +28,7 @@ "common.MixinEntityTrackerEntry", "common.MixinIBlockAccess_MinMaxHeight", "common.MixinMinecraftServer", + "common.MixinPlayerList", "common.MixinRegionFileCache", "common.MixinStructureStart", "common.MixinWorld", @@ -65,6 +66,7 @@ "client.MixinWorldProvider" ], "server": [ - "server.MixinDedicatedServer_HeightLimits" + "server.MixinDedicatedServer_HeightLimits", + "server.MixinDedicatedPlayerList" ] } \ No newline at end of file diff --git a/src/main/resources/cubicchunks.mixins.core.vanilla.json b/src/main/resources/cubicchunks.mixins.core.vanilla.json index 80f56ba44..9b202a222 100644 --- a/src/main/resources/cubicchunks.mixins.core.vanilla.json +++ b/src/main/resources/cubicchunks.mixins.core.vanilla.json @@ -11,10 +11,8 @@ "common.MixinChunk_Cubes_Vanilla_Sided", "common.MixinWorld_HeightLimits_Vanilla_Sided", "common.MixinWorldServer", - "common.MixinPlayerList" + "common.MixinPlayerList_Vanilla_Sided" ], "client": [], - "server": [ - "server.MixinDedicatedPlayerList" - ] + "server": [] } \ No newline at end of file From 42c744b87759bdbcc748f4eedab838d8bff2e4bd Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Sun, 5 Jan 2025 00:07:42 -0800 Subject: [PATCH 07/13] [ci skip] Add changes comment --- .../mixin/core/common/MixinChunk_Cubes.java | 21 ------------------- .../common/MixinChunk_Cubes_Bukkit_Sided.java | 4 ++++ .../mixin/core/common/MixinPlayerList.java | 20 ------------------ .../common/MixinPlayerList_Bukkit_Sided.java | 14 ++++++++++++- .../MixinWorld_HeightLimits_Bukkit_Sided.java | 4 ++++ 5 files changed, 21 insertions(+), 42 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java index c805c5546..dcda5dfef 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes.java @@ -225,27 +225,6 @@ private void cubicChunkColumn_construct(World world, int x, int z, CallbackInfo Arrays.fill(getBiomeArray(), (byte) -1); } - /* - @ModifyConstant(method = "(Lnet/minecraft/world/World;II)V", constant = @Constant(intValue = 16), - slice = @Slice(to = @At( - value = "FIELD", - target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;", - opcode = Opcodes.PUTFIELD - )), - allow = 1, require = 1) - private int modifySectionArrayLength(int sixteen, World worldIn, int x, int z) { - if (worldIn == null) { - // Some mods construct chunks with null world, ignore them - return sixteen; - } - if (!((ICubicWorld) worldIn).isCubicWorld()) { - IMinMaxHeight y = (IMinMaxHeight) worldIn; - return Coords.blockToCube(y.getMaxHeight()) - Coords.blockToCube(y.getMinHeight()); - } - return sixteen; - } - */ // Now moved to MixinChunk_Cubes_Vanilla_Sided - @Redirect(method = "(Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/ChunkPrimer;II)V", at = @At( value = "FIELD", diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java index dc45b8049..21fbd7ba9 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java @@ -38,6 +38,10 @@ @Mixin(value = Chunk.class, priority = 999) public abstract class MixinChunk_Cubes_Bukkit_Sided { + + /* + * Spigot added some more constants before the storageArrays array is set, so we need to adjust the slice. + */ @ModifyConstant(method = "(Lnet/minecraft/world/World;II)V", constant = @Constant(intValue = 16), slice = @Slice( from = @At( diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java index ee02b5d72..145407190 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList.java @@ -24,25 +24,17 @@ */ package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; -import io.github.opencubicchunks.cubicchunks.api.util.Coords; import io.github.opencubicchunks.cubicchunks.core.entity.ICubicEntityTracker; import io.github.opencubicchunks.cubicchunks.core.server.ICubicPlayerList; import io.github.opencubicchunks.cubicchunks.core.server.PlayerCubeMap; import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; -import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; import mcp.MethodsReturnNonnullByDefault; -import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import net.minecraft.world.WorldServer; -import net.minecraft.world.chunk.Chunk; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.*; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import javax.annotation.ParametersAreNonnullByDefault; @@ -56,18 +48,6 @@ public abstract class MixinPlayerList implements ICubicPlayerList { @Shadow @Final private MinecraftServer server; protected int verticalViewDistance = -1; -// @Redirect(method = "playerLoggedOut", -// at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;markDirty()V", ordinal = 0), -// require = 1) -// private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP playerIn) { -// ICubicWorldInternal world = (ICubicWorldInternal) playerIn.getServerWorld(); -// if (world.isCubicWorld()) { -// world.getCubeFromCubeCoords(playerIn.chunkCoordX, playerIn.chunkCoordY, playerIn.chunkCoordZ).markDirty(); -// } else { -// ((World) world).getChunk(playerIn.chunkCoordX, playerIn.chunkCoordZ).markDirty(); -// } -// } // Moved to MixinPlayerList_Vanilla_Sided - @Override public int getVerticalViewDistance() { return verticalViewDistance < 0 ? viewDistance : verticalViewDistance; } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java index a8d680f42..88a415941 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java @@ -44,9 +44,15 @@ @ParametersAreNonnullByDefault @Mixin(PlayerList.class) public abstract class MixinPlayerList_Bukkit_Sided { + + /* + * CraftBukkit has a different return value for this method comparing to vanilla. + * CB: String playerLoggedOut(EntityPlayerMP); + * Vanilla: void playerLoggedOut(EntityPlayerMP); + */ @Redirect(method = "playerLoggedOut(Lnet/minecraft/entity/player/EntityPlayerMP;)Ljava/lang/String;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;markDirty()V", ordinal = 0), - require = 1) // CB method has a different return value + require = 1) private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP playerIn) { ICubicWorldInternal world = (ICubicWorldInternal) playerIn.getServerWorld(); if (world.isCubicWorld()) { @@ -56,6 +62,12 @@ private void setChunkModifiedOnPlayerLoggedOut(Chunk chunkIn, EntityPlayerMP pla } } + /* + * CraftBukkit changed the logic of how Vanilla "respawns" a player. + * In vanilla, the player instance will be recreated and the player's inventory will be copied over, + * while in CB, player instance is always same while the referenced player is online, + * and they offer another method "moveToWorld" to handle this. + */ @Inject(method = "moveToWorld(Lnet/minecraft/entity/player/EntityPlayerMP;IZLorg/bukkit/Location;Z)Lnet/minecraft/entity/player/EntityPlayerMP;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/gen/ChunkProviderServer;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;")) private void createPlayerChunk(EntityPlayerMP playerIn, int dimension, boolean conqueredEnd, diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java index 72b2c0874..46569a67c 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java @@ -45,6 +45,10 @@ public abstract class MixinWorld_HeightLimits_Bukkit_Sided implements ICubicWorl @Shadow public abstract boolean isBlockLoaded(BlockPos pos, boolean allowEmpty); + /* + * CraftBukkit moved the vanilla spawnEntity method logic to addEntity. + * And now in Spigot calling spawnEntity will be redirected to addEntity. + */ // Error is fine here, disabled remap as it's a CB method. @Redirect(method = "addEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;isChunkLoaded(IIZ)Z"), remap = false) private boolean addEntity_isChunkLoaded(World world, int chunkX, int chunkZ, boolean allowEmpty, Entity ent) { From d4d0377cf62efe16241ed19b6adb8064775876da Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Sun, 5 Jan 2025 01:58:27 -0800 Subject: [PATCH 08/13] Requested changes --- .../mixin/core/common/MixinWorldServer.java | 5 +- .../core/common/MixinWorldServer_Bukkit.java | 434 ------------------ .../cubicchunks/core/util/CompatHandler.java | 25 +- .../core/util/PlatformCompatUtils.java | 11 +- .../cubicchunks/core/util/ReflectionUtil.java | 34 ++ .../cubicchunks.mixins.core.bukkit.json | 3 +- .../resources/cubicchunks.mixins.core.json | 1 + .../cubicchunks.mixins.core.vanilla.json | 1 - 8 files changed, 70 insertions(+), 444 deletions(-) delete mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java index 4e4dec0db..c89cae870 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java @@ -46,6 +46,7 @@ import io.github.opencubicchunks.cubicchunks.core.server.PlayerCubeMap; import io.github.opencubicchunks.cubicchunks.core.server.SpawnCubes; import io.github.opencubicchunks.cubicchunks.core.server.VanillaNetworkHandler; +import io.github.opencubicchunks.cubicchunks.core.util.CompatHandler; import io.github.opencubicchunks.cubicchunks.core.util.world.CubeSplitTickList; import io.github.opencubicchunks.cubicchunks.core.util.world.CubeSplitTickSet; import io.github.opencubicchunks.cubicchunks.core.world.CubeWorldEntitySpawner; @@ -117,8 +118,6 @@ public abstract class MixinWorldServer extends MixinWorld implements ICubicWorld @Shadow protected abstract void playerCheckLight(); - @Shadow public abstract boolean spawnEntity(Entity entityIn); - @Shadow public abstract boolean addWeatherEffect(Entity entityIn); @Shadow @Mutable @Final private Set pendingTickListEntriesHashSet; @@ -368,7 +367,7 @@ private void tickColumn(boolean raining, boolean thundering, Chunk chunk) { skeletonHorse.setTrap(true); skeletonHorse.setGrowingAge(0); skeletonHorse.setPosition((double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ()); - this.spawnEntity(skeletonHorse); + CompatHandler.spawnEntity(skeletonHorse, (WorldServer) (Object) this); this.addWeatherEffect(new EntityLightningBolt((World) (Object) this, (double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ(), true)); } else { diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java deleted file mode 100644 index 73052cc33..000000000 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer_Bukkit.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT). - * - * Copyright (c) 2015-2021 OpenCubicChunks - * Copyright (c) 2015-2021 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; - -import static io.github.opencubicchunks.cubicchunks.api.util.Coords.cubeToMinBlock; -import static io.github.opencubicchunks.cubicchunks.core.util.ReflectionUtil.cast; - -import io.github.opencubicchunks.cubicchunks.api.util.Coords; -import io.github.opencubicchunks.cubicchunks.api.util.CubePos; -import io.github.opencubicchunks.cubicchunks.api.util.IntRange; -import io.github.opencubicchunks.cubicchunks.api.util.NotCubicChunksWorldException; -import io.github.opencubicchunks.cubicchunks.api.util.XYZMap; -import io.github.opencubicchunks.cubicchunks.api.util.XZMap; -import io.github.opencubicchunks.cubicchunks.api.world.IColumn; -import io.github.opencubicchunks.cubicchunks.api.world.ICube; -import io.github.opencubicchunks.cubicchunks.api.world.ICubeProviderServer; -import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorldServer; -import io.github.opencubicchunks.cubicchunks.api.worldgen.ICubeGenerator; -import io.github.opencubicchunks.cubicchunks.core.CubicChunks; -import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; -import io.github.opencubicchunks.cubicchunks.core.lighting.LightingManager; -import io.github.opencubicchunks.cubicchunks.core.server.ChunkGc; -import io.github.opencubicchunks.cubicchunks.core.server.CubeProviderServer; -import io.github.opencubicchunks.cubicchunks.core.server.PlayerCubeMap; -import io.github.opencubicchunks.cubicchunks.core.server.SpawnCubes; -import io.github.opencubicchunks.cubicchunks.core.server.VanillaNetworkHandler; -import io.github.opencubicchunks.cubicchunks.core.util.world.CubeSplitTickList; -import io.github.opencubicchunks.cubicchunks.core.util.world.CubeSplitTickSet; -import io.github.opencubicchunks.cubicchunks.core.world.CubeWorldEntitySpawner; -import io.github.opencubicchunks.cubicchunks.core.world.IWorldEntitySpawner; -import io.github.opencubicchunks.cubicchunks.core.world.chunkloader.CubicChunkManager; -import io.github.opencubicchunks.cubicchunks.core.world.cube.Cube; -import io.github.opencubicchunks.cubicchunks.core.world.provider.ICubicWorldProvider; -import mcp.MethodsReturnNonnullByDefault; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.EntityTracker; -import net.minecraft.entity.effect.EntityLightningBolt; -import net.minecraft.entity.passive.EntitySkeletonHorse; -import net.minecraft.init.Blocks; -import net.minecraft.server.management.PlayerChunkMap; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.NextTickListEntry; -import net.minecraft.world.World; -import net.minecraft.world.WorldEntitySpawner; -import net.minecraft.world.WorldServer; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import net.minecraftforge.common.ForgeChunkManager; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -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 java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -/** - * Implementation of {@link ICubicWorldServer} interface. - */ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -@Mixin(WorldServer.class) -@Implements(@Interface(iface = ICubicWorldServer.class, prefix = "world$")) -public abstract class MixinWorldServer_Bukkit extends MixinWorld implements ICubicWorldInternal.Server { - - @Shadow @Mutable @Final private PlayerChunkMap playerChunkMap; - @Shadow @Mutable @Final private WorldEntitySpawner entitySpawner; - @Shadow @Mutable @Final private EntityTracker entityTracker; - @Shadow public boolean disableLevelSaving; - private Map> forcedChunksCubes; - private XYZMap forcedCubes; - private XZMap forcedColumns; - - private ChunkGc worldChunkGc; - private SpawnCubes spawnArea; - private boolean runningCompatibilityGenerator; - private VanillaNetworkHandler vanillaNetworkHandler; - - @Shadow protected abstract void playerCheckLight(); - - @Shadow(remap = false) public abstract boolean addEntity(Entity entityIn, CreatureSpawnEvent.SpawnReason reason); // CB renamed method - - @Shadow public abstract boolean addWeatherEffect(Entity entityIn); - - @Shadow @Mutable @Final private Set pendingTickListEntriesHashSet; - @Shadow @Mutable @Final private List pendingTickListEntriesThisTick; - - @Shadow public abstract PlayerChunkMap getPlayerChunkMap(); - - @Override public void initCubicWorldServer(IntRange heightRange, IntRange generationRange) { - super.initCubicWorld(heightRange, generationRange); - this.isCubicWorld = true; - IWorldEntitySpawner spawner = new CubeWorldEntitySpawner(); - IWorldEntitySpawner.Handler spawnHandler = cast(entitySpawner); - spawnHandler.setEntitySpawner(spawner); - - this.chunkProvider = new CubeProviderServer((WorldServer) (Object) this, - ((ICubicWorldProvider) this.provider).createCubeGenerator()); - - this.vanillaNetworkHandler = new VanillaNetworkHandler((WorldServer) (Object) this); - this.playerChunkMap = new PlayerCubeMap((WorldServer) (Object) this); - - this.forcedChunksCubes = new HashMap<>(); - this.forcedCubes = new XYZMap<>(0.75f, 64*1024); - this.forcedColumns = new XZMap<>(0.75f, 2048); - - this.pendingTickListEntriesHashSet = new CubeSplitTickSet(); - this.pendingTickListEntriesThisTick = new CubeSplitTickList(); - this.worldChunkGc = new ChunkGc(getCubeCache()); - - this.lightingManager = new LightingManager((World) (Object) this); - } - - @Override public VanillaNetworkHandler getVanillaNetworkHandler() { - return vanillaNetworkHandler; - } - - @Override public void setSpawnArea(SpawnCubes spawn) { - this.spawnArea = spawn; - } - - @Override public SpawnCubes getSpawnArea() { - return spawnArea; - } - - @Override public CubeSplitTickSet getScheduledTicks() { - return (CubeSplitTickSet) pendingTickListEntriesHashSet; - } - - @Override public CubeSplitTickList getThisTickScheduledTicks() { - return (CubeSplitTickList) pendingTickListEntriesThisTick; - } - - @Override public void tickCubicWorld() { - if (!this.isCubicWorld()) { - throw new NotCubicChunksWorldException(); - } - getLightingManager().onTick(); - if (this.spawnArea != null) { - this.spawnArea.update((World) (Object) this); - } - } - - @Override public CubeProviderServer getCubeCache() { - if (!this.isCubicWorld()) { - throw new NotCubicChunksWorldException(); - } - return (CubeProviderServer) this.chunkProvider; - } - - @Override public ICubeGenerator getCubeGenerator() { - return getCubeCache().getCubeGenerator(); - } - - - @Override public void removeForcedCube(ICube cube) { - if (!forcedChunksCubes.get(cube.getColumn()).remove(cube)) { - CubicChunks.LOGGER.error("Trying to remove forced cube " + cube.getCoords() + ", but it's not forced!"); - } - forcedCubes.remove(cube); - if (forcedChunksCubes.get(cube.getColumn()).isEmpty()) { - forcedChunksCubes.remove(cube.getColumn()); - forcedColumns.remove(cube.getColumn()); - } - } - - @Override public void addForcedCube(ICube cube) { - if (!forcedChunksCubes.computeIfAbsent(cube.getColumn(), chunk -> new HashSet<>()).add(cube)) { - CubicChunks.LOGGER.error("Trying to add forced cube " + cube.getCoords() + ", but it's already forced!"); - } - forcedCubes.put(cube); - forcedColumns.put(cube.getColumn()); - } - - @Override public XYZMap getForcedCubes() { - return forcedCubes; - } - - @Override public XZMap getForcedColumns() { - return forcedColumns; - } - - @Override public void unloadOldCubes() { - worldChunkGc.chunkGc(); - } - - - /** - * CubicChunks equivalent of {@link ForgeChunkManager#forceChunk(ForgeChunkManager.Ticket, ChunkPos)}. - * - * Can accept tickets from different worlds. - */ - @Override - public void forceChunk(ForgeChunkManager.Ticket ticket, CubePos chunk) { - CubicChunkManager.forceChunk(ticket, chunk); - } - - /** - * CubicChunks equivalent of {@link ForgeChunkManager#reorderChunk(ForgeChunkManager.Ticket, ChunkPos)} - * - * Can accept tickets from different worlds. - */ - @Override - public void reorderChunk(ForgeChunkManager.Ticket ticket, CubePos chunk) { - CubicChunkManager.reorderChunk(ticket, chunk); - } - - /** - * CubicChunks equivalent of {@link ForgeChunkManager#unforceChunk(ForgeChunkManager.Ticket, ChunkPos)} - * - * Can accept tickets from different worlds. - */ - @Override - public void unforceChunk(ForgeChunkManager.Ticket ticket, CubePos chunk) { - CubicChunkManager.unforceChunk(ticket, chunk); - } - - - @Override - public CompatGenerationScope doCompatibilityGeneration() { - runningCompatibilityGenerator = true; - return () -> runningCompatibilityGenerator = false; - } - - @Override - public boolean isCompatGenerationScope() { - return runningCompatibilityGenerator; - } - - /** - * Handles cubic chunks world block updates. - * - * @param cbi callback info - * @author Barteks2x - */ - @Inject(method = "updateBlocks", at = @At("HEAD"), cancellable = true) - private void updateBlocksCubicChunks(CallbackInfo cbi) { - if (!isCubicWorld()) { - return; - } - cbi.cancel(); - this.playerCheckLight(); - - int tickSpeed = this.getGameRules().getInt("randomTickSpeed"); - boolean raining = this.isRaining(); - boolean thundering = this.isThundering(); - this.profiler.startSection("pollingChunks"); - - // CubicChunks - iterate over PlayerCubeMap.TickableChunkContainer instead of Chunks, getTickableChunks already includes forced chunks - PlayerCubeMap.TickableChunkContainer chunks = ((PlayerCubeMap) this.playerChunkMap).getTickableChunks(); - for (Chunk chunk : chunks.columns()) { - tickColumn(raining, thundering, chunk); - } - this.profiler.endStartSection("pollingCubes"); - - if (tickSpeed > 0) { - long worldTime = worldInfo.getWorldTotalTime(); - // CubicChunks - iterate over cubes instead of storage array from Chunk - for (ICube cube : chunks.forcedCubes()) { - tickCube(tickSpeed, cube, worldTime); - } - for (ICube cube : chunks.playerTickableCubes()) { - if (cube == null) { // this is the internal array from the arraylist, anything beyond the size is null - break; - } - tickCube(tickSpeed, cube, worldTime); - } - } - - this.profiler.endSection(); - } - - private void tickCube(int tickSpeed, ICube cube, long worldTime) { - if (!((Cube) cube).checkAndUpdateTick(worldTime)) { - return; - } - int chunkBlockX = cubeToMinBlock(cube.getX()); - int chunkBlockZ = cubeToMinBlock(cube.getZ()); - - this.profiler.startSection("tickBlocks"); - ExtendedBlockStorage ebs = cube.getStorage(); - if (ebs != Chunk.NULL_BLOCK_STORAGE && ebs.needsRandomTick()) { - for (int i = 0; i < tickSpeed; ++i) { - tickNextBlock(chunkBlockX, chunkBlockZ, ebs); - } - } - this.profiler.endSection(); - } - - private void tickNextBlock(int chunkBlockX, int chunkBlockZ, ExtendedBlockStorage ebs) { - this.updateLCG = this.updateLCG * 3 + 1013904223; - int rand = this.updateLCG >> 2; - int localX = rand & 15; - int localZ = rand >> 8 & 15; - int localY = rand >> 16 & 15; - IBlockState state = ebs.get(localX, localY, localZ); - Block block = state.getBlock(); - this.profiler.startSection("randomTick"); - - if (block.getTickRandomly()) { - block.randomTick((World) (Object) this, - new BlockPos(localX + chunkBlockX, localY + ebs.getYLocation(), localZ + chunkBlockZ), state, this.rand); - } - - this.profiler.endSection(); - } - - private void tickColumn(boolean raining, boolean thundering, Chunk chunk) { - int chunkBlockX = chunk.x * 16; - int chunkBlockZ = chunk.z * 16; - this.profiler.startSection("checkNextLight"); - chunk.enqueueRelightChecks(); - this.profiler.endStartSection("tickChunk"); - chunk.onTick(false); - this.profiler.endStartSection("thunder"); - - if (this.provider.canDoLightning(chunk) && raining && thundering && this.rand.nextInt(100000) == 0) { - this.updateLCG = this.updateLCG * 3 + 1013904223; - int rand = this.updateLCG >> 2; - BlockPos strikePos = - this.adjustPosToNearbyEntityCubicChunks(new BlockPos(chunkBlockX + (rand & 15), 0, chunkBlockZ + (rand >> 8 & 15))); - - if (strikePos != null && this.isRainingAt(strikePos)) { - DifficultyInstance difficultyinstance = this.getDifficultyForLocation(strikePos); - - if (this.getGameRules().getBoolean("doMobSpawning") - && this.rand.nextDouble() < (double) difficultyinstance.getAdditionalDifficulty() * 0.01D) { - EntitySkeletonHorse skeletonHorse = new EntitySkeletonHorse((World) (Object) this); - skeletonHorse.setTrap(true); - skeletonHorse.setGrowingAge(0); - skeletonHorse.setPosition((double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ()); - this.addEntity(skeletonHorse, CreatureSpawnEvent.SpawnReason.DEFAULT); // Use default spawn reason - this.addWeatherEffect(new EntityLightningBolt((World) (Object) this, - (double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ(), true)); - } else { - this.addWeatherEffect(new EntityLightningBolt((World) (Object) this, - (double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ(), false)); - } - } - } - - this.profiler.endStartSection("iceandsnow"); - - if (this.provider.canDoRainSnowIce(chunk) && this.rand.nextInt(16) == 0) { - this.updateLCG = this.updateLCG * 3 + 1013904223; - int j2 = this.updateLCG >> 2; - BlockPos block = this.getPrecipitationHeight(new BlockPos(chunkBlockX + (j2 & 15), 0, chunkBlockZ + (j2 >> 8 & 15))); - BlockPos blockBelow = block.down(); - - if (this.isAreaLoaded(blockBelow, 1)) { // Forge: check area to avoid loading neighbors in unloaded chunks - if (this.canBlockFreezeNoWater(blockBelow)) { - this.setBlockState(blockBelow, Blocks.ICE.getDefaultState()); - } - } - - // CubicChunks - isBlockLoaded check - if (raining && isBlockLoaded(block) && this.canSnowAt(block, true)) { - this.setBlockState(block, Blocks.SNOW_LAYER.getDefaultState()); - } - - // CubicChunks - isBlockLoaded check - if (raining && isBlockLoaded(blockBelow) && this.getBiome(blockBelow).canRain()) { - this.getBlockState(blockBelow).getBlock().fillWithRain((World) (Object) this, blockBelow); - } - } - this.profiler.endSection(); - } - - private BlockPos adjustPosToNearbyEntityCubicChunks(BlockPos strikeTarget) { - Chunk column = this.getCubeCache().getColumn(Coords.blockToCube(strikeTarget.getX()), Coords.blockToCube(strikeTarget.getZ()), - ICubeProviderServer.Requirement.GET_CACHED); - strikeTarget = column.getPrecipitationHeight(strikeTarget); - Cube cube = this.getCubeCache().getLoadedCube(CubePos.fromBlockCoords(strikeTarget)); - if (cube == null) { - return null; - } - AxisAlignedBB aabb = (new AxisAlignedBB(strikeTarget)).grow(3.0D); - - Iterable setOfLiving = cube.getEntityContainer().getEntitySet().getByClass(EntityLivingBase.class); - for (EntityLivingBase entity : setOfLiving) { - if (!entity.isEntityAlive()) { - continue; - } - BlockPos entityPos = entity.getPosition(); - if (entityPos.getY() < column.getHeightValue(Coords.blockToLocal(entityPos.getX()), Coords.blockToLocal(entityPos.getZ()))) { - continue; - } - if (entity.getEntityBoundingBox().intersects(aabb)) { - return entityPos; - } - } - return strikeTarget; - } -} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java index 5339c781d..d2bd55deb 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java @@ -24,8 +24,8 @@ */ package io.github.opencubicchunks.cubicchunks.core.util; +import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; @@ -43,7 +43,9 @@ import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; import io.github.opencubicchunks.cubicchunks.core.asm.mixin.fixes.common.fakeheight.IASMEventHandler; import io.github.opencubicchunks.cubicchunks.core.asm.mixin.fixes.common.fakeheight.IEventBus; +import net.minecraft.entity.Entity; import net.minecraft.world.World; +import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.gen.IChunkGenerator; import net.minecraftforge.common.MinecraftForge; @@ -56,6 +58,7 @@ import net.minecraftforge.fml.common.eventhandler.EventBus; import net.minecraftforge.fml.common.eventhandler.IEventListener; import net.minecraftforge.fml.common.eventhandler.ListenerList; +import org.bukkit.event.entity.CreatureSpawnEvent; public class CompatHandler { @@ -290,4 +293,24 @@ private static IEventListener[] getFakeEventListeners(ListenerList listenerL return newList.toArray(new IEventListener[0]); } + + /* + * Hybrid servers do have this method in World class, but not in WorldServer. + */ + public static boolean spawnEntity(Entity entity, WorldServer world) { + if (PlatformCompatUtils.isHybridEnv() && MH_WorldServer_Bukkit_addEntity != null) { + try { + return (boolean) MH_WorldServer_Bukkit_addEntity.invokeExact(world, entity, CreatureSpawnEvent.SpawnReason.DEFAULT); + } catch (Throwable th) { + CubicChunks.LOGGER.error("Failed to call WorldServer.addEntity", th); + return false; + } + } + return world.spawnEntity(entity); + } + + // MethodHandle for WorldServer#addEntity(Entity, CreatureSpawnEvent.SpawnReason) method in CraftBukkit + private static final MethodHandle MH_WorldServer_Bukkit_addEntity = ReflectionUtil.methodHandle(true, WorldServer.class, "addEntity", + Entity.class, + ReflectionUtil.getClass("org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason")); } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java index 0040476f3..ea690c785 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/PlatformCompatUtils.java @@ -28,17 +28,22 @@ public class PlatformCompatUtils { private PlatformCompatUtils() { } - private static final boolean isHybridEnv = isClassLoaded("org.bukkit.Bukkit"); + private static final boolean isHybridEnv = isClassExists("org.bukkit.Bukkit"); - public static boolean isClassLoaded(String name) { + public static boolean isClassLoaded(String className) { try { - Class.forName(name); + Class.forName(className); return true; } catch (ClassNotFoundException e) { return false; } } + public static boolean isClassExists(String className) { + String classPath = className.replace('.', '/') + ".class"; + return Thread.currentThread().getContextClassLoader().getResource(classPath) != null; + } + public static boolean isHybridEnv() { return isHybridEnv; } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java index d4376c3d7..31bb895f0 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java @@ -30,6 +30,8 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @ParametersAreNonnullByDefault @@ -65,4 +67,36 @@ public static MethodHandle constructHandle(Class owner, Class... args) { throw new Error(e); } } + + /** + * Returns a method handle for a method of a class. + * + * @param suppressException if true, returns null if the method is not found instead of throwing error + * @param owner the class + * @param name the method name + * @param args the method arguments + * @return the method handle, or null if not found and suppressException is true + */ + @CheckForNull + public static MethodHandle methodHandle(boolean suppressException, Class owner, String name, Class... args) { + for (Class clazz : args) { + if (clazz == null) return null; + } + try { + return MethodHandles.lookup().unreflect(owner.getDeclaredMethod(name, args)); + } catch (Exception e) { + if (suppressException) return null; + //if it happens - either something has gone horribly wrong or the JVM is blocking access + throw new Error(e); + } + } + + @Nullable + public static Class getClass(String className) { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + return null; + } + } } diff --git a/src/main/resources/cubicchunks.mixins.core.bukkit.json b/src/main/resources/cubicchunks.mixins.core.bukkit.json index 7591f6cf5..633483c2a 100644 --- a/src/main/resources/cubicchunks.mixins.core.bukkit.json +++ b/src/main/resources/cubicchunks.mixins.core.bukkit.json @@ -12,7 +12,6 @@ "server": [ "common.MixinWorld_HeightLimits_Bukkit_Sided", "common.MixinPlayerList_Bukkit_Sided", - "common.MixinChunk_Cubes_Bukkit_Sided", - "common.MixinWorldServer_Bukkit" + "common.MixinChunk_Cubes_Bukkit_Sided" ] } \ No newline at end of file diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 07fc9f4a2..460b16914 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -37,6 +37,7 @@ "common.MixinWorldEntitySpawner", "common.MixinWorldInfo", "common.MixinWorldProvider", + "common.MixinWorldServer", "common.MixinWorldSettings", "common.vanillaclient.ICPacketPlayer", "common.vanillaclient.ICPacketPlayerDigging", diff --git a/src/main/resources/cubicchunks.mixins.core.vanilla.json b/src/main/resources/cubicchunks.mixins.core.vanilla.json index 9b202a222..bad879c11 100644 --- a/src/main/resources/cubicchunks.mixins.core.vanilla.json +++ b/src/main/resources/cubicchunks.mixins.core.vanilla.json @@ -10,7 +10,6 @@ "mixins": [ "common.MixinChunk_Cubes_Vanilla_Sided", "common.MixinWorld_HeightLimits_Vanilla_Sided", - "common.MixinWorldServer", "common.MixinPlayerList_Vanilla_Sided" ], "client": [], From e698bab9db72967a2986ee56e8cd4d0f773e73fb Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Sun, 5 Jan 2025 09:18:14 -0800 Subject: [PATCH 09/13] Requested changes --- .../core/asm/mixin/core/common/MixinWorldServer.java | 1 - .../cubicchunks/core/util/CompatHandler.java | 12 ++++++------ .../cubicchunks/core/util/ReflectionUtil.java | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java index c89cae870..ecc2fdcc5 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java @@ -91,7 +91,6 @@ import java.util.Map; import java.util.Set; -import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; /** diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java index d2bd55deb..1c031e41e 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java @@ -92,6 +92,11 @@ public class CompatHandler { private static final Map packageToModId = getPackageToModId(); + // MethodHandle for WorldServer#addEntity(Entity, CreatureSpawnEvent.SpawnReason) method in CraftBukkit + private static final MethodHandle MH_WorldServer_Bukkit_addEntity = ReflectionUtil.methodHandle(true, WorldServer.class, "addEntity", + Entity.class, + ReflectionUtil.getClass("org.bukkit.event.entity.CreatureSpawnEvent$SpawnReason")); + private static IEventListener[] fakeChunkLoadListeners; public static void init() { @@ -302,15 +307,10 @@ public static boolean spawnEntity(Entity entity, WorldServer world) { try { return (boolean) MH_WorldServer_Bukkit_addEntity.invokeExact(world, entity, CreatureSpawnEvent.SpawnReason.DEFAULT); } catch (Throwable th) { - CubicChunks.LOGGER.error("Failed to call WorldServer.addEntity", th); + CubicChunks.LOGGER.error("Failed to invoke WorldServer#addEntity", th); return false; } } return world.spawnEntity(entity); } - - // MethodHandle for WorldServer#addEntity(Entity, CreatureSpawnEvent.SpawnReason) method in CraftBukkit - private static final MethodHandle MH_WorldServer_Bukkit_addEntity = ReflectionUtil.methodHandle(true, WorldServer.class, "addEntity", - Entity.class, - ReflectionUtil.getClass("org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason")); } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java index 31bb895f0..1128fa3dc 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java @@ -84,7 +84,7 @@ public static MethodHandle methodHandle(boolean suppressException, Class owne } try { return MethodHandles.lookup().unreflect(owner.getDeclaredMethod(name, args)); - } catch (Exception e) { + } catch (IllegalAccessException | NoSuchMethodException e) { if (suppressException) return null; //if it happens - either something has gone horribly wrong or the JVM is blocking access throw new Error(e); From c90063fe0a9c22def162c644d7098983e564a603 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Sun, 5 Jan 2025 09:30:01 -0800 Subject: [PATCH 10/13] Requested changes --- .../asm/mixin/core/common/MixinWorld.java | 3 ++ .../mixin/core/common/MixinWorldServer.java | 8 ++++- .../cubicchunks/core/util/CompatHandler.java | 24 ------------- .../cubicchunks/core/util/ReflectionUtil.java | 34 ------------------- 4 files changed, 10 insertions(+), 59 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java index 9e34f3cac..21260f9d8 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java @@ -41,6 +41,7 @@ import io.github.opencubicchunks.cubicchunks.core.world.cube.Cube; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.profiler.Profiler; import net.minecraft.tileentity.TileEntity; @@ -143,6 +144,8 @@ public abstract class MixinWorld implements ICubicWorldInternal { @Shadow public abstract void setLightFor(EnumSkyBlock type, BlockPos pos, int lightValue); + @Shadow public abstract boolean spawnEntity(Entity entityIn); + protected void initCubicWorld(IntRange heightRange, IntRange generationRange) { ((ICubicWorldSettings) worldInfo).setCubic(true); // Set the world height boundaries to their highest and lowest values respectively diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java index ecc2fdcc5..780a16a28 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java @@ -124,6 +124,10 @@ public abstract class MixinWorldServer extends MixinWorld implements ICubicWorld @Shadow public abstract PlayerChunkMap getPlayerChunkMap(); + @Shadow protected abstract boolean canAddEntity(Entity entityIn); + + @Shadow public abstract boolean spawnEntity(Entity entityIn); + @Override public void initCubicWorldServer(IntRange heightRange, IntRange generationRange) { super.initCubicWorld(heightRange, generationRange); this.isCubicWorld = true; @@ -366,7 +370,9 @@ private void tickColumn(boolean raining, boolean thundering, Chunk chunk) { skeletonHorse.setTrap(true); skeletonHorse.setGrowingAge(0); skeletonHorse.setPosition((double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ()); - CompatHandler.spawnEntity(skeletonHorse, (WorldServer) (Object) this); + if (this.canAddEntity(skeletonHorse)) { + this.spawnEntity(skeletonHorse); + } this.addWeatherEffect(new EntityLightningBolt((World) (Object) this, (double) strikePos.getX(), (double) strikePos.getY(), (double) strikePos.getZ(), true)); } else { diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java index 1c031e41e..c4dbdefd3 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/CompatHandler.java @@ -24,7 +24,6 @@ */ package io.github.opencubicchunks.cubicchunks.core.util; -import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; import java.util.AbstractMap; import java.util.ArrayList; @@ -43,9 +42,7 @@ import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; import io.github.opencubicchunks.cubicchunks.core.asm.mixin.fixes.common.fakeheight.IASMEventHandler; import io.github.opencubicchunks.cubicchunks.core.asm.mixin.fixes.common.fakeheight.IEventBus; -import net.minecraft.entity.Entity; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.gen.IChunkGenerator; import net.minecraftforge.common.MinecraftForge; @@ -58,7 +55,6 @@ import net.minecraftforge.fml.common.eventhandler.EventBus; import net.minecraftforge.fml.common.eventhandler.IEventListener; import net.minecraftforge.fml.common.eventhandler.ListenerList; -import org.bukkit.event.entity.CreatureSpawnEvent; public class CompatHandler { @@ -92,11 +88,6 @@ public class CompatHandler { private static final Map packageToModId = getPackageToModId(); - // MethodHandle for WorldServer#addEntity(Entity, CreatureSpawnEvent.SpawnReason) method in CraftBukkit - private static final MethodHandle MH_WorldServer_Bukkit_addEntity = ReflectionUtil.methodHandle(true, WorldServer.class, "addEntity", - Entity.class, - ReflectionUtil.getClass("org.bukkit.event.entity.CreatureSpawnEvent$SpawnReason")); - private static IEventListener[] fakeChunkLoadListeners; public static void init() { @@ -298,19 +289,4 @@ private static IEventListener[] getFakeEventListeners(ListenerList listenerL return newList.toArray(new IEventListener[0]); } - - /* - * Hybrid servers do have this method in World class, but not in WorldServer. - */ - public static boolean spawnEntity(Entity entity, WorldServer world) { - if (PlatformCompatUtils.isHybridEnv() && MH_WorldServer_Bukkit_addEntity != null) { - try { - return (boolean) MH_WorldServer_Bukkit_addEntity.invokeExact(world, entity, CreatureSpawnEvent.SpawnReason.DEFAULT); - } catch (Throwable th) { - CubicChunks.LOGGER.error("Failed to invoke WorldServer#addEntity", th); - return false; - } - } - return world.spawnEntity(entity); - } } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java index 1128fa3dc..d4376c3d7 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/util/ReflectionUtil.java @@ -30,8 +30,6 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @ParametersAreNonnullByDefault @@ -67,36 +65,4 @@ public static MethodHandle constructHandle(Class owner, Class... args) { throw new Error(e); } } - - /** - * Returns a method handle for a method of a class. - * - * @param suppressException if true, returns null if the method is not found instead of throwing error - * @param owner the class - * @param name the method name - * @param args the method arguments - * @return the method handle, or null if not found and suppressException is true - */ - @CheckForNull - public static MethodHandle methodHandle(boolean suppressException, Class owner, String name, Class... args) { - for (Class clazz : args) { - if (clazz == null) return null; - } - try { - return MethodHandles.lookup().unreflect(owner.getDeclaredMethod(name, args)); - } catch (IllegalAccessException | NoSuchMethodException e) { - if (suppressException) return null; - //if it happens - either something has gone horribly wrong or the JVM is blocking access - throw new Error(e); - } - } - - @Nullable - public static Class getClass(String className) { - try { - return Class.forName(className); - } catch (ClassNotFoundException e) { - return null; - } - } } From 9af67609bd7f7ed1013dc00fad7a480254215f8a Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Sun, 5 Jan 2025 09:34:50 -0800 Subject: [PATCH 11/13] Remove unused shadow --- .../core/asm/mixin/core/common/MixinWorldServer.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java index 780a16a28..2f6a5c2db 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorldServer.java @@ -126,8 +126,6 @@ public abstract class MixinWorldServer extends MixinWorld implements ICubicWorld @Shadow protected abstract boolean canAddEntity(Entity entityIn); - @Shadow public abstract boolean spawnEntity(Entity entityIn); - @Override public void initCubicWorldServer(IntRange heightRange, IntRange generationRange) { super.initCubicWorld(heightRange, generationRange); this.isCubicWorld = true; From fa6839694d070a6c0b70b4fe9895539f0bdab9d0 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Sun, 5 Jan 2025 10:24:09 -0800 Subject: [PATCH 12/13] Move package & Fix MixinGen --- build.gradle.kts | 8 ++++++++ .../core/asm/coremod/CubicChunksCoreMod.java | 4 ++-- .../bukkit}/common/MixinChunk_Cubes_Bukkit_Sided.java | 2 +- .../bukkit}/common/MixinPlayerList_Bukkit_Sided.java | 2 +- .../common/MixinWorld_HeightLimits_Bukkit_Sided.java | 2 +- .../common/MixinChunk_Cubes_Vanilla_Sided.java | 2 +- .../vanilla}/common/MixinPlayerList_Vanilla_Sided.java | 3 ++- .../common/MixinWorld_HeightLimits_Vanilla_Sided.java | 3 ++- ....json => cubicchunks.mixins.core_sided.bukkit.json} | 10 +++++----- ...json => cubicchunks.mixins.core_sided.vanilla.json} | 2 +- 10 files changed, 24 insertions(+), 14 deletions(-) rename src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/{core => core_sided/bukkit}/common/MixinChunk_Cubes_Bukkit_Sided.java (99%) rename src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/{core => core_sided/bukkit}/common/MixinPlayerList_Bukkit_Sided.java (99%) rename src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/{core => core_sided/bukkit}/common/MixinWorld_HeightLimits_Bukkit_Sided.java (99%) rename src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/{core => core_sided/vanilla}/common/MixinChunk_Cubes_Vanilla_Sided.java (99%) rename src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/{core => core_sided/vanilla}/common/MixinPlayerList_Vanilla_Sided.java (97%) rename src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/{core => core_sided/vanilla}/common/MixinWorld_HeightLimits_Vanilla_Sided.java (95%) rename src/main/resources/{cubicchunks.mixins.core.bukkit.json => cubicchunks.mixins.core_sided.bukkit.json} (86%) rename src/main/resources/{cubicchunks.mixins.core.vanilla.json => cubicchunks.mixins.core_sided.vanilla.json} (94%) diff --git a/build.gradle.kts b/build.gradle.kts index 0dc0ce464..0b970d668 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -176,6 +176,14 @@ mixinGen { defaultCompatibilityLevel = "JAVA_8" defaultMinVersion = "0.7.10" + config("core_sided.bukkit") { + required = false + conformVisibility = true + } + config("core_sided.vanilla") { + required = false + conformVisibility = true + } config("core") { required = true conformVisibility = true diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java index bab7d050b..9351b1bb9 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/coremod/CubicChunksCoreMod.java @@ -106,10 +106,10 @@ public static void initMixin() { MixinBootstrap.init(); Mixins.addConfiguration("cubicchunks.mixins.core.json"); if (PlatformCompatUtils.isHybridEnv()) { - Mixins.addConfiguration("cubicchunks.mixins.core.bukkit.json"); + Mixins.addConfiguration("cubicchunks.mixins.core_sided.bukkit.json"); System.out.println("Running in Forge+Bukkit hybrid environment, using compatibility mixins"); } else { - Mixins.addConfiguration("cubicchunks.mixins.core.vanilla.json"); + Mixins.addConfiguration("cubicchunks.mixins.core_sided.vanilla.json"); } Mixins.addConfiguration("cubicchunks.mixins.fixes.json"); Mixins.addConfiguration("cubicchunks.mixins.selectable.json"); diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinChunk_Cubes_Bukkit_Sided.java similarity index 99% rename from src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinChunk_Cubes_Bukkit_Sided.java index 21fbd7ba9..a61d2a132 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Bukkit_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinChunk_Cubes_Bukkit_Sided.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.bukkit.common; import io.github.opencubicchunks.cubicchunks.api.util.Coords; import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinPlayerList_Bukkit_Sided.java similarity index 99% rename from src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinPlayerList_Bukkit_Sided.java index 88a415941..58c2764e6 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Bukkit_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinPlayerList_Bukkit_Sided.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.bukkit.common; import io.github.opencubicchunks.cubicchunks.api.util.Coords; import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinWorld_HeightLimits_Bukkit_Sided.java similarity index 99% rename from src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinWorld_HeightLimits_Bukkit_Sided.java index 46569a67c..4430eca94 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Bukkit_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/bukkit/common/MixinWorld_HeightLimits_Bukkit_Sided.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.bukkit.common; import static io.github.opencubicchunks.cubicchunks.api.util.Coords.cubeToMinBlock; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Vanilla_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinChunk_Cubes_Vanilla_Sided.java similarity index 99% rename from src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Vanilla_Sided.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinChunk_Cubes_Vanilla_Sided.java index daaa40242..351b7a8bd 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinChunk_Cubes_Vanilla_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinChunk_Cubes_Vanilla_Sided.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.vanilla.common; import io.github.opencubicchunks.cubicchunks.api.util.Coords; import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Vanilla_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinPlayerList_Vanilla_Sided.java similarity index 97% rename from src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Vanilla_Sided.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinPlayerList_Vanilla_Sided.java index b12ebf9f7..8852dfa11 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinPlayerList_Vanilla_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinPlayerList_Vanilla_Sided.java @@ -22,11 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.vanilla.common; import io.github.opencubicchunks.cubicchunks.api.util.Coords; import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; import io.github.opencubicchunks.cubicchunks.core.asm.mixin.ICubicWorldInternal; +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinPlayerList; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.management.PlayerList; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Vanilla_Sided.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinWorld_HeightLimits_Vanilla_Sided.java similarity index 95% rename from src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Vanilla_Sided.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinWorld_HeightLimits_Vanilla_Sided.java index 990ba1ce0..6aba6cce1 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld_HeightLimits_Vanilla_Sided.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core_sided/vanilla/common/MixinWorld_HeightLimits_Vanilla_Sided.java @@ -22,11 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common; +package io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.vanilla.common; import static io.github.opencubicchunks.cubicchunks.api.util.Coords.cubeToMinBlock; import io.github.opencubicchunks.cubicchunks.api.world.ICubicWorld; +import io.github.opencubicchunks.cubicchunks.core.asm.mixin.core.common.MixinWorld_HeightLimits; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; diff --git a/src/main/resources/cubicchunks.mixins.core.bukkit.json b/src/main/resources/cubicchunks.mixins.core_sided.bukkit.json similarity index 86% rename from src/main/resources/cubicchunks.mixins.core.bukkit.json rename to src/main/resources/cubicchunks.mixins.core_sided.bukkit.json index 633483c2a..c919f3bf6 100644 --- a/src/main/resources/cubicchunks.mixins.core.bukkit.json +++ b/src/main/resources/cubicchunks.mixins.core_sided.bukkit.json @@ -1,17 +1,17 @@ { "required": false, - "package": "io.github.opencubicchunks.cubicchunks.core.asm.mixin.core", + "package": "io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.bukkit", "refmap": "cubicchunks.mixins.refmap.json", "compatibilityLevel": "JAVA_8", "minVersion": "0.7.10", "overwrites": { "conformVisibility": true }, - "mixins": [], - "client": [], - "server": [ + "mixins": [ "common.MixinWorld_HeightLimits_Bukkit_Sided", "common.MixinPlayerList_Bukkit_Sided", "common.MixinChunk_Cubes_Bukkit_Sided" - ] + ], + "client": [], + "server": [] } \ No newline at end of file diff --git a/src/main/resources/cubicchunks.mixins.core.vanilla.json b/src/main/resources/cubicchunks.mixins.core_sided.vanilla.json similarity index 94% rename from src/main/resources/cubicchunks.mixins.core.vanilla.json rename to src/main/resources/cubicchunks.mixins.core_sided.vanilla.json index bad879c11..0721fce7e 100644 --- a/src/main/resources/cubicchunks.mixins.core.vanilla.json +++ b/src/main/resources/cubicchunks.mixins.core_sided.vanilla.json @@ -1,6 +1,6 @@ { "required": false, - "package": "io.github.opencubicchunks.cubicchunks.core.asm.mixin.core", + "package": "io.github.opencubicchunks.cubicchunks.core.asm.mixin.core_sided.vanilla", "refmap": "cubicchunks.mixins.refmap.json", "compatibilityLevel": "JAVA_8", "minVersion": "0.7.10", From 2dc5ed5ca6db7a9a7963f056108c9dac569e8008 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Mon, 6 Jan 2025 08:31:46 -0800 Subject: [PATCH 13/13] [ci skip] Add comment for spawnEntity --- .../cubicchunks/core/asm/mixin/core/common/MixinWorld.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java index 21260f9d8..f9b2da7bf 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/core/asm/mixin/core/common/MixinWorld.java @@ -144,6 +144,11 @@ public abstract class MixinWorld implements ICubicWorldInternal { @Shadow public abstract void setLightFor(EnumSkyBlock type, BlockPos pos, int lightValue); + /* + * This shadow method is used by MixinWorldServer, place in here for Bukkit compatibility. + * As World#spawnEntity method is not getting overridden in CraftBukkit WorldServer class, + * shadowing spawnEntity in WorldServer will break Bukkit compatibility. + */ @Shadow public abstract boolean spawnEntity(Entity entityIn); protected void initCubicWorld(IntRange heightRange, IntRange generationRange) {