Skip to content

Commit

Permalink
Add spigot-1.20.4 initial support
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeprimm committed Dec 13, 2023
1 parent 06fbcb8 commit 85885ce
Show file tree
Hide file tree
Showing 13 changed files with 881 additions and 18 deletions.
8 changes: 7 additions & 1 deletion DynmapCore/src/main/resources/models_1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,13 @@ modellist:id=%iron_bars,state=west:false/east:false/south:false/north:false,box=
# Fern
# Dead shrub
# Tall grass
patchblock:id=fern,id=grass,id=cobweb,id=tall_grass,id=dead_bush,id=sugar_cane,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90
patchblock:id=fern,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90
[-1.20.2]patchblock:id=grass,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90
[1.20.3-]patchblock:id=short_grass,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90
patchblock:id=cobweb,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90
patchblock:id=tall_grass,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90
patchblock:id=dead_bush,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90
patchblock:id=sugar_cane,patch0=VertX1Z0ToX0Z1,patch1=VertX1Z0ToX0Z1@90

# Seagrass
# Tall seagrass
Expand Down
3 changes: 2 additions & 1 deletion DynmapCore/src/main/resources/texture_1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,8 @@ block:id=detector_rail,state=powered:false,patch0=0:detector_rail,transparency=T
# Web
block:id=cobweb,patch0-1=0:cobweb,transparency=TRANSPARENT
# Grass
block:id=grass,patch0-1=1000:grass,transparency=TRANSPARENT
[-1.20.2]block:id=grass,patch0-1=1000:grass,transparency=TRANSPARENT
[1.20.3-]block:id=short_grass,patch0-1=1000:grass,transparency=TRANSPARENT
# Fern
block:id=fern,patch0-1=1000:fern,transparency=TRANSPARENT
# Dead shrub
Expand Down
1 change: 1 addition & 0 deletions bukkit-helper-120-4/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build/
17 changes: 17 additions & 0 deletions bukkit-helper-120-4/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
eclipse {
project {
name = "Dynmap(Spigot-1.20.4)"
}
}

description = 'bukkit-helper-1.20.4'

sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = JavaLanguageVersion.of(17) // Need this here so eclipse task generates correctly.

dependencies {
implementation project(':bukkit-helper')
implementation project(':dynmap-api')
implementation project(path: ':DynmapCore', configuration: 'shadow')
compileOnly group: 'org.spigotmc', name: 'spigot-api', version:'1.20.4-R0.1-SNAPSHOT'
compileOnly group: 'org.spigotmc', name: 'spigot', version:'1.20.4-R0.1-SNAPSHOT'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package org.dynmap.bukkit.helper.v120_4;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.WorldServer;
import net.minecraft.world.level.chunk.Chunk;
import net.minecraft.world.level.chunk.IChunkAccess;
import net.minecraft.world.level.chunk.storage.ChunkRegionLoader;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.dynmap.MapManager;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

/**
* The provider used to work with paper libs
* Because paper libs need java 17 we can't interact with them directly
*/
@SuppressWarnings({"JavaReflectionMemberAccess"}) //java don't know about paper
public class AsyncChunkProvider120_4 {
private final Method getChunk;
private final Method getAsyncSaveData;
private final Method save;
private final Enum<?> data;
private final Enum<?> priority;
private int currTick = MinecraftServer.currentTick;
private int currChunks = 0;

AsyncChunkProvider120_4() {
try {
Method getChunk1 = null;
Method getAsyncSaveData1 = null;
Method save1 = null;
Enum<?> priority1 = null;
Enum<?> data1 = null;
try {
Class<?> threadClass = Class.forName("io.papermc.paper.chunk.system.io.RegionFileIOThread");

Class<?> dataclass = Arrays.stream(threadClass.getDeclaredClasses())
.filter(c -> c.getSimpleName().equals("RegionFileType"))
.findAny()
.orElseThrow(NullPointerException::new);
data1 = Enum.valueOf(cast(dataclass), "CHUNK_DATA");

Class<?> priorityClass = Arrays.stream(Class.forName("ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor").getClasses())
.filter(c -> c.getSimpleName().equals("Priority"))
.findAny()
.orElseThrow(NullPointerException::new);
//Almost lowest priority, but not quite so low as to be considered idle
//COMPLETING->BLOCKING->HIGHEST->HIGHER->HIGH->NORMAL->LOW->LOWER->LOWEST->IDLE
priority1 = Enum.valueOf(cast(priorityClass), "LOWEST");

getAsyncSaveData1 = ChunkRegionLoader.class.getMethod("getAsyncSaveData", WorldServer.class, IChunkAccess.class);
save1 = ChunkRegionLoader.class.getMethod("saveChunk", WorldServer.class, IChunkAccess.class, getAsyncSaveData1.getReturnType());
getChunk1 = threadClass.getMethod("loadDataAsync", WorldServer.class, int.class, int.class, data1.getClass(), BiConsumer.class, boolean.class, priority1.getClass());
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
}
getAsyncSaveData = Objects.requireNonNull(getAsyncSaveData1);
save = Objects.requireNonNull(save1);
getChunk = Objects.requireNonNull(getChunk1);
data = Objects.requireNonNull(data1);
priority = Objects.requireNonNull(priority1);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

@SuppressWarnings("unchecked")
private <T> T cast(Object o) {
return (T) o;
}
public CompletableFuture<NBTTagCompound> getChunk(WorldServer world, int x, int y) throws InvocationTargetException, IllegalAccessException {
CompletableFuture<NBTTagCompound> future = new CompletableFuture<>();
getChunk.invoke(null, world, x, y, data, (BiConsumer<NBTTagCompound, Throwable>) (nbt, exception) -> future.complete(nbt), true, priority);
return future;
}

public synchronized Supplier<NBTTagCompound> getLoadedChunk(CraftWorld world, int x, int z) {
if (!world.isChunkLoaded(x, z)) return () -> null;
Chunk c = world.getHandle().getChunkIfLoaded(x, z); //already safe async on vanilla
if ((c == null) || !c.q) return () -> null; // c.loaded
if (currTick != MinecraftServer.currentTick) {
currTick = MinecraftServer.currentTick;
currChunks = 0;
}
//prepare data synchronously
CompletableFuture<?> future = CompletableFuture.supplyAsync(() -> {
//Null will mean that we save with spigot methods, which may be risky on async
//Since we're not in main thread, it now refuses new tasks because of shutdown, the risk is lower
if (!Bukkit.isPrimaryThread()) return null;
try {
return getAsyncSaveData.invoke(null, world.getHandle(), c);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}, ((CraftServer) Bukkit.getServer()).getServer());
//we shouldn't stress main thread
if (++currChunks > MapManager.mapman.getMaxChunkLoadsPerTick()) {
try {
Thread.sleep(25); //hold the lock so other threads also won't stress main thread
} catch (InterruptedException ignored) {}
}
//save data asynchronously
return () -> {
Object o = null;
try {
o = future.get();
return (NBTTagCompound) save.invoke(null, world.getHandle(), c, o);
} catch (InterruptedException e) {
return null;
} catch (InvocationTargetException e) {
//We tried to use simple spigot methods at shutdown and failed, hopes for reading from disk
if (o == null) return null;
throw new RuntimeException(e);
} catch (ReflectiveOperationException | ExecutionException e) {
throw new RuntimeException(e);
}
};
}
}
Loading

0 comments on commit 85885ce

Please sign in to comment.