Skip to content

Commit

Permalink
Merge branch '1.20.6' into 1.21
Browse files Browse the repository at this point in the history
  • Loading branch information
rfresh2 committed Jan 19, 2025
2 parents 092762a + 1876b23 commit 1fcd566
Show file tree
Hide file tree
Showing 30 changed files with 490 additions and 236 deletions.
1 change: 1 addition & 0 deletions common/src/main/java/xaeroplus/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class Globals {
public static int minimapSizeMultiplier = 1;
public static boolean shouldResetFBO = false;
public static boolean minimapSettingsInitialized = false;
public static boolean switchingDimension = false;
public static ResourceKey<Level> getCurrentDimensionId() {
try {
var dim = XaeroWorldMapCore.currentSession.getMapProcessor().getMapWorld().getCurrentDimensionId();
Expand Down
14 changes: 13 additions & 1 deletion common/src/main/java/xaeroplus/event/XaeroWorldChangeEvent.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
package xaeroplus.event;

public record XaeroWorldChangeEvent(String worldId, String dimId, String mwId) { }
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;

public record XaeroWorldChangeEvent(WorldChangeType worldChangeType, @Nullable ResourceKey<Level> from, @Nullable ResourceKey<Level> to) {
public enum WorldChangeType {
ENTER_WORLD,
EXIT_WORLD,
ACTUAL_DIMENSION_SWITCH,
VIEWED_DIMENSION_SWITCH,
MULTIWORLD_SWITCH
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import it.unimi.dsi.fastutil.longs.LongList;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import xaeroplus.event.XaeroWorldChangeEvent;

public interface ChunkHighlightCache {
boolean addHighlight(final int x, final int z);
boolean removeHighlight(final int x, final int z);
boolean isHighlighted(final int x, final int z, ResourceKey<Level> dimensionId);
LongList getHighlightsSnapshot(ResourceKey<Level> dimensionId);
void handleWorldChange();
void handleWorldChange(final XaeroWorldChangeEvent event);
void handleTick();
void onEnable();
void onDisable();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package xaeroplus.feature.render.highlights;

import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import xaeroplus.XaeroPlus;
import xaeroplus.event.XaeroWorldChangeEvent;
import xaeroplus.util.ChunkUtils;

import java.util.ArrayList;
Expand Down Expand Up @@ -45,87 +47,105 @@ public void setWindow(int regionX, int regionZ, int regionSize) {
}

private void loadHighlightsInWindow() {
executorService.execute(() -> {
final List<ChunkHighlightData> chunks = database.getHighlightsInWindow(
try {
executorService.execute(() -> {
final List<ChunkHighlightData> chunks = database.getHighlightsInWindow(
dimension,
windowRegionX - windowRegionSize, windowRegionX + windowRegionSize,
windowRegionZ - windowRegionSize, windowRegionZ + windowRegionSize
);
try {
if (lock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
for (int i = 0; i < chunks.size(); i++) {
final ChunkHighlightData chunk = chunks.get(i);
this.chunks.put(chunkPosToLong(chunk.x(), chunk.z()), chunk.foundTime());
);
try {
if (lock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
for (int i = 0; i < chunks.size(); i++) {
final ChunkHighlightData chunk = chunks.get(i);
this.chunks.put(chunkPosToLong(chunk.x(), chunk.z()), chunk.foundTime());
}
lock.writeLock().unlock();
}
lock.writeLock().unlock();
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to load highlights in window for {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to load highlights in window for {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
});
});
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed submitting load highlights task for {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
}

private void writeHighlightsOutsideWindowToDatabase() {
executorService.execute(() -> {
final List<ChunkHighlightData> chunksToWrite = new ArrayList<>();
try {
if (lock.writeLock().tryLock(1L, TimeUnit.SECONDS)) {
var minChunkX = regionCoordToChunkCoord(windowRegionX - windowRegionSize);
var maxChunkX = regionCoordToChunkCoord(windowRegionX + windowRegionSize);
var minChunkZ = regionCoordToChunkCoord(windowRegionZ - windowRegionSize);
var maxChunkZ = regionCoordToChunkCoord(windowRegionZ + windowRegionSize);
for (var it = chunks.long2LongEntrySet().iterator(); it.hasNext(); ) {
var entry = it.next();
final long chunkPos = entry.getLongKey();
final int chunkX = ChunkUtils.longToChunkX(chunkPos);
final int chunkZ = ChunkUtils.longToChunkZ(chunkPos);
if (chunkX < minChunkX
try {
executorService.execute(() -> {
final List<ChunkHighlightData> chunksToWrite = new ArrayList<>();
try {
if (lock.writeLock().tryLock(1L, TimeUnit.SECONDS)) {
var minChunkX = regionCoordToChunkCoord(windowRegionX - windowRegionSize);
var maxChunkX = regionCoordToChunkCoord(windowRegionX + windowRegionSize);
var minChunkZ = regionCoordToChunkCoord(windowRegionZ - windowRegionSize);
var maxChunkZ = regionCoordToChunkCoord(windowRegionZ + windowRegionSize);
for (var it = chunks.long2LongEntrySet().iterator(); it.hasNext(); ) {
var entry = it.next();
final long chunkPos = entry.getLongKey();
final int chunkX = ChunkUtils.longToChunkX(chunkPos);
final int chunkZ = ChunkUtils.longToChunkZ(chunkPos);
if (chunkX < minChunkX
|| chunkX > maxChunkX
|| chunkZ < minChunkZ
|| chunkZ > maxChunkZ) {
chunksToWrite.add(new ChunkHighlightData(chunkX, chunkZ, entry.getLongValue()));
it.remove();
chunksToWrite.add(new ChunkHighlightData(chunkX, chunkZ, entry.getLongValue()));
it.remove();
}
}
lock.writeLock().unlock();
}
lock.writeLock().unlock();
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Error while writing highlights outside window to {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Error while writing highlights outside window to {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
database.insertHighlightList(chunksToWrite, dimension);
});
database.insertHighlightList(chunksToWrite, dimension);
});
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed submitting write highlights task for {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
}

public ListenableFuture<?> writeAllHighlightsToDatabase() {
return executorService.submit(() -> {
final List<ChunkHighlightData> chunksToWrite = new ArrayList<>(chunks.size());
try {
if (lock.readLock().tryLock(1, TimeUnit.SECONDS)) {
for (var it = chunks.long2LongEntrySet().iterator(); it.hasNext(); ) {
var entry = it.next();
final long chunkPos = entry.getLongKey();
final int chunkX = ChunkUtils.longToChunkX(chunkPos);
final int chunkZ = ChunkUtils.longToChunkZ(chunkPos);
chunksToWrite.add(new ChunkHighlightData(chunkX, chunkZ, entry.getLongValue()));
try {
return executorService.submit(() -> {
final List<ChunkHighlightData> chunksToWrite = new ArrayList<>(chunks.size());
try {
if (lock.readLock().tryLock(1, TimeUnit.SECONDS)) {
for (var it = chunks.long2LongEntrySet().iterator(); it.hasNext(); ) {
var entry = it.next();
final long chunkPos = entry.getLongKey();
final int chunkX = ChunkUtils.longToChunkX(chunkPos);
final int chunkZ = ChunkUtils.longToChunkZ(chunkPos);
chunksToWrite.add(new ChunkHighlightData(chunkX, chunkZ, entry.getLongValue()));
}
lock.readLock().unlock();
}
lock.readLock().unlock();
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Error while writing all chunks to {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Error while writing all chunks to {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
}
database.insertHighlightList(chunksToWrite, dimension);
});
database.insertHighlightList(chunksToWrite, dimension);
});
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed submitting write all highlights task for {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
return Futures.immediateFuture(null);
}
}

@Override
public boolean removeHighlight(final int x, final int z) {
super.removeHighlight(x, z);
database.removeHighlight(x, z, dimension);
try {
database.removeHighlight(x, z, dimension);
} catch (final Exception e) {
XaeroPlus.LOGGER.error("Failed to remove highlight from {} disk cache dimension: {}", database.databaseName, dimension.location(), e);
return false;
}
return true;
}

@Override
public void handleWorldChange() {}
public void handleWorldChange(final XaeroWorldChangeEvent event) {}

@Override
public void handleTick() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import static xaeroplus.util.ChunkUtils.regionCoordToChunkCoord;

public class ChunkHighlightDatabase implements Closeable {
public static int MAX_HIGHLIGHTS_LIST = 25000;
public static final int MAX_HIGHLIGHTS_LIST = 25000;
private final Connection connection;
protected final String databaseName;
private static final DatabaseMigrator MIGRATOR = new DatabaseMigrator();
Expand Down Expand Up @@ -83,15 +83,21 @@ public void insertHighlightList(final List<ChunkHighlightData> chunks, final Res

private void insertHighlightsListInternal(final List<ChunkHighlightData> chunks, final ResourceKey<Level> dimension) {
try {
try (var ps = connection.prepareStatement("INSERT OR IGNORE INTO \"" + getTableName(dimension) + "\" VALUES (?, ?, ?)")) {
for (int i = 0; i < chunks.size(); i++) {
final ChunkHighlightData chunk = chunks.get(i);
ps.setInt(1, chunk.x());
ps.setInt(2, chunk.z());
ps.setLong(3, chunk.foundTime());
ps.addBatch();
// Prepared statements is orders of magnitude slower than single insert like this
// batches even slower
// only issue is gc spam from string allocations
// could reuse this stringbuilder as this should only be called from a single thread
StringBuilder sb = new StringBuilder(50 * chunks.size() + 75);
sb.append("INSERT OR IGNORE INTO \"").append(getTableName(dimension)).append("\" VALUES ");
for (int i = 0; i < chunks.size(); i++) {
ChunkHighlightData chunk = chunks.get(i);
sb.append("(").append(chunk.x()).append(", ").append(chunk.z()).append(", ").append(chunk.foundTime()).append(")");
if (i < chunks.size() - 1) {
sb.append(", ");
}
ps.executeBatch();
}
try (var stmt = connection.createStatement()) {
stmt.executeUpdate(sb.toString());
}
} catch (Exception e) {
XaeroPlus.LOGGER.error("Error inserting {} chunks into {} database in dimension: {}", chunks.size(), databaseName, dimension.location(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import it.unimi.dsi.fastutil.longs.Long2LongMap;
import xaeroplus.XaeroPlus;
import xaeroplus.event.XaeroWorldChangeEvent;

import java.util.Map;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -48,7 +49,12 @@ private void limitChunksSize() {
}

@Override
public void handleWorldChange() {}
public void handleWorldChange(final XaeroWorldChangeEvent event) {
// intentionally not clearing cache on any world change state
// its somewhat useful for players so they don't lose all date if they get disconnected somehow
// but it does lead to data incoherence if they switch dimensions or servers in the same session
// so its a tradeoff, generally players will always use the database cache anyway
}

@Override
public void handleTick() {}
Expand Down
Loading

0 comments on commit 1fcd566

Please sign in to comment.