diff --git a/sources/pom.xml b/sources/pom.xml
index 1b2a35df1..496572704 100644
--- a/sources/pom.xml
+++ b/sources/pom.xml
@@ -3,7 +3,7 @@
4.0.0
akarin
jar
- 1.12.2-R0.4-RELEASE
+ 1.12.2-R0.4-SNAPSHOT
Akarin
https://github.com/Akarin-project/Akarin
@@ -134,7 +134,7 @@
io.akarin
legacylauncher
- 1.25
+ 1.26
org.spongepowered
diff --git a/sources/src/main/java/io/akarin/api/internal/mixin/IMixinChunk.java b/sources/src/main/java/io/akarin/api/internal/mixin/IMixinChunk.java
deleted file mode 100644
index 7dd2723b1..000000000
--- a/sources/src/main/java/io/akarin/api/internal/mixin/IMixinChunk.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package io.akarin.api.internal.mixin;
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.Nullable;
-
-import net.minecraft.server.Chunk;
-import net.minecraft.server.EnumSkyBlock;
-
-public interface IMixinChunk {
- AtomicInteger getPendingLightUpdates();
-
- long getLightUpdateTime();
-
- boolean areNeighborsLoaded();
-
- @Nullable Chunk getNeighborChunk(int index);
-
- CopyOnWriteArrayList getQueuedLightingUpdates(EnumSkyBlock type);
-
- List getNeighbors();
-
- void setNeighborChunk(int index, @Nullable Chunk chunk);
-
- void setLightUpdateTime(long time);
-}
\ No newline at end of file
diff --git a/sources/src/main/java/io/akarin/api/internal/mixin/IMixinWorldServer.java b/sources/src/main/java/io/akarin/api/internal/mixin/IMixinWorldServer.java
deleted file mode 100644
index 03f5ad0ae..000000000
--- a/sources/src/main/java/io/akarin/api/internal/mixin/IMixinWorldServer.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.akarin.api.internal.mixin;
-
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-
-import net.minecraft.server.BlockPosition;
-import net.minecraft.server.Chunk;
-import net.minecraft.server.EnumSkyBlock;
-
-public interface IMixinWorldServer {
- boolean updateLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk chunk);
-
- boolean checkLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List neighbors);
-
- ExecutorService getLightingExecutor();
-}
\ No newline at end of file
diff --git a/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java b/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java
index 97d4e2e43..62115a4f5 100644
--- a/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java
+++ b/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java
@@ -185,16 +185,6 @@ public class AkarinGlobalConfig {
keepAliveTimeout = getSeconds(getString("core.keep-alive-response-timeout", "30s")) * 1000;
}
- public static int asyncLightingThreads;
- private static void asyncLightingThreads() {
- asyncLightingThreads = getInt("core.async-lighting.executor-threads", 4);
- }
-
- public static boolean asyncLightingWorkStealing;
- private static void asyncLightingWorkStealing() {
- asyncLightingWorkStealing = getBoolean("core.async-lighting.use-work-stealing", false);
- }
-
public static boolean throwOnAsyncCaught;
private static void throwOnAsyncCaught() {
throwOnAsyncCaught = getBoolean("core.thread-safe.async-catcher.throw-on-caught", true);
diff --git a/sources/src/main/java/io/akarin/server/mixin/cps/MixinChunk.java b/sources/src/main/java/io/akarin/server/mixin/cps/MixinChunk.java
deleted file mode 100644
index 2939743c8..000000000
--- a/sources/src/main/java/io/akarin/server/mixin/cps/MixinChunk.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * This file is part of Sponge, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) 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.akarin.server.mixin.cps;
-
-import java.util.List;
-import javax.annotation.Nullable;
-
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import com.google.common.collect.Lists;
-
-import io.akarin.api.internal.mixin.IMixinChunk;
-import net.minecraft.server.BlockPosition;
-import net.minecraft.server.Chunk;
-import net.minecraft.server.EnumDirection;
-import net.minecraft.server.MCUtil;
-import net.minecraft.server.World;
-
-@Mixin(value = Chunk.class, remap = false)
-public abstract class MixinChunk implements IMixinChunk {
- private Chunk[] neighborChunks = new Chunk[4];
- private static final EnumDirection[] CARDINAL_DIRECTIONS = new EnumDirection[] {EnumDirection.NORTH, EnumDirection.SOUTH, EnumDirection.EAST, EnumDirection.WEST};
-
- @Shadow @Final public World world;
- @Shadow @Final public int locX;
- @Shadow @Final public int locZ;
-
- @Override
- public Chunk getNeighborChunk(int index) {
- return this.neighborChunks[index];
- }
-
- @Override
- public void setNeighborChunk(int index, @Nullable Chunk chunk) {
- this.neighborChunks[index] = chunk;
- }
-
- @Override
- public List getNeighbors() {
- List neighborList = Lists.newArrayList();
- for (Chunk neighbor : this.neighborChunks) {
- if (neighbor != null) {
- neighborList.add(neighbor);
- }
- }
- return neighborList;
- }
-
- @Override
- public boolean areNeighborsLoaded() {
- for (int i = 0; i < 4; i++) {
- if (this.neighborChunks[i] == null) {
- return false;
- }
- }
- return true;
- }
-
- private static int directionToIndex(EnumDirection direction) {
- switch (direction) {
- case NORTH:
- return 0;
- case SOUTH:
- return 1;
- case EAST:
- return 2;
- case WEST:
- return 3;
- default:
- throw new IllegalArgumentException("Unexpected direction");
- }
- }
-
- @Inject(method = "addEntities", at = @At("RETURN"))
- public void onLoadReturn(CallbackInfo ci) {
- BlockPosition origin = new BlockPosition(locX, 0, locZ);
- for (EnumDirection direction : CARDINAL_DIRECTIONS) {
- BlockPosition shift = origin.shift(direction);
- Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(world.getChunkProvider(), shift.getX(), shift.getZ());
- if (neighbor != null) {
- int neighborIndex = directionToIndex(direction);
- int oppositeNeighborIndex = directionToIndex(direction.opposite());
- this.setNeighborChunk(neighborIndex, neighbor);
- ((IMixinChunk) neighbor).setNeighborChunk(oppositeNeighborIndex, (Chunk) (Object) this);
- }
- }
- }
-
- @Inject(method = "removeEntities", at = @At("RETURN"))
- public void onUnload(CallbackInfo ci) {
- BlockPosition origin = new BlockPosition(locX, 0, locZ);
- for (EnumDirection direction : CARDINAL_DIRECTIONS) {
- BlockPosition shift = origin.shift(direction);
- Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(world.getChunkProvider(), shift.getX(), shift.getZ());
- if (neighbor != null) {
- int neighborIndex = directionToIndex(direction);
- int oppositeNeighborIndex = directionToIndex(direction.opposite());
- this.setNeighborChunk(neighborIndex, null);
- ((IMixinChunk) neighbor).setNeighborChunk(oppositeNeighborIndex, null);
- }
- }
- }
-}
diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java
deleted file mode 100644
index aa8e8ac79..000000000
--- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java
+++ /dev/null
@@ -1,640 +0,0 @@
-/*
- * This file is part of Sponge, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) 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.akarin.server.mixin.lighting;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.Nullable;
-
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.Redirect;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import io.akarin.api.internal.Akari;
-import io.akarin.api.internal.mixin.IMixinChunk;
-import io.akarin.api.internal.mixin.IMixinWorldServer;
-import net.minecraft.server.BlockPosition;
-import net.minecraft.server.Blocks;
-import net.minecraft.server.Chunk;
-import net.minecraft.server.ChunkSection;
-import net.minecraft.server.EnumDirection;
-import net.minecraft.server.EnumSkyBlock;
-import net.minecraft.server.IBlockData;
-import net.minecraft.server.MCUtil;
-import net.minecraft.server.TileEntity;
-import net.minecraft.server.World;
-import net.minecraft.server.BlockPosition.MutableBlockPosition;
-
-@Mixin(value = Chunk.class, remap = false, priority = 1001)
-public abstract class MixinChunk implements IMixinChunk {
-
- // Keeps track of block positions in this chunk currently queued for sky light update
- private CopyOnWriteArrayList queuedSkyLightingUpdates = new CopyOnWriteArrayList<>();
- // Keeps track of block positions in this chunk currently queued for block light update
- private CopyOnWriteArrayList queuedBlockLightingUpdates = new CopyOnWriteArrayList<>();
- private AtomicInteger pendingLightUpdates = new AtomicInteger();
- private long lightUpdateTime;
- private static ExecutorService lightExecutorService;
-
- @Shadow(aliases = "m") private boolean isGapLightingUpdated;
- @Shadow(aliases = "r") private boolean ticked;
- @Shadow @Final private ChunkSection[] sections;
- @Shadow @Final public int locX;
- @Shadow @Final public int locZ;
- @Shadow @Final public World world;
- @Shadow @Final public int[] heightMap;
- /** Which columns need their skylightMaps updated. */
- @Shadow(aliases = "i") @Final private boolean[] updateSkylightColumns;
- /** Queue containing the BlockPosition of tile entities queued for creation */
- @Shadow(aliases = "y") @Final private ConcurrentLinkedQueue tileEntityPosQueue;
- /** Boolean value indicating if the terrain is populated. */
- @Shadow(aliases = "done") private boolean isTerrainPopulated;
- @Shadow(aliases = "lit") private boolean isLightPopulated;
- /** Lowest value in the heightmap. */
- @Shadow(aliases = "v") private int heightMapMinimum;
-
- @Shadow(aliases = "b") public abstract int getHeightValue(int x, int z);
- @Shadow(aliases = "g") @Nullable public abstract TileEntity createNewTileEntity(BlockPosition pos);
- @Shadow(aliases = "a") @Nullable public abstract TileEntity getTileEntity(BlockPosition pos, Chunk.EnumTileEntityState state);
- @Shadow @Final public abstract IBlockData getBlockData(BlockPosition pos);
- @Shadow @Final public abstract IBlockData getBlockData(int x, int y, int z);
- @Shadow public abstract boolean isUnloading();
- /** Checks the height of a block next to a sky-visible block and schedules a lighting update as necessary */
- @Shadow(aliases = "b") public abstract void checkSkylightNeighborHeight(int x, int z, int maxValue);
- @Shadow(aliases = "a") public abstract void updateSkylightNeighborHeight(int x, int z, int startY, int endY);
- @Shadow(aliases = "z") public abstract void setSkylightUpdated();
- @Shadow(aliases = "g") public abstract int getTopFilledSegment();
- @Shadow public abstract void markDirty();
-
- @Inject(method = "", at = @At("RETURN"))
- public void onConstruct(World worldIn, int x, int z, CallbackInfo ci) {
- lightExecutorService = ((IMixinWorldServer) worldIn).getLightingExecutor();
- }
-
- @Override
- public AtomicInteger getPendingLightUpdates() {
- return this.pendingLightUpdates;
- }
-
- @Override
- public long getLightUpdateTime() {
- return this.lightUpdateTime;
- }
-
- @Override
- public void setLightUpdateTime(long time) {
- this.lightUpdateTime = time;
- }
-
- @Inject(method = "b(Z)V", at = @At("HEAD"), cancellable = true)
- private void onTickHead(boolean skipRecheckGaps, CallbackInfo ci) {
- final List neighbors = this.getSurroundingChunks();
- if (this.isGapLightingUpdated && this.world.worldProvider.m() && !skipRecheckGaps && !neighbors.isEmpty()) { // OBFHELPER: hasSkyLight
- lightExecutorService.execute(() -> {
- this.recheckGapsAsync(neighbors);
- });
- this.isGapLightingUpdated = false;
- }
-
- this.ticked = true;
-
- if (!this.isLightPopulated && this.isTerrainPopulated && !neighbors.isEmpty()) {
- lightExecutorService.execute(() -> {
- this.checkLightAsync(neighbors);
- });
- // set to true to avoid requeuing the same task when not finished
- this.isLightPopulated = true;
- }
-
- while (!this.tileEntityPosQueue.isEmpty()) {
- BlockPosition blockpos = this.tileEntityPosQueue.poll();
-
- if (this.getTileEntity(blockpos, Chunk.EnumTileEntityState.CHECK) == null && this.getBlockData(blockpos).getBlock().isTileEntity()) { // OBFHELPER: getTileEntity
- TileEntity tileentity = this.createNewTileEntity(blockpos);
- this.world.setTileEntity(blockpos, tileentity);
- this.world.b(blockpos, blockpos); // OBFHELPER: markBlockRangeForRenderUpdate
- }
- }
- ci.cancel();
- }
-
- @Redirect(method = "b(III)V", at = @At(value = "INVOKE", target = "net/minecraft/server/World.getHighestBlockYAt(Lnet/minecraft/server/BlockPosition;)Lnet/minecraft/server/BlockPosition;"))
- private BlockPosition onCheckSkylightGetHeight(World world, BlockPosition pos) {
- final Chunk chunk = this.getLightChunk(pos.getX() >> 4, pos.getZ() >> 4, null);
- if (chunk == null) {
- return BlockPosition.ZERO;
- }
-
- return new BlockPosition(pos.getX(), chunk.b(pos.getX() & 15, pos.getZ() & 15), pos.getZ()); // OBFHELPER: getHeightValue
- }
-
- @Redirect(method = "a(IIII)V", at = @At(value = "INVOKE", target = "net/minecraft/server/World.areChunksLoaded(Lnet/minecraft/server/BlockPosition;I)Z"))
- private boolean onAreaLoadedSkyLightNeighbor(World world, BlockPosition pos, int radius) {
- return this.isAreaLoaded();
- }
-
- @Redirect(method = "a(IIII)V", at = @At(value = "INVOKE", target = "net/minecraft/server/World.c(Lnet/minecraft/server/EnumSkyBlock;Lnet/minecraft/server/BlockPosition;)Z"))
- private boolean onCheckLightForSkylightNeighbor(World world, EnumSkyBlock enumSkyBlock, BlockPosition pos) {
- return this.checkWorldLightFor(enumSkyBlock, pos);
- }
-
- /**
- * Rechecks chunk gaps async.
- *
- * @param neighbors A thread-safe list of surrounding neighbor chunks
- */
- private void recheckGapsAsync(List neighbors) {
- for (int i = 0; i < 16; ++i) {
- for (int j = 0; j < 16; ++j) {
- if (this.updateSkylightColumns[i + j * 16]) {
- this.updateSkylightColumns[i + j * 16] = false;
- int k = this.getHeightValue(i, j);
- int l = this.locX * 16 + i;
- int i1 = this.locZ * 16 + j;
- int j1 = Integer.MAX_VALUE;
-
- for (EnumDirection enumfacing : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
- final Chunk chunk = this.getLightChunk((l + enumfacing.getAdjacentX()) >> 4, (i1 + enumfacing.getAdjacentZ()) >> 4, neighbors);
- if (chunk == null || chunk.isUnloading()) {
- continue;
- }
- j1 = Math.min(j1, chunk.w()); // OBFHELPER: getLowestHeight
- }
-
- this.checkSkylightNeighborHeight(l, i1, j1);
-
- for (EnumDirection enumfacing1 : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
- this.checkSkylightNeighborHeight(l + enumfacing1.getAdjacentX(), i1 + enumfacing1.getAdjacentZ(), k);
- }
- }
- }
-
- // this.isGapLightingUpdated = false;
- }
- }
-
- @Redirect(method = "n()V", at = @At(value = "INVOKE", target = "net/minecraft/server/World.getType(Lnet/minecraft/server/BlockPosition;)Lnet/minecraft/server/IBlockData;"))
- private IBlockData onRelightChecksGetBlockData(World world, BlockPosition pos) {
- Chunk chunk = MCUtil.getLoadedChunkWithoutMarkingActive(world.getChunkProvider(), pos.getX() >> 4, pos.getZ() >> 4);
-
- final IMixinChunk spongeChunk = (IMixinChunk) chunk;
- if (chunk == null || chunk.isUnloading() || !spongeChunk.areNeighborsLoaded()) {
- return Blocks.AIR.getBlockData();
- }
-
- return chunk.getBlockData(pos);
- }
-
- @Redirect(method = "n()V", at = @At(value = "INVOKE", target = "net/minecraft/server/World.w(Lnet/minecraft/server/BlockPosition;)Z"))
- private boolean onRelightChecksCheckLight(World world, BlockPosition pos) {
- return this.checkWorldLight(pos);
- }
-
- // Avoids grabbing chunk async during light check
- @Redirect(method = "e(II)Z", at = @At(value = "INVOKE", target = "net/minecraft/server/World.w(Lnet/minecraft/server/BlockPosition;)Z"))
- private boolean onCheckLightWorld(World world, BlockPosition pos) {
- return this.checkWorldLight(pos);
- }
-
- @Inject(method = "o()V", at = @At("HEAD"), cancellable = true)
- private void checkLightHead(CallbackInfo ci) {
- if (this.world.getMinecraftServer().isStopped() || lightExecutorService.isShutdown()) {
- return;
- }
-
- if (this.isUnloading()) {
- return;
- }
- final List neighborChunks = this.getSurroundingChunks();
- if (neighborChunks.isEmpty()) {
- this.isLightPopulated = false;
- return;
- }
-
- if (Akari.isPrimaryThread()) {
- try {
- lightExecutorService.execute(() -> {
- this.checkLightAsync(neighborChunks);
- });
- } catch (RejectedExecutionException ex) {
- // This could happen if ServerHangWatchdog kills the server
- // between the start of the method and the execute() call.
- if (!this.world.getMinecraftServer().isStopped() && !lightExecutorService.isShutdown()) {
- throw ex;
- }
- }
- } else {
- this.checkLightAsync(neighborChunks);
- }
- ci.cancel();
- }
-
- /**
- * Checks light async.
- *
- * @param neighbors A thread-safe list of surrounding neighbor chunks
- */
- private void checkLightAsync(List neighbors) {
- this.isTerrainPopulated = true;
- this.isLightPopulated = true;
- BlockPosition blockpos = new BlockPosition(this.locX << 4, 0, this.locZ << 4);
-
- if (this.world.worldProvider.m()) { // OBFHELPER: hasSkyLight
- CHECK_LIGHT:
- for (int i = 0; i < 16; ++i) {
- for (int j = 0; j < 16; ++j) {
- if (!this.checkLightAsync(i, j, neighbors)) {
- this.isLightPopulated = false;
- break CHECK_LIGHT;
- }
- }
- }
-
- if (this.isLightPopulated) {
- for (EnumDirection enumfacing : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
- int k = enumfacing.c() == EnumDirection.EnumAxisDirection.POSITIVE ? 16 : 1; // OBFHELPER: getAxisDirection
- final BlockPosition pos = blockpos.shift(enumfacing, k);
- final Chunk chunk = this.getLightChunk(pos.getX() >> 4, pos.getZ() >> 4, neighbors);
- if (chunk == null) {
- continue;
- }
- chunk.a(enumfacing.opposite()); // OBFHELPER: checkLightSide
- }
-
- for (int i = 0; i < this.updateSkylightColumns.length; ++i) {
- this.updateSkylightColumns[i] = true;
- }
-
- this.recheckGapsAsync(neighbors);
- }
- }
- }
-
- /**
- * Checks light async.
- *
- * @param x The x position of chunk
- * @param z The z position of chunk
- * @param neighbors A thread-safe list of surrounding neighbor chunks
- * @return True if light update was successful, false if not
- */
- private boolean checkLightAsync(int x, int z, List neighbors) {
- int i = this.getTopFilledSegment();
- boolean flag = false;
- boolean flag1 = false;
- MutableBlockPosition blockpos$mutableblockpos = new MutableBlockPosition((this.locX << 4) + x, 0, (this.locZ << 4) + z);
-
- for (int j = i + 16 - 1; j > this.world.getSeaLevel() || j > 0 && !flag1; --j) {
- blockpos$mutableblockpos.setValues(blockpos$mutableblockpos.getX(), j, blockpos$mutableblockpos.getZ());
- int k = this.getBlockData(blockpos$mutableblockpos).c(); // OBFHELPER: getLightOpacity
-
- if (k == 255 && blockpos$mutableblockpos.getY() < this.world.getSeaLevel()) {
- flag1 = true;
- }
-
- if (!flag && k > 0) {
- flag = true;
- } else if (flag && k == 0 && !this.checkWorldLight(blockpos$mutableblockpos, neighbors)) {
- return false;
- }
- }
-
- for (int l = blockpos$mutableblockpos.getY(); l > 0; --l) {
- blockpos$mutableblockpos.setValues(blockpos$mutableblockpos.getX(), l, blockpos$mutableblockpos.getZ());
-
- if (this.getBlockData(blockpos$mutableblockpos).d() > 0) { // getLightValue
- this.checkWorldLight(blockpos$mutableblockpos, neighbors);
- }
- }
-
- return true;
- }
-
- /**
- * Thread-safe method to retrieve a chunk during async light updates.
- *
- * @param chunkX The x position of chunk.
- * @param chunkZ The z position of chunk.
- * @param neighbors A thread-safe list of surrounding neighbor chunks
- * @return The chunk if available, null if not
- */
- private Chunk getLightChunk(int chunkX, int chunkZ, List neighbors) {
- final Chunk currentChunk = (Chunk) (Object) this;
- if (currentChunk.a(chunkX, chunkZ)) { // OBFHELPER: isAtLocation
- if (currentChunk.isUnloading()) {
- return null;
- }
- return currentChunk;
- }
- if (neighbors == null) {
- neighbors = this.getSurroundingChunks();
- if (neighbors.isEmpty()) {
- return null;
- }
- }
- for (Chunk neighbor : neighbors) {
- if (neighbor.a(chunkX, chunkZ)) { // OBFHELPER: isAtLocation
- if (neighbor.isUnloading()) {
- return null;
- }
- return neighbor;
- }
- }
-
- return null;
- }
-
- /**
- * Checks if surrounding chunks are loaded thread-safe.
- *
- * @return True if surrounded chunks are loaded, false if not
- */
- private boolean isAreaLoaded() {
- if (!this.areNeighborsLoaded()) {
- return false;
- }
-
- // add diagonal chunks
- final Chunk southEastChunk = ((IMixinChunk) this.getNeighborChunk(0)).getNeighborChunk(2);
- if (southEastChunk == null) {
- return false;
- }
-
- final Chunk southWestChunk = ((IMixinChunk) this.getNeighborChunk(0)).getNeighborChunk(3);
- if (southWestChunk == null) {
- return false;
- }
-
- final Chunk northEastChunk = ((IMixinChunk) this.getNeighborChunk(1)).getNeighborChunk(2);
- if (northEastChunk == null) {
- return false;
- }
-
- final Chunk northWestChunk = ((IMixinChunk) this.getNeighborChunk(1)).getNeighborChunk(3);
- if (northWestChunk == null) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Gets surrounding chunks thread-safe.
- *
- * @return The list of surrounding chunks, empty list if not loaded
- */
- private List getSurroundingChunks() {
- if (!this.areNeighborsLoaded()) {
- return Collections.emptyList();
- }
-
- // add diagonal chunks
- final Chunk southEastChunk = ((IMixinChunk) this.getNeighborChunk(0)).getNeighborChunk(2);
- if (southEastChunk == null) {
- return Collections.emptyList();
- }
-
- final Chunk southWestChunk = ((IMixinChunk) this.getNeighborChunk(0)).getNeighborChunk(3);
- if (southWestChunk == null) {
- return Collections.emptyList();
- }
-
- final Chunk northEastChunk = ((IMixinChunk) this.getNeighborChunk(1)).getNeighborChunk(2);
- if (northEastChunk == null) {
- return Collections.emptyList();
- }
-
- final Chunk northWestChunk = ((IMixinChunk) this.getNeighborChunk(1)).getNeighborChunk(3);
- if (northWestChunk == null) {
- return Collections.emptyList();
- }
-
- List chunkList = this.getNeighbors();
- chunkList.add(southEastChunk);
- chunkList.add(southWestChunk);
- chunkList.add(northEastChunk);
- chunkList.add(northWestChunk);
- return chunkList;
- }
-
- @Inject(method = "c(III)V", at = @At("HEAD"), cancellable = true)
- private void onRelightBlock(int x, int y, int z, CallbackInfo ci) {
- lightExecutorService.execute(() -> {
- this.relightBlockAsync(x, y, z);
- });
- ci.cancel();
- }
-
- /**
- * Relight's a block async.
- *
- * @param x The x position
- * @param y The y position
- * @param z The z position
- */
- private void relightBlockAsync(int x, int y, int z) {
- int i = this.heightMap[z << 4 | x] & 255;
- int j = i;
-
- if (y > i) {
- j = y;
- }
-
- while (j > 0 && this.getBlockData(x, j - 1, z).c() == 0) { // OBFHELPER: getLightOpacity
- --j;
- }
-
- if (j != i) {
- this.markBlocksDirtyVerticalAsync(x + this.locX * 16, z + this.locZ * 16, j, i);
- this.heightMap[z << 4 | x] = j;
- int k = this.locX * 16 + x;
- int l = this.locZ * 16 + z;
-
- if (this.world.worldProvider.m()) { // OBFHELPER: hasSkyLight
- if (j < i) {
- for (int j1 = j; j1 < i; ++j1) {
- ChunkSection extendedblockstorage2 = this.sections[j1 >> 4];
-
- if (extendedblockstorage2 != Chunk.EMPTY_CHUNK_SECTION) {
- extendedblockstorage2.a(x, j1 & 15, z, 15); // OBFHELPER: setSkyLight
- // this.world.m(new BlockPosition((this.locX << 4) + x, j1, (this.locZ << 4) + z)); // OBFHELPER: notifyLightSet - client side
- }
- }
- } else {
- for (int i1 = i; i1 < j; ++i1) {
- ChunkSection extendedblockstorage = this.sections[i1 >> 4];
-
- if (extendedblockstorage != Chunk.EMPTY_CHUNK_SECTION) {
- extendedblockstorage.a(x, i1 & 15, z, 0); // OBFHELPER: setSkyLight
- // this.world.m(new BlockPosition((this.locX << 4) + x, i1, (this.locZ << 4) + z)); // OBFHELPER: notifyLightSet - client side
- }
- }
- }
-
- int k1 = 15;
-
- while (j > 0 && k1 > 0) {
- --j;
- int i2 = this.getBlockData(x, j, z).c();
-
- if (i2 == 0) {
- i2 = 1;
- }
-
- k1 -= i2;
-
- if (k1 < 0) {
- k1 = 0;
- }
-
- ChunkSection extendedblockstorage1 = this.sections[j >> 4];
-
- if (extendedblockstorage1 != Chunk.EMPTY_CHUNK_SECTION) {
- extendedblockstorage1.a(x, j & 15, z, k1); // OBFHELPER: setSkyLight
- }
- }
- }
-
- int l1 = this.heightMap[z << 4 | x];
- int j2 = i;
- int k2 = l1;
-
- if (l1 < i) {
- j2 = l1;
- k2 = i;
- }
-
- if (l1 < this.heightMapMinimum) {
- this.heightMapMinimum = l1;
- }
-
- if (this.world.worldProvider.m()) { // OBFHELPER: hasSkyLight
- for (EnumDirection enumfacing : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
- this.updateSkylightNeighborHeight(k + enumfacing.getAdjacentX(), l + enumfacing.getAdjacentZ(), j2, k2); // OBFHELPER: updateSkylightNeighborHeight
- }
-
- this.updateSkylightNeighborHeight(k, l, j2, k2);
- }
-
- this.markDirty();
- }
- }
-
- /**
- * Marks a vertical line of blocks as dirty async.
- * Instead of calling world directly, we pass chunk safely for async light method.
- *
- * @param x1
- * @param z1
- * @param x2
- * @param z2
- */
- private void markBlocksDirtyVerticalAsync(int x1, int z1, int x2, int z2) {
- if (x2 > z2) {
- int i = z2;
- z2 = x2;
- x2 = i;
- }
-
- if (this.world.worldProvider.m()) { // OBFHELPER: hasSkyLight
- for (int j = x2; j <= z2; ++j) {
- final BlockPosition pos = new BlockPosition(x1, j, z1);
- final Chunk chunk = this.getLightChunk(pos.getX() >> 4, pos.getZ() >> 4, null);
- if (chunk == null) {
- continue;
- }
- ((IMixinWorldServer) this.world).updateLightAsync(EnumSkyBlock.SKY, new BlockPosition(x1, j, z1), chunk);
- }
- }
-
- this.world.b(x1, x2, z1, x1, z2, z1); // OBFHELPER: markBlockRangeForRenderUpdate
- }
-
- /**
- * Checks world light thread-safe.
- *
- * @param lightType The type of light to check
- * @param pos The block position
- * @return True if light update was successful, false if not
- */
- private boolean checkWorldLightFor(EnumSkyBlock lightType, BlockPosition pos) {
- final Chunk chunk = this.getLightChunk(pos.getX() >> 4, pos.getZ() >> 4, null);
- if (chunk == null) {
- return false;
- }
-
- return ((IMixinWorldServer) this.world).updateLightAsync(lightType, pos, chunk);
- }
-
- private boolean checkWorldLight(BlockPosition pos) {
- return this.checkWorldLight(pos, null);
- }
-
- /**
- * Checks world light async.
- *
- * @param pos The block position
- * @param neighbors A thread-safe list of surrounding neighbor chunks
- * @return True if light update was successful, false if not
- */
- private boolean checkWorldLight(BlockPosition pos, List neighbors) {
- boolean flag = false;
- final Chunk chunk = this.getLightChunk(pos.getX() >> 4, pos.getZ() >> 4, neighbors);
- if (chunk == null) {
- return false;
- }
-
- if (this.world.worldProvider.m()) { // OBFHELPER: hasSkyLight
- flag |= ((IMixinWorldServer) this.world).updateLightAsync(EnumSkyBlock.SKY, pos, chunk);
- }
-
- flag = flag | ((IMixinWorldServer) this.world).updateLightAsync(EnumSkyBlock.BLOCK, pos, chunk);
- return flag;
- }
-
- /**
- * Gets the list of block positions currently queued for lighting updates.
- *
- * @param type The light type
- * @return The list of queued block positions, empty if none
- */
- @Override
- public CopyOnWriteArrayList getQueuedLightingUpdates(EnumSkyBlock type) {
- if (type == EnumSkyBlock.SKY) {
- return this.queuedSkyLightingUpdates;
- }
- return this.queuedBlockLightingUpdates;
- }
-}
diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunkProviderServer.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunkProviderServer.java
deleted file mode 100644
index aa384fcba..000000000
--- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunkProviderServer.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This file is part of Sponge, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) 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.akarin.server.mixin.lighting;
-
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.Redirect;
-
-import io.akarin.api.internal.mixin.IMixinChunk;
-import net.minecraft.server.ChunkProviderServer;
-import net.minecraft.server.WorldServer;
-
-@Mixin(value = ChunkProviderServer.class, remap = false, priority = 1001)
-public abstract class MixinChunkProviderServer {
- @Shadow @Final public WorldServer world;
-
- @Redirect(method = "unloadChunks", at = @At(
- value = "INVOKE",
- target = "Lnet/minecraft/server/Chunk;isUnloading()Z"
- ))
- public boolean shouldUnload(IMixinChunk chunk) {
- if (chunk.getPendingLightUpdates().get() > 0 || this.world.getTime() - chunk.getLightUpdateTime() < 20) {
- return false;
- }
- return true;
- }
-}
diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorld.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorld.java
deleted file mode 100644
index d09d94a33..000000000
--- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorld.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is part of Sponge, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) 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.akarin.server.mixin.lighting;
-
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import net.minecraft.server.BlockPosition;
-import net.minecraft.server.Chunk;
-import net.minecraft.server.EnumSkyBlock;
-import net.minecraft.server.IChunkProvider;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.World;
-
-@Mixin(value = World.class, remap = false, priority = 1002)
-public abstract class MixinWorld {
- @Shadow protected IChunkProvider chunkProvider;
- @Shadow int[] J; // OBFHELPER: lightUpdateBlockList
-
- @Shadow(aliases = "c") public abstract boolean checkLightFor(EnumSkyBlock lightType, BlockPosition pos);
- @Shadow public abstract MinecraftServer getMinecraftServer();
- @Shadow public abstract boolean areChunksLoaded(BlockPosition center, int radius, boolean allowEmpty);
- @Shadow public abstract Chunk getChunkIfLoaded(int x, int z);
-}
diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java
deleted file mode 100644
index 8461839a3..000000000
--- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * This file is part of Sponge, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) 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.akarin.server.mixin.lighting;
-
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import javax.annotation.Nullable;
-
-import org.spongepowered.asm.mixin.Mixin;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-
-import io.akarin.api.internal.Akari;
-import io.akarin.api.internal.mixin.IMixinChunk;
-import io.akarin.api.internal.mixin.IMixinWorldServer;
-import io.akarin.server.core.AkarinGlobalConfig;
-import net.minecraft.server.BlockPosition;
-import net.minecraft.server.Chunk;
-import net.minecraft.server.EnumDirection;
-import net.minecraft.server.EnumSkyBlock;
-import net.minecraft.server.IBlockData;
-import net.minecraft.server.MCUtil;
-import net.minecraft.server.MathHelper;
-import net.minecraft.server.WorldServer;
-import net.minecraft.server.BlockPosition.PooledBlockPosition;
-
-@Mixin(value = WorldServer.class, remap = false, priority = 1002)
-public abstract class MixinWorldServer extends MixinWorld implements IMixinWorldServer {
-
- private static final int NUM_XZ_BITS = 4;
- private static final int NUM_SHORT_Y_BITS = 8;
- private static final short XZ_MASK = 0xF;
- private static final short Y_SHORT_MASK = 0xFF;
-
- private final static ExecutorService lightExecutorService = getExecutorService();
- private static ExecutorService getExecutorService() {
- return AkarinGlobalConfig.asyncLightingWorkStealing ?
- Executors.newFixedThreadPool(AkarinGlobalConfig.asyncLightingThreads, new ThreadFactoryBuilder().setNameFormat("Akarin Async Light Thread").build())
- :
- Executors.newWorkStealingPool(AkarinGlobalConfig.asyncLightingThreads);
- }
-
- @Override
- public boolean checkLightFor(EnumSkyBlock lightType, BlockPosition pos) { // OBFHELPER: checkLightFor
- return updateLightAsync(lightType, pos, null);
- }
-
- @Override
- public boolean checkLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List neighbors) {
- // Sponge - This check is not needed as neighbors are checked in updateLightAsync
- if (false && !this.areChunksLoaded(pos, 17, false)) {
- return false;
- } else {
- final IMixinChunk spongeChunk = (IMixinChunk) currentChunk;
- int recheckIndex = 0;
- int blockIndex = 0;
- int current = this.getLightForAsync(lightType, pos, currentChunk, neighbors); // Sponge - use thread safe method
- int rawLight = this.getRawBlockLightAsync(lightType, pos, currentChunk, neighbors); // Sponge - use thread safe method
- int x = pos.getX();
- int y = pos.getY();
- int z = pos.getZ();
-
- if (rawLight > current) {
- this.J[blockIndex++] = 133152; // OBFHELPER: lightUpdateBlockList
- } else if (rawLight < current) {
- this.J[blockIndex++] = 133152 | current << 18; // OBFHELPER: lightUpdateBlockList
-
- while (recheckIndex < blockIndex) {
- int blockData = this.J[recheckIndex++]; // OBFHELPER: lightUpdateBlockList
- int i2 = (blockData & 63) - 32 + x;
- int j2 = (blockData >> 6 & 63) - 32 + y;
- int k2 = (blockData >> 12 & 63) - 32 + z;
- int l2 = blockData >> 18 & 15;
- BlockPosition blockpos = new BlockPosition(i2, j2, k2);
- int lightLevel = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors); // Sponge - use thread safe method
-
- if (lightLevel == l2) {
- this.setLightForAsync(lightType, blockpos, 0, currentChunk, neighbors); // Sponge - use thread safe method
-
- if (l2 > 0) {
- int j3 = MathHelper.a(i2 - x); // abs
- int k3 = MathHelper.a(j2 - y);
- int l3 = MathHelper.a(k2 - z);
-
- if (j3 + k3 + l3 < 17) {
- PooledBlockPosition mutableBlockpos = PooledBlockPosition.aquire();
-
- for (EnumDirection enumfacing : EnumDirection.values()) {
- int i4 = i2 + enumfacing.getAdjacentX();
- int j4 = j2 + enumfacing.getAdjacentX();
- int k4 = k2 + enumfacing.getAdjacentX();
- mutableBlockpos.setValues(i4, j4, k4);
- // Sponge start - get chunk safely
- final Chunk pooledChunk = this.getLightChunk(mutableBlockpos, currentChunk, neighbors);
- if (pooledChunk == null) {
- continue;
- }
- int opacity = Math.max(1, pooledChunk.getBlockData(mutableBlockpos).c()); // OBFHELPER: getLightOpacity
- lightLevel = this.getLightForAsync(lightType, mutableBlockpos, currentChunk, neighbors);
- // Sponge end
-
- if (lightLevel == l2 - opacity && blockIndex < this.J.length) { // OBFHELPER: lightUpdateBlockList
- this.J[blockIndex++] = i4 - x + 32 | j4 - y + 32 << 6 | k4 - z + 32 << 12 | l2 - opacity << 18; // OBFHELPER: lightUpdateBlockList
- }
- }
-
- mutableBlockpos.free();
- }
- }
- }
- }
-
- recheckIndex = 0;
- }
-
- while (recheckIndex < blockIndex) {
- int i5 = this.J[recheckIndex++]; // OBFHELPER: lightUpdateBlockList
- int j5 = (i5 & 63) - 32 + x;
- int k5 = (i5 >> 6 & 63) - 32 + y;
- int l5 = (i5 >> 12 & 63) - 32 + z;
- BlockPosition blockpos1 = new BlockPosition(j5, k5, l5);
- int i6 = this.getLightForAsync(lightType, blockpos1, currentChunk, neighbors); // Sponge - use thread safe method
- int j6 = this.getRawBlockLightAsync(lightType, blockpos1, currentChunk, neighbors); // Sponge - use thread safe method
-
- if (j6 != i6) {
- this.setLightForAsync(lightType, blockpos1, j6, currentChunk, neighbors); // Sponge - use thread safe method
-
- if (j6 > i6) {
- int k6 = Math.abs(j5 - x);
- int l6 = Math.abs(k5 - y);
- int i7 = Math.abs(l5 - z);
- boolean flag = blockIndex < this.J.length - 6; // OBFHELPER: lightUpdateBlockList
-
- if (k6 + l6 + i7 < 17 && flag) {
- // Sponge start - use thread safe method getLightForAsync
- if (this.getLightForAsync(lightType, blockpos1.west(), currentChunk, neighbors) < j6) {
- this.J[blockIndex++] = j5 - 1 - x + 32 + (k5 - y + 32 << 6) + (l5 - z + 32 << 12); // OBFHELPER: lightUpdateBlockList
- }
-
- if (this.getLightForAsync(lightType, blockpos1.east(), currentChunk, neighbors) < j6) {
- this.J[blockIndex++] = j5 + 1 - x + 32 + (k5 - y + 32 << 6) + (l5 - z + 32 << 12); // OBFHELPER: lightUpdateBlockList
- }
-
- if (this.getLightForAsync(lightType, blockpos1.down(), currentChunk, neighbors) < j6) {
- this.J[blockIndex++] = j5 - x + 32 + (k5 - 1 - y + 32 << 6) + (l5 - z + 32 << 12); // OBFHELPER: lightUpdateBlockList
- }
-
- if (this.getLightForAsync(lightType, blockpos1.up(), currentChunk, neighbors) < j6) {
- this.J[blockIndex++] = j5 - x + 32 + (k5 + 1 - y + 32 << 6) + (l5 - z + 32 << 12); // OBFHELPER: lightUpdateBlockList
- }
-
- if (this.getLightForAsync(lightType, blockpos1.north(), currentChunk, neighbors) < j6) {
- this.J[blockIndex++] = j5 - x + 32 + (k5 - y + 32 << 6) + (l5 - 1 - z + 32 << 12); // OBFHELPER: lightUpdateBlockList
- }
-
- if (this.getLightForAsync(lightType, blockpos1.south(), currentChunk, neighbors) < j6) {
- this.J[blockIndex++] = j5 - x + 32 + (k5 - y + 32 << 6) + (l5 + 1 - z + 32 << 12); // OBFHELPER: lightUpdateBlockList
- }
- // Sponge end
- }
- }
- }
- }
-
- // Sponge start - Asynchronous light updates
- spongeChunk.getQueuedLightingUpdates(lightType).remove((Short) this.blockPosToShort(pos));
- spongeChunk.getPendingLightUpdates().decrementAndGet();
- for (Chunk neighborChunk : neighbors) {
- final IMixinChunk neighbor = (IMixinChunk) neighborChunk;
- neighbor.getPendingLightUpdates().decrementAndGet();
- }
- // Sponge end
- return true;
- }
- }
-
- @Override
- public boolean updateLightAsync(EnumSkyBlock lightType, BlockPosition pos, @Nullable Chunk currentChunk) {
- if (this.getMinecraftServer().isStopped() || lightExecutorService.isShutdown()) {
- return false;
- }
-
- if (currentChunk == null) {
- if (!Akari.isPrimaryThread()) return false;
- currentChunk = MCUtil.getLoadedChunkWithoutMarkingActive(chunkProvider, pos.getX() >> 4, pos.getZ() >> 4);
- }
-
- final IMixinChunk spongeChunk = (IMixinChunk) currentChunk;
- if (currentChunk == null || currentChunk.isUnloading() || !spongeChunk.areNeighborsLoaded()) {
- return false;
- }
-
- final short shortPos = this.blockPosToShort(pos);
- if (spongeChunk.getQueuedLightingUpdates(lightType).contains(shortPos)) {
- return false;
- }
-
- final Chunk chunk = currentChunk;
- spongeChunk.getQueuedLightingUpdates(lightType).add(shortPos);
- spongeChunk.getPendingLightUpdates().incrementAndGet();
- spongeChunk.setLightUpdateTime(chunk.getWorld().getTime());
-
- List neighbors = spongeChunk.getNeighbors();
- // add diagonal chunks
- Chunk southEastChunk = ((IMixinChunk) spongeChunk.getNeighborChunk(0)).getNeighborChunk(2);
- Chunk southWestChunk = ((IMixinChunk) spongeChunk.getNeighborChunk(0)).getNeighborChunk(3);
- Chunk northEastChunk = ((IMixinChunk) spongeChunk.getNeighborChunk(1)).getNeighborChunk(2);
- Chunk northWestChunk = ((IMixinChunk) spongeChunk.getNeighborChunk(1)).getNeighborChunk(3);
- if (southEastChunk != null) {
- neighbors.add(southEastChunk);
- }
- if (southWestChunk != null) {
- neighbors.add(southWestChunk);
- }
- if (northEastChunk != null) {
- neighbors.add(northEastChunk);
- }
- if (northWestChunk != null) {
- neighbors.add(northWestChunk);
- }
-
- for (Chunk neighborChunk : neighbors) {
- final IMixinChunk neighbor = (IMixinChunk) neighborChunk;
- neighbor.getPendingLightUpdates().incrementAndGet();
- neighbor.setLightUpdateTime(chunk.getWorld().getTime());
- }
-
- if (Akari.isPrimaryThread()) { // Akarin
- lightExecutorService.execute(() -> {
- this.checkLightAsync(lightType, pos, chunk, neighbors);
- });
- } else {
- this.checkLightAsync(lightType, pos, chunk, neighbors);
- }
-
- return true;
- }
-
- @Override
- public ExecutorService getLightingExecutor() {
- return lightExecutorService;
- }
-
- // Thread safe methods to retrieve a chunk during async light updates
- // Each method avoids calling getLoadedChunk and instead accesses the passed neighbor chunk list to avoid concurrency issues
- public Chunk getLightChunk(BlockPosition pos, Chunk currentChunk, List neighbors) {
- if (currentChunk.a(pos.getX() >> 4, pos.getZ() >> 4)) { // OBFHELPER: isAtLocation
- if (currentChunk.isUnloading()) {
- return null;
- }
- return currentChunk;
- }
- for (Chunk neighbor : neighbors) {
- if (neighbor.a(pos.getX() >> 4, pos.getZ() >> 4)) { // OBFHELPER: isAtLocation
- if (neighbor.isUnloading()) {
- return null;
- }
- return neighbor;
- }
- }
-
- return null;
- }
-
- private int getLightForAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List neighbors) {
- if (pos.getY() < 0) {
- pos = new BlockPosition(pos.getX(), 0, pos.getZ());
- }
- if (!pos.isValidLocation()) {
- return lightType.c; // OBFHELPER: defaultLightValue
- }
-
- final Chunk chunk = this.getLightChunk(pos, currentChunk, neighbors);
- if (chunk == null || chunk.isUnloading()) {
- return lightType.c; // OBFHELPER: defaultLightValue
- }
-
- return chunk.getBrightness(lightType, pos);
- }
-
- private int getRawBlockLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List neighbors) {
- final Chunk chunk = getLightChunk(pos, currentChunk, neighbors);
- if (chunk == null || chunk.isUnloading()) {
- return lightType.c; // OBFHELPER: defaultLightValue
- }
- if (lightType == EnumSkyBlock.SKY && chunk.c(pos)) { // OBFHELPER: canSeeSky
- return 15;
- } else {
- IBlockData blockData = chunk.getBlockData(pos);
- int blockLight = blockData.d(); // getLightValue
- int rawLight = lightType == EnumSkyBlock.SKY ? 0 : blockLight;
- int opacity = blockData.c(); // OBFHELPER: getLightOpacity
-
- if (opacity >= 15 && blockLight > 0) {
- opacity = 1;
- }
-
- if (opacity < 1) {
- opacity = 1;
- }
-
- if (opacity >= 15) {
- return 0;
- } else if (rawLight >= 14) {
- return rawLight;
- } else {
- for (EnumDirection facing : EnumDirection.values()) {
- BlockPosition blockpos = pos.shift(facing);
- int current = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors) - opacity;
-
- if (current > rawLight) {
- rawLight = current;
- }
-
- if (rawLight >= 14) {
- return rawLight;
- }
- }
-
- return rawLight;
- }
- }
- }
-
- public void setLightForAsync(EnumSkyBlock type, BlockPosition pos, int lightValue, Chunk currentChunk, List neighbors) {
- if (pos.isValidLocation()) {
- final Chunk chunk = this.getLightChunk(pos, currentChunk, neighbors);
- if (chunk != null && !chunk.isUnloading()) {
- chunk.a(type, pos, lightValue); // OBFHELPER: setLightFor
- // this.notifyLightSet(pos); // client side
- }
- }
- }
-
- private short blockPosToShort(BlockPosition pos) {
- short serialized = (short) setNibble(0, pos.getX() & XZ_MASK, 0, NUM_XZ_BITS);
- serialized = (short) setNibble(serialized, pos.getY() & Y_SHORT_MASK, 1, NUM_SHORT_Y_BITS);
- serialized = (short) setNibble(serialized, pos.getZ() & XZ_MASK, 3, NUM_XZ_BITS);
- return serialized;
- }
-
- /**
- * Modifies bits in an integer.
- *
- * @param num Integer to modify
- * @param data Bits of data to add
- * @param which Index of nibble to start at
- * @param bitsToReplace The number of bits to replace starting from nibble index
- * @return The modified integer
- */
- private int setNibble(int num, int data, int which, int bitsToReplace) {
- return (num & ~(bitsToReplace << (which * 4)) | (data << (which * 4)));
- }
-}
diff --git a/sources/src/main/resources/mixins.akarin.optimization.lighting.json b/sources/src/main/resources/mixins.akarin.optimization.lighting.json
deleted file mode 100644
index 28cc496c4..000000000
--- a/sources/src/main/resources/mixins.akarin.optimization.lighting.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "required": true,
- "minVersion": "0.7.10",
- "package": "io.akarin.server.mixin",
- "target": "@env(DEFAULT)",
- "compatibilityLevel": "JAVA_8",
- "server": [
- "cps.MixinChunk",
-
- "lighting.MixinChunk",
- "lighting.MixinWorld",
- "lighting.MixinWorldServer",
- "lighting.MixinChunkProviderServer",
- ]
-}
\ No newline at end of file