Skip to content

Commit

Permalink
Merge branch '1.20.1' into 1.20.2
Browse files Browse the repository at this point in the history
  • Loading branch information
rfresh2 committed Feb 1, 2025
2 parents 673b0ee + 685ba6e commit e955e46
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 54 deletions.
13 changes: 11 additions & 2 deletions common/src/main/java/xaeroplus/event/ChunkBlockUpdateEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@

import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;

// fired right before block update is applied to mc.level
public record ChunkBlockUpdateEvent(ClientboundBlockUpdatePacket packet) { }
public class ChunkBlockUpdateEvent extends PhasedEvent {
private final ClientboundBlockUpdatePacket packet;

public ChunkBlockUpdateEvent(final ClientboundBlockUpdatePacket packet) {
this.packet = packet;
}

public ClientboundBlockUpdatePacket packet() {
return packet;
}
}
13 changes: 11 additions & 2 deletions common/src/main/java/xaeroplus/event/ChunkBlocksUpdateEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@

import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;

// fired right before block updates are applied to mc.level
public record ChunkBlocksUpdateEvent(ClientboundSectionBlocksUpdatePacket packet) { }
public class ChunkBlocksUpdateEvent extends PhasedEvent {
private final ClientboundSectionBlocksUpdatePacket packet;

public ChunkBlocksUpdateEvent(final ClientboundSectionBlocksUpdatePacket packet) {
this.packet = packet;
}

public ClientboundSectionBlocksUpdatePacket packet() {
return packet;
}
}
6 changes: 6 additions & 0 deletions common/src/main/java/xaeroplus/event/Phase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package xaeroplus.event;

public enum Phase {
PRE,
POST
}
13 changes: 13 additions & 0 deletions common/src/main/java/xaeroplus/event/PhasedEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package xaeroplus.event;

public abstract class PhasedEvent {
private Phase phase = Phase.PRE;

public Phase phase() {
return phase;
}

public void setPhase(Phase phase) {
this.phase = phase;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public LineDrawFeature(LineProvider lineProvider, int refreshIntervalMs) {
this.lineRenderCache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
.refreshAfterWrite(refreshIntervalMs, TimeUnit.MILLISECONDS)
.executor(Globals.cacheRefreshExecutorService.get())
.buildAsync(k -> loadLinesInWindow());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import xaeroplus.XaeroPlus;
import xaeroplus.util.ChunkUtils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.StampedLock;
Expand All @@ -18,9 +19,11 @@
public abstract class ChunkHighlightBaseCacheHandler implements ChunkHighlightCache {
public final ReadWriteLock lock = new StampedLock().asReadWriteLock();
public final Long2LongMap chunks = new Long2LongOpenHashMap();
private final ExecutorService queuedWriteExecutor;

public ChunkHighlightBaseCacheHandler() {
chunks.defaultReturnValue(-1);
public ChunkHighlightBaseCacheHandler(ExecutorService queuedWriteExecutor) {
this.queuedWriteExecutor = queuedWriteExecutor;
this.chunks.defaultReturnValue(-1);
}

@Override
Expand All @@ -31,30 +34,72 @@ public boolean addHighlight(final int x, final int z) {
public boolean addHighlight(final int x, final int z, final long foundTime) {
final long chunkPos = chunkPosToLong(x, z);
try {
if (lock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
if (lock.writeLock().tryLock()) {
chunks.put(chunkPos, foundTime);
lock.writeLock().unlock();
} else {
try {
queuedWriteExecutor.execute(() -> addQueuedHighlight(x, z, foundTime));
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to submit new queued highlight write: {}, {}", x, z, e);
}
}
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to add new highlight: {}, {}", x, z, e);
}
return true;
}

private void addQueuedHighlight(final int x, final int z, final long foundTime) {
final long chunkPos = chunkPosToLong(x, z);
try {
if (lock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
chunks.put(chunkPos, foundTime);
lock.writeLock().unlock();
} else {
XaeroPlus.LOGGER.error("Failed to add new queued highlight: timed out: {}, {}", x, z);
}
} catch (InterruptedException e) {
XaeroPlus.LOGGER.debug("Thread interrupted while adding new queued highlight: {}, {}", x, z, e);
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to add new highlight: {}, {}", x, z, e);
}
}

@Override
public boolean removeHighlight(final int x, final int z) {
final long chunkPos = chunkPosToLong(x, z);
try {
if (lock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
if (lock.writeLock().tryLock()) {
chunks.remove(chunkPos);
lock.writeLock().unlock();
} else {
try {
queuedWriteExecutor.execute(() -> removeQueuedHighlight(x, z));
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to submit new queued highlight remove: {}, {}", x, z, e);
}
}
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to add new highlight: {}, {}", x, z, e);
}
return true;
}

private void removeQueuedHighlight(final int x, final int z) {
final long chunkPos = chunkPosToLong(x, z);
try {
if (lock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
chunks.remove(chunkPos);
lock.writeLock().unlock();
} else {
XaeroPlus.LOGGER.error("Failed to remove queued highlight: timed out: {}, {}", x, z);
}
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to remove queued highlight: {}, {}", x, z, e);
}
}

@Override
public boolean isHighlighted(final int x, final int z, ResourceKey<Level> dimensionId) {
return isHighlighted(chunkPosToLong(x, z));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public ChunkHighlightCacheDimensionHandler(
@NotNull ResourceKey<Level> dimension,
@NotNull ChunkHighlightDatabase database,
@NotNull ListeningExecutorService executorService) {
super(executorService);
this.dimension = dimension;
this.database = database;
this.executorService = executorService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
import xaeroplus.event.XaeroWorldChangeEvent;

import java.util.Map;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;

public class ChunkHighlightLocalCache extends ChunkHighlightBaseCacheHandler {
private static final int maxNumber = 5000;

public ChunkHighlightLocalCache() {
super(ForkJoinPool.commonPool());
}

@Override
public boolean addHighlight(final int x, final int z) {
limitChunksSize();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
package xaeroplus.mixin.client.mc;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkStatus;
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 xaeroplus.XaeroPlus;
import xaeroplus.event.ChunkBlockUpdateEvent;
import xaeroplus.event.ChunkBlocksUpdateEvent;
import xaeroplus.event.ChunkDataEvent;
import xaeroplus.event.ClientPlaySessionFinalizedEvent;
import xaeroplus.event.*;

import java.util.function.BiConsumer;

@Mixin(ClientPacketListener.class)
public class MixinClientPlayNetworkHandler {
Expand All @@ -42,20 +46,31 @@ public void onChunkData(
XaeroPlus.EVENT_BUS.call(new ChunkDataEvent(level.getChunk(packet.getX(), packet.getZ()), seenChunkRef.get()));
}

@Inject(method = "handleChunkBlocksUpdate", at = @At(
@WrapOperation(method = "handleChunkBlocksUpdate", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket;runUpdates(Ljava/util/function/BiConsumer;)V"
))
public void onChunkBlocksUpdate(final ClientboundSectionBlocksUpdatePacket packet, final CallbackInfo ci) {
XaeroPlus.EVENT_BUS.call(new ChunkBlocksUpdateEvent(packet));
public void onChunkBlocksUpdate(final ClientboundSectionBlocksUpdatePacket instance, final BiConsumer<BlockPos, BlockState> mutableBlockPos, final Operation<Void> original) {
var event = new ChunkBlocksUpdateEvent(instance);
event.setPhase(Phase.PRE);
XaeroPlus.EVENT_BUS.call(event);
original.call(instance, mutableBlockPos);
event.setPhase(Phase.POST);
XaeroPlus.EVENT_BUS.call(event);
}

@Inject(method = "handleBlockUpdate", at = @At(
@WrapOperation(method = "handleBlockUpdate", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/multiplayer/ClientLevel;setServerVerifiedBlockState(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)V"
))
public void onBlockUpdate(final ClientboundBlockUpdatePacket packet, final CallbackInfo ci) {
XaeroPlus.EVENT_BUS.call(new ChunkBlockUpdateEvent(packet));
public void onBlockUpdate(final ClientLevel instance, final BlockPos pos, final BlockState state, final int flags, final Operation<Void> original,
@Local(argsOnly = true) final ClientboundBlockUpdatePacket packet) {
var event = new ChunkBlockUpdateEvent(packet);
event.setPhase(Phase.PRE);
XaeroPlus.EVENT_BUS.call(event);
original.call(instance, pos, state, flags);
event.setPhase(Phase.POST);
XaeroPlus.EVENT_BUS.call(event);
}

@Inject(method = "close", at = @At(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import xaeroplus.Globals;
import xaeroplus.event.ChunkBlockUpdateEvent;
import xaeroplus.event.ChunkBlocksUpdateEvent;
import xaeroplus.event.ChunkDataEvent;
import xaeroplus.event.XaeroWorldChangeEvent;
import xaeroplus.event.*;
import xaeroplus.feature.render.highlights.SavableHighlightCacheInstance;
import xaeroplus.module.Module;
import xaeroplus.settings.Settings;
Expand Down Expand Up @@ -58,6 +55,7 @@ public void setDiskCache(boolean disk) {

@EventHandler
public void onMultiBlockUpdate(final ChunkBlocksUpdateEvent event) {
if (event.phase() != Phase.PRE) return;
var level = mc.level;
if (level == null || mc.levelRenderer.viewArea == null) return;
event.packet().runUpdates((pos, state) -> {
Expand All @@ -67,6 +65,7 @@ public void onMultiBlockUpdate(final ChunkBlocksUpdateEvent event) {

@EventHandler
public void onBlockUpdate(final ChunkBlockUpdateEvent event) {
if (event.phase() != Phase.PRE) return;
var level = mc.level;
if (level == null || mc.levelRenderer.viewArea == null) return;
handleBlockUpdate(level, event.packet().getPos(), event.packet().getBlockState());
Expand Down
73 changes: 41 additions & 32 deletions common/src/main/java/xaeroplus/module/impl/Portals.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import it.unimi.dsi.fastutil.objects.ReferenceSet;
import net.lenni0451.lambdaevents.EventHandler;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
Expand All @@ -14,7 +15,6 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.EmptyLevelChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import xaeroplus.Globals;
import xaeroplus.event.ChunkBlockUpdateEvent;
import xaeroplus.event.ChunkBlocksUpdateEvent;
Expand Down Expand Up @@ -65,12 +65,48 @@ public void onChunkData(final ChunkDataEvent event) {

@EventHandler
public void onMultiBlockUpdate(final ChunkBlocksUpdateEvent event) {
event.packet().runUpdates(this::handleBlockChange);
switch (event.phase()) {
case PRE -> event.packet().runUpdates(this::handleBlockChange);
case POST -> handleMultiBlockChangePost(event);
}
}

// checking for portal removal
private void handleMultiBlockChangePost(final ChunkBlocksUpdateEvent event) {
ClientLevel level = mc.level;
if (level == null) return;
event.packet().runUpdates(((blockPos, blockState) -> {
if (!blockState.isAir()) return;
int chunkX = ChunkUtils.posToChunkPos(blockPos.getX());
int chunkZ = ChunkUtils.posToChunkPos(blockPos.getZ());
if (!portalsCache.get().isHighlighted(chunkX, chunkZ, ChunkUtils.getActualDimension())) return;
ChunkAccess chunk = level.getChunkSource().getChunk(chunkX, chunkZ, false);
if (chunk instanceof EmptyLevelChunk || chunk == null) return;
findPortalInChunk(chunk);
}));
}

@EventHandler
public void onBlockUpdate(final ChunkBlockUpdateEvent event) {
handleBlockChange(event.packet().getPos(), event.packet().getBlockState());
switch (event.phase()) {
case PRE -> handleBlockChange(event.packet().getPos(), event.packet().getBlockState());
case POST -> handleBlockChangePost(event);
}
}

// checking for portal removal
private void handleBlockChangePost(final ChunkBlockUpdateEvent event) {
ClientLevel level = mc.level;
if (level == null) return;
var blockPos = event.packet().getPos();
var blockState = event.packet().getBlockState();
if (!blockState.isAir()) return;
int chunkX = ChunkUtils.posToChunkPos(blockPos.getX());
int chunkZ = ChunkUtils.posToChunkPos(blockPos.getZ());
if (!portalsCache.get().isHighlighted(chunkX, chunkZ, ChunkUtils.getActualDimension())) return;
ChunkAccess chunk = level.getChunkSource().getChunk(chunkX, chunkZ, false);
if (chunk instanceof EmptyLevelChunk || chunk == null) return;
findPortalInChunk(chunk);
}

private void findPortalInChunk(final ChunkAccess chunk) {
Expand All @@ -83,16 +119,6 @@ private void findPortalInChunk(final ChunkAccess chunk) {
}
}

private boolean findPortalAtBlockPos(final BlockPos pos) {
if (mc.level == null) return false;
int chunkX = ChunkUtils.posToChunkPos(pos.getX());
int chunkZ = ChunkUtils.posToChunkPos(pos.getZ());
LevelChunk worldChunk = mc.level.getChunkSource().getChunk(chunkX, chunkZ, false);
if (worldChunk == null || worldChunk instanceof EmptyLevelChunk) return false;
BlockState blockState = worldChunk.getBlockState(pos);
return (blockState.getBlock() instanceof NetherPortalBlock || blockState.getBlock() instanceof EndPortalBlock);
}

private void searchAllLoadedChunks() {
if (mc.level == null) return;
final int renderDist = mc.options.renderDistance().get();
Expand All @@ -112,25 +138,8 @@ private void searchAllLoadedChunks() {
private void handleBlockChange(final BlockPos pos, final BlockState state) {
int chunkX = ChunkUtils.posToChunkPos(pos.getX());
int chunkZ = ChunkUtils.posToChunkPos(pos.getZ());
if (portalsCache.get().isHighlighted(chunkX, chunkZ, ChunkUtils.getActualDimension())) {
if (findPortalAtBlockPos(pos)) {
if (mc.level == null || mc.level.getChunkSource() == null) return;
LevelChunk worldChunk = mc.level.getChunkSource().getChunk(chunkX, chunkZ, false);
if (worldChunk != null && !(worldChunk instanceof EmptyLevelChunk)) {
// todo: this isn't guaranteed to search _after_ the block update is processed
Globals.moduleExecutorService.get().execute(() -> {
try {
Thread.sleep(250L);
} catch (InterruptedException e) {
// fall through
}
findPortalInChunk(worldChunk);
});
}
}
} else if (state.getBlock() instanceof NetherPortalBlock || state.getBlock() instanceof EndPortalBlock) {
portalsCache.get().addHighlight(chunkX, chunkZ);
}
if (!(state.getBlock() instanceof NetherPortalBlock || state.getBlock() instanceof EndPortalBlock)) return;
portalsCache.get().addHighlight(chunkX, chunkZ);
}

public int getPortalsColor() {
Expand Down

0 comments on commit e955e46

Please sign in to comment.