mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-12-26 10:37:44 +01:00
Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0
This commit is contained in:
commit
e68f628131
@ -766,7 +766,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read NBT data from loaded chunks - do not needs to be called from server/world
|
* Read NBT data from loaded chunks - do not needs to be called from server/world <p>
|
||||||
* Will throw {@link IllegalStateException} if not supporting
|
* Will throw {@link IllegalStateException} if not supporting
|
||||||
*/
|
*/
|
||||||
public void getLoadedChunksAsync() {
|
public void getLoadedChunksAsync() {
|
||||||
@ -836,7 +836,9 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the chunks async
|
* Loads all chunks in the world asynchronously.
|
||||||
|
* <p>
|
||||||
|
* If it is not supported, it will throw {@link IllegalStateException}
|
||||||
*/
|
*/
|
||||||
public void loadChunksAsync() {
|
public void loadChunksAsync() {
|
||||||
getLoadedChunksAsync();
|
getLoadedChunksAsync();
|
||||||
@ -923,6 +925,12 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It loads chunks from the cache or from the world, and if the chunk is not visible, it fills it with stone, ocean or
|
||||||
|
* empty chunk
|
||||||
|
* <p>
|
||||||
|
* if it's not supported, will throw {@link IllegalStateException}
|
||||||
|
*/
|
||||||
public void readChunksAsync() {
|
public void readChunksAsync() {
|
||||||
class SimplePair { //pair of the chunk and the data which is readed async
|
class SimplePair { //pair of the chunk and the data which is readed async
|
||||||
private final Supplier<GenericChunk> supplier;
|
private final Supplier<GenericChunk> supplier;
|
||||||
|
@ -16,7 +16,7 @@ public class CustomBlockModel extends HDBlockModel {
|
|||||||
super(bstate, databits, blockset);
|
super(bstate, databits, blockset);
|
||||||
try {
|
try {
|
||||||
Class<?> cls = Class.forName(classname); /* Get class */
|
Class<?> cls = Class.forName(classname); /* Get class */
|
||||||
render = (CustomRenderer) cls.newInstance();
|
render = (CustomRenderer) cls.getDeclaredConstructor().newInstance();
|
||||||
if(render.initializeRenderer(HDBlockModels.pdf, bstate.blockName, databits, classparm) == false) {
|
if(render.initializeRenderer(HDBlockModels.pdf, bstate.blockName, databits, classparm) == false) {
|
||||||
Log.severe("Error loading custom renderer - " + classname);
|
Log.severe("Error loading custom renderer - " + classname);
|
||||||
render = null;
|
render = null;
|
||||||
|
@ -2097,7 +2097,7 @@ public class TexturePack {
|
|||||||
else if(av[0].equals("custColorMult")) {
|
else if(av[0].equals("custColorMult")) {
|
||||||
try {
|
try {
|
||||||
Class<?> cls = Class.forName(av[1]);
|
Class<?> cls = Class.forName(av[1]);
|
||||||
custColorMult = (CustomColorMultiplier)cls.newInstance();
|
custColorMult = (CustomColorMultiplier)cls.getDeclaredConstructor().newInstance();
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
Log.severe("Error loading custom color multiplier - " + av[1] + ": " + x.getMessage());
|
Log.severe("Error loading custom color multiplier - " + av[1] + ": " + x.getMessage());
|
||||||
}
|
}
|
||||||
@ -2263,7 +2263,7 @@ public class TexturePack {
|
|||||||
else if(av[0].equals("custColorMult")) {
|
else if(av[0].equals("custColorMult")) {
|
||||||
try {
|
try {
|
||||||
Class<?> cls = Class.forName(av[1]);
|
Class<?> cls = Class.forName(av[1]);
|
||||||
custColorMult = (CustomColorMultiplier)cls.newInstance();
|
custColorMult = (CustomColorMultiplier)cls.getDeclaredConstructor().newInstance();
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
Log.severe("Error loading custom color multiplier - " + av[1] + ": " + x.getMessage());
|
Log.severe("Error loading custom color multiplier - " + av[1] + ": " + x.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ if ($stmt->fetch()) {
|
|||||||
header('Content-Type: image/jpeg');
|
header('Content-Type: image/jpeg');
|
||||||
}
|
}
|
||||||
header('ETag: \'' . $thash . '\'');
|
header('ETag: \'' . $thash . '\'');
|
||||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $tlast / 1000) . ' GMT');
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', (int) ($tlast / 1000)) . ' GMT');
|
||||||
if (is_null($tnewimage)) {
|
if (is_null($tnewimage)) {
|
||||||
echo $timage;
|
echo $timage;
|
||||||
} else {
|
} else {
|
||||||
|
@ -99,7 +99,7 @@ if ($res && $timage) {
|
|||||||
header('Content-Type: image/jpeg');
|
header('Content-Type: image/jpeg');
|
||||||
}
|
}
|
||||||
header('ETag: \'' . $thash . '\'');
|
header('ETag: \'' . $thash . '\'');
|
||||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $tlast / 1000) . ' GMT');
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', (int) ($tlast / 1000)) . ' GMT');
|
||||||
echo stream_get_contents($timage);
|
echo stream_get_contents($timage);
|
||||||
} else {
|
} else {
|
||||||
header('Location: ../images/blank.png');
|
header('Location: ../images/blank.png');
|
||||||
|
@ -3431,7 +3431,7 @@ block:id=%melon_stem,patch0=0:melon_stem,blockcolor=foliagebiome,transparency=TR
|
|||||||
[1.19-]block:id=%mangrove_sign,patch0=0,patch1=1,patch2=2,patch3=3,patch4=4,patch5=5,patch6=6,patch7=7,patch8=8,patch9=9,transparency=TRANSPARENT,txtid=mangrove_sign
|
[1.19-]block:id=%mangrove_sign,patch0=0,patch1=1,patch2=2,patch3=3,patch4=4,patch5=5,patch6=6,patch7=7,patch8=8,patch9=9,transparency=TRANSPARENT,txtid=mangrove_sign
|
||||||
[1.19-]block:id=%mangrove_wall_sign,patch0=0,patch1=1,patch2=2,patch3=3,patch4=4,patch5=5,transparency=TRANSPARENT,txtid=mangrove_sign
|
[1.19-]block:id=%mangrove_wall_sign,patch0=0,patch1=1,patch2=2,patch3=3,patch4=4,patch5=5,transparency=TRANSPARENT,txtid=mangrove_sign
|
||||||
[1.19-]block:id=%packed_mud,patch0=0:packed_mud,patch1=0:packed_mud,patch2=0:packed_mud,patch3=0:packed_mud,patch4=0:packed_mud,patch5=0:packed_mud,stdrot=true
|
[1.19-]block:id=%packed_mud,patch0=0:packed_mud,patch1=0:packed_mud,patch2=0:packed_mud,patch3=0:packed_mud,patch4=0:packed_mud,patch5=0:packed_mud,stdrot=true
|
||||||
[1.19-]block:id=%mud_bricks,patch0=0:mud_bricks,stdrot=true
|
[1.19-]block:id=%mud_bricks,patch0=0:mud_bricks,patch1=0:mud_bricks,patch2=0:mud_bricks,patch3=0:mud_bricks,patch4=0:mud_bricks,patch5=0:mud_bricks,stdrot=true
|
||||||
[1.19-]block:id=%mud_brick_stairs,state=facing:north/half:top/shape:straight,patch0=0:mud_bricks,transparency=SEMITRANSPARENT,stdrot=true
|
[1.19-]block:id=%mud_brick_stairs,state=facing:north/half:top/shape:straight,patch0=0:mud_bricks,transparency=SEMITRANSPARENT,stdrot=true
|
||||||
[1.19-]block:id=%mud_brick_stairs,state=facing:north/half:top/shape:inner_left,patch0=0:mud_bricks,transparency=SEMITRANSPARENT,stdrot=true
|
[1.19-]block:id=%mud_brick_stairs,state=facing:north/half:top/shape:inner_left,patch0=0:mud_bricks,transparency=SEMITRANSPARENT,stdrot=true
|
||||||
[1.19-]block:id=%mud_brick_stairs,state=facing:north/half:top/shape:inner_right,patch0=0:mud_bricks,transparency=SEMITRANSPARENT,stdrot=true
|
[1.19-]block:id=%mud_brick_stairs,state=facing:north/half:top/shape:inner_right,patch0=0:mud_bricks,transparency=SEMITRANSPARENT,stdrot=true
|
||||||
|
@ -1,31 +1,54 @@
|
|||||||
package org.dynmap.bukkit.helper.v118_2;
|
package org.dynmap.bukkit.helper.v118_2;
|
||||||
|
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.WorldServer;
|
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_18_R2.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
||||||
|
import org.dynmap.MapManager;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The provider used to work with paper libs
|
* The provider used to work with paper libs
|
||||||
* Because paper libs need java 17 we can't interact with them directly
|
* Because paper libs need java 17 we can't interact with them directly
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"JavaReflectionMemberAccess"}) //java don't know about paper
|
||||||
public class AsyncChunkProvider118_2 {
|
public class AsyncChunkProvider118_2 {
|
||||||
private final Thread ioThread;
|
private final Thread ioThread;
|
||||||
private final Method getChunk;
|
private final Method getChunk;
|
||||||
private final Predicate<NBTTagCompound> ifFailed;
|
private final Predicate<NBTTagCompound> ifFailed;
|
||||||
|
private final Method getAsyncSaveData;
|
||||||
|
private final Method save;
|
||||||
|
private int currTick = MinecraftServer.currentTick;
|
||||||
|
private int currChunks = 0;
|
||||||
|
|
||||||
AsyncChunkProvider118_2 () {
|
AsyncChunkProvider118_2 () {
|
||||||
try {
|
try {
|
||||||
Predicate<NBTTagCompound> ifFailed1 = null;
|
Predicate<NBTTagCompound> ifFailed1 = null;
|
||||||
Method getChunk1 = null;
|
Method getChunk1 = null, getAsyncSaveData1 = null, save1 = null;
|
||||||
Thread ioThread1 = null;
|
Thread ioThread1 = null;
|
||||||
try {
|
try {
|
||||||
Class<?> threadClass = Class.forName("com.destroystokyo.paper.io.PaperFileIOThread");
|
Class<?> threadClass = Class.forName("com.destroystokyo.paper.io.PaperFileIOThread");
|
||||||
|
Class<?> asyncChunkData = Arrays.stream(ChunkRegionLoader.class.getClasses())
|
||||||
|
.filter(c -> c.getSimpleName().equals("AsyncSaveData"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(RuntimeException::new);
|
||||||
|
getAsyncSaveData1 = ChunkRegionLoader.class.getMethod("getAsyncSaveData", WorldServer.class, IChunkAccess.class);
|
||||||
|
save1 = ChunkRegionLoader.class.getMethod("saveChunk", WorldServer.class, IChunkAccess.class, asyncChunkData);
|
||||||
Class<?>[] classes = threadClass.getClasses();
|
Class<?>[] classes = threadClass.getClasses();
|
||||||
Class<?> holder = Arrays.stream(classes).filter(aClass -> aClass.getSimpleName().equals("Holder")).findAny().orElseThrow(RuntimeException::new);
|
Class<?> holder = Arrays.stream(classes).filter(aClass -> aClass.getSimpleName().equals("Holder")).findAny().orElseThrow(RuntimeException::new);
|
||||||
ioThread1 = (Thread) holder.getField("INSTANCE").get(null);
|
ioThread1 = (Thread) holder.getField("INSTANCE").get(null);
|
||||||
@ -35,6 +58,8 @@ public class AsyncChunkProvider118_2 {
|
|||||||
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
|
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
getAsyncSaveData = Objects.requireNonNull(getAsyncSaveData1);
|
||||||
|
save = Objects.requireNonNull(save1);
|
||||||
ifFailed = Objects.requireNonNull(ifFailed1);
|
ifFailed = Objects.requireNonNull(ifFailed1);
|
||||||
getChunk = Objects.requireNonNull(getChunk1);
|
getChunk = Objects.requireNonNull(getChunk1);
|
||||||
ioThread = Objects.requireNonNull(ioThread1);
|
ioThread = Objects.requireNonNull(ioThread1);
|
||||||
@ -57,4 +82,38 @@ public class AsyncChunkProvider118_2 {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.o) return () -> null; // c.loaded
|
||||||
|
if (currTick != MinecraftServer.currentTick) {
|
||||||
|
currTick = MinecraftServer.currentTick;
|
||||||
|
currChunks = 0;
|
||||||
|
}
|
||||||
|
//prepare data synchronously
|
||||||
|
CompletableFuture<?> future = CompletableFuture.supplyAsync(() -> {
|
||||||
|
try {
|
||||||
|
return getAsyncSaveData.invoke(null, world.getHandle(), c);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException 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 e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//save data asynchronously
|
||||||
|
return () -> {
|
||||||
|
try {
|
||||||
|
return (NBTTagCompound) save.invoke(null, world.getHandle(), c, future.get());
|
||||||
|
} catch (ReflectiveOperationException | ExecutionException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package org.dynmap.bukkit.helper.v118_2;
|
package org.dynmap.bukkit.helper.v118_2;
|
||||||
|
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
|
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
||||||
import org.dynmap.DynmapChunk;
|
import org.dynmap.DynmapChunk;
|
||||||
|
import org.dynmap.MapManager;
|
||||||
import org.dynmap.bukkit.helper.BukkitVersionHelper;
|
import org.dynmap.bukkit.helper.BukkitVersionHelper;
|
||||||
import org.dynmap.bukkit.helper.BukkitWorld;
|
import org.dynmap.bukkit.helper.BukkitWorld;
|
||||||
import org.dynmap.common.chunk.GenericChunk;
|
import org.dynmap.common.chunk.GenericChunk;
|
||||||
@ -20,6 +22,7 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,11 +40,20 @@ public class MapChunkCache118_2 extends GenericMapChunkCache {
|
|||||||
|
|
||||||
// Load generic chunk from existing and already loaded chunk
|
// Load generic chunk from existing and already loaded chunk
|
||||||
protected GenericChunk getLoadedChunk(DynmapChunk chunk) {
|
protected GenericChunk getLoadedChunk(DynmapChunk chunk) {
|
||||||
return getLoadedChunk(chunk, false).get();
|
CraftWorld cw = (CraftWorld) w;
|
||||||
|
if (!cw.isChunkLoaded(chunk.x, chunk.z)) return null;
|
||||||
|
Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla
|
||||||
|
if ((c == null) || !c.o) return null; // c.loaded
|
||||||
|
NBTTagCompound nbt = ChunkRegionLoader.a(cw.getHandle(), c);
|
||||||
|
return nbt != null ? parseChunkFromNBT(new NBT.NBTCompound(nbt)) : null;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected Supplier<GenericChunk> getLoadedChunkAsync(DynmapChunk ch) {
|
protected Supplier<GenericChunk> getLoadedChunkAsync(DynmapChunk ch) {
|
||||||
return getLoadedChunk(ch, true);
|
Supplier<NBTTagCompound> nbtSupplier = provider.getLoadedChunk((CraftWorld) w, ch.x, ch.z);
|
||||||
|
return () -> {
|
||||||
|
NBTTagCompound nbt = nbtSupplier.get();
|
||||||
|
return nbt == null ? null : parseChunkFromNBT(new NBT.NBTCompound(nbt));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,26 +69,6 @@ public class MapChunkCache118_2 extends GenericMapChunkCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Supplier<GenericChunk> getLoadedChunk(DynmapChunk chunk, boolean async) {
|
|
||||||
CraftWorld cw = (CraftWorld) w;
|
|
||||||
if (!cw.isChunkLoaded(chunk.x, chunk.z)) return () -> null;
|
|
||||||
Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla
|
|
||||||
if ((c == null) || c.o) return () -> null; // c.loaded
|
|
||||||
if (async) { //the data of the chunk may change while we write, better to write it sync
|
|
||||||
CompletableFuture<NBTTagCompound> nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer());
|
|
||||||
return () -> {
|
|
||||||
NBTTagCompound compound = nbt.join();
|
|
||||||
return compound == null ? null : parseChunkFromNBT(new NBT.NBTCompound(compound));
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
NBTTagCompound nbt = ChunkRegionLoader.a(cw.getHandle(), c);
|
|
||||||
GenericChunk genericChunk;
|
|
||||||
if (nbt != null) genericChunk = parseChunkFromNBT(new NBT.NBTCompound(nbt));
|
|
||||||
else genericChunk = null;
|
|
||||||
return () -> genericChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// Load generic chunk from unloaded chunk
|
// Load generic chunk from unloaded chunk
|
||||||
protected GenericChunk loadChunk(DynmapChunk chunk) {
|
protected GenericChunk loadChunk(DynmapChunk chunk) {
|
||||||
CraftWorld cw = (CraftWorld) w;
|
CraftWorld cw = (CraftWorld) w;
|
||||||
|
@ -1,31 +1,53 @@
|
|||||||
package org.dynmap.bukkit.helper.v119;
|
package org.dynmap.bukkit.helper.v119;
|
||||||
|
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.WorldServer;
|
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_19_R1.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||||
|
import org.dynmap.MapManager;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The provider used to work with paper libs
|
* The provider used to work with paper libs
|
||||||
* Because paper libs need java 17 we can't interact with them directly
|
* Because paper libs need java 17 we can't interact with them directly
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"JavaReflectionMemberAccess"}) //java don't know about paper
|
||||||
public class AsyncChunkProvider119 {
|
public class AsyncChunkProvider119 {
|
||||||
private final Thread ioThread;
|
private final Thread ioThread;
|
||||||
private final Method getChunk;
|
private final Method getChunk;
|
||||||
private final Predicate<NBTTagCompound> ifFailed;
|
private final Predicate<NBTTagCompound> ifFailed;
|
||||||
AsyncChunkProvider119 () {
|
private final Method getAsyncSaveData;
|
||||||
|
private final Method save;
|
||||||
|
private int currTick = MinecraftServer.currentTick;
|
||||||
|
private int currChunks = 0;
|
||||||
|
|
||||||
|
AsyncChunkProvider119() {
|
||||||
try {
|
try {
|
||||||
Predicate<NBTTagCompound> ifFailed1 = null;
|
Predicate<NBTTagCompound> ifFailed1 = null;
|
||||||
Method getChunk1 = null;
|
Method getChunk1 = null, getAsyncSaveData1 = null, save1 = null;
|
||||||
Thread ioThread1 = null;
|
Thread ioThread1 = null;
|
||||||
try {
|
try {
|
||||||
Class<?> threadClass = Class.forName("com.destroystokyo.paper.io.PaperFileIOThread");
|
Class<?> threadClass = Class.forName("com.destroystokyo.paper.io.PaperFileIOThread");
|
||||||
|
Class<?> asyncChunkData = Arrays.stream(ChunkRegionLoader.class.getClasses())
|
||||||
|
.filter(c -> c.getSimpleName().equals("AsyncSaveData"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(RuntimeException::new);
|
||||||
|
getAsyncSaveData1 = ChunkRegionLoader.class.getMethod("getAsyncSaveData", WorldServer.class, IChunkAccess.class);
|
||||||
|
save1 = ChunkRegionLoader.class.getMethod("saveChunk", WorldServer.class, IChunkAccess.class, asyncChunkData);
|
||||||
Class<?>[] classes = threadClass.getClasses();
|
Class<?>[] classes = threadClass.getClasses();
|
||||||
Class<?> holder = Arrays.stream(classes).filter(aClass -> aClass.getSimpleName().equals("Holder")).findAny().orElseThrow(RuntimeException::new);
|
Class<?> holder = Arrays.stream(classes).filter(aClass -> aClass.getSimpleName().equals("Holder")).findAny().orElseThrow(RuntimeException::new);
|
||||||
ioThread1 = (Thread) holder.getField("INSTANCE").get(null);
|
ioThread1 = (Thread) holder.getField("INSTANCE").get(null);
|
||||||
@ -35,6 +57,8 @@ public class AsyncChunkProvider119 {
|
|||||||
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
|
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
getAsyncSaveData = Objects.requireNonNull(getAsyncSaveData1);
|
||||||
|
save = Objects.requireNonNull(save1);
|
||||||
ifFailed = Objects.requireNonNull(ifFailed1);
|
ifFailed = Objects.requireNonNull(ifFailed1);
|
||||||
getChunk = Objects.requireNonNull(getChunk1);
|
getChunk = Objects.requireNonNull(getChunk1);
|
||||||
ioThread = Objects.requireNonNull(ioThread1);
|
ioThread = Objects.requireNonNull(ioThread1);
|
||||||
@ -57,4 +81,38 @@ public class AsyncChunkProvider119 {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.o) return () -> null; // c.loaded
|
||||||
|
if (currTick != MinecraftServer.currentTick) {
|
||||||
|
currTick = MinecraftServer.currentTick;
|
||||||
|
currChunks = 0;
|
||||||
|
}
|
||||||
|
//prepare data synchronously
|
||||||
|
CompletableFuture<?> future = CompletableFuture.supplyAsync(() -> {
|
||||||
|
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 e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//save data asynchronously
|
||||||
|
return () -> {
|
||||||
|
try {
|
||||||
|
return (NBTTagCompound) save.invoke(null, world.getHandle(), c, future.get());
|
||||||
|
} catch (ReflectiveOperationException | ExecutionException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package org.dynmap.bukkit.helper.v119;
|
package org.dynmap.bukkit.helper.v119;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||||
import org.dynmap.DynmapChunk;
|
import org.dynmap.DynmapChunk;
|
||||||
import org.dynmap.bukkit.helper.BukkitVersionHelper;
|
import org.dynmap.bukkit.helper.BukkitVersionHelper;
|
||||||
@ -16,7 +14,6 @@ import net.minecraft.world.level.ChunkCoordIntPair;
|
|||||||
import net.minecraft.world.level.chunk.storage.ChunkRegionLoader;
|
import net.minecraft.world.level.chunk.storage.ChunkRegionLoader;
|
||||||
import net.minecraft.world.level.chunk.Chunk;
|
import net.minecraft.world.level.chunk.Chunk;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
@ -38,14 +35,24 @@ public class MapChunkCache119 extends GenericMapChunkCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load generic chunk from existing and already loaded chunk
|
// Load generic chunk from existing and already loaded chunk
|
||||||
protected GenericChunk getLoadedChunk(DynmapChunk chunk) {
|
|
||||||
return getLoadedChunk(chunk, false).get();
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
protected Supplier<GenericChunk> getLoadedChunkAsync(DynmapChunk ch) {
|
protected Supplier<GenericChunk> getLoadedChunkAsync(DynmapChunk chunk) {
|
||||||
return getLoadedChunk(ch, true);
|
Supplier<NBTTagCompound> supplier = provider.getLoadedChunk((CraftWorld) w, chunk.x, chunk.z);
|
||||||
|
return () -> {
|
||||||
|
NBTTagCompound nbt = supplier.get();
|
||||||
|
return nbt != null ? parseChunkFromNBT(new NBT.NBTCompound(nbt)) : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
protected GenericChunk getLoadedChunk(DynmapChunk chunk) {
|
||||||
|
CraftWorld cw = (CraftWorld) w;
|
||||||
|
if (!cw.isChunkLoaded(chunk.x, chunk.z)) return null;
|
||||||
|
Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z);
|
||||||
|
if (c == null || !c.o) return null; // c.loaded
|
||||||
|
NBTTagCompound nbt = ChunkRegionLoader.a(cw.getHandle(), c);
|
||||||
|
return nbt != null ? parseChunkFromNBT(new NBT.NBTCompound(nbt)) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load generic chunk from unloaded chunk
|
||||||
@Override
|
@Override
|
||||||
protected Supplier<GenericChunk> loadChunkAsync(DynmapChunk chunk){
|
protected Supplier<GenericChunk> loadChunkAsync(DynmapChunk chunk){
|
||||||
try {
|
try {
|
||||||
@ -59,27 +66,6 @@ public class MapChunkCache119 extends GenericMapChunkCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Supplier<GenericChunk> getLoadedChunk(DynmapChunk chunk, boolean async) {
|
|
||||||
CraftWorld cw = (CraftWorld) w;
|
|
||||||
if (!cw.isChunkLoaded(chunk.x, chunk.z)) return () -> null;
|
|
||||||
Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla
|
|
||||||
if ((c == null) || c.o) return () -> null; // c.loaded
|
|
||||||
if (async) { //the data of the chunk may change while we write, better to write it sync
|
|
||||||
CompletableFuture<NBTTagCompound> nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer());
|
|
||||||
return () -> {
|
|
||||||
NBTTagCompound compound = nbt.join();
|
|
||||||
return compound == null ? null : parseChunkFromNBT(new NBT.NBTCompound(compound));
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
NBTTagCompound nbt = ChunkRegionLoader.a(cw.getHandle(), c);
|
|
||||||
GenericChunk genericChunk;
|
|
||||||
if (nbt != null) genericChunk = parseChunkFromNBT(new NBT.NBTCompound(nbt));
|
|
||||||
else genericChunk = null;
|
|
||||||
return () -> genericChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// Load generic chunk from unloaded chunk
|
|
||||||
protected GenericChunk loadChunk(DynmapChunk chunk) {
|
protected GenericChunk loadChunk(DynmapChunk chunk) {
|
||||||
CraftWorld cw = (CraftWorld) w;
|
CraftWorld cw = (CraftWorld) w;
|
||||||
NBTTagCompound nbt = null;
|
NBTTagCompound nbt = null;
|
||||||
|
@ -397,7 +397,7 @@ public abstract class BukkitVersionHelperGeneric extends BukkitVersionHelper {
|
|||||||
/**
|
/**
|
||||||
* Get inhabited ticks count from chunk
|
* Get inhabited ticks count from chunk
|
||||||
*/
|
*/
|
||||||
private static final Long zero = new Long(0);
|
private static final Long zero = Long.valueOf(0);
|
||||||
public long getInhabitedTicks(Chunk c) {
|
public long getInhabitedTicks(Chunk c) {
|
||||||
if (nmsc_inhabitedticks == null) {
|
if (nmsc_inhabitedticks == null) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -557,25 +557,25 @@ public abstract class BukkitVersionHelperGeneric extends BukkitVersionHelper {
|
|||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
Object propmap = callMethod(profile, cmaprofile_getproperties, nullargs, null);
|
Object propmap = callMethod(profile, cmaprofile_getproperties, nullargs, null);
|
||||||
if ((propmap != null) && (propmap instanceof ForwardingMultimap)) {
|
if ((propmap != null) && (propmap instanceof ForwardingMultimap)) {
|
||||||
ForwardingMultimap<String, Object> fmm = (ForwardingMultimap<String, Object>) propmap;
|
ForwardingMultimap<String, Object> fmm = (ForwardingMultimap<String, Object>) propmap;
|
||||||
Collection<Object> txt = fmm.get("textures");
|
Collection<Object> txt = fmm.get("textures");
|
||||||
Object textureProperty = Iterables.getFirst(fmm.get("textures"), null);
|
Object textureProperty = Iterables.getFirst(fmm.get("textures"), null);
|
||||||
if (textureProperty != null) {
|
if (textureProperty != null) {
|
||||||
String val = (String) callMethod(textureProperty, cmaproperty_getvalue, nullargs, null);
|
String val = (String) callMethod(textureProperty, cmaproperty_getvalue, nullargs, null);
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
TexturesPayload result = null;
|
TexturesPayload result = null;
|
||||||
try {
|
try {
|
||||||
String json = new String(Base64.getDecoder().decode(val), StandardCharsets.UTF_8);
|
String json = new String(Base64.getDecoder().decode(val), StandardCharsets.UTF_8);
|
||||||
result = gson.fromJson(json, TexturesPayload.class);
|
result = gson.fromJson(json, TexturesPayload.class);
|
||||||
} catch (JsonParseException e) {
|
} catch (JsonParseException e) {
|
||||||
} catch (IllegalArgumentException x) {
|
} catch (IllegalArgumentException x) {
|
||||||
Log.warning("Malformed response from skin URL check: " + val);
|
Log.warning("Malformed response from skin URL check: " + val);
|
||||||
}
|
}
|
||||||
if ((result != null) && (result.textures != null) && (result.textures.containsKey("SKIN"))) {
|
if ((result != null) && (result.textures != null) && (result.textures.containsKey("SKIN"))) {
|
||||||
url = result.textures.get("SKIN").url;
|
url = result.textures.get("SKIN").url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ configurations {
|
|||||||
implementation.extendsFrom(shadow)
|
implementation.extendsFrom(shadow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||||
@ -27,6 +32,9 @@ dependencies {
|
|||||||
compileOnly group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
|
compileOnly group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
|
||||||
|
|
||||||
shadow project(path: ':DynmapCore', configuration: 'shadow')
|
shadow project(path: ':DynmapCore', configuration: 'shadow')
|
||||||
|
|
||||||
|
modCompileOnly "me.lucko:fabric-permissions-api:0.1-SNAPSHOT"
|
||||||
|
compileOnly 'net.luckperms:api:5.4'
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
@ -3,10 +3,10 @@ package org.dynmap.fabric_1_19;
|
|||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.FluidBlock;
|
import net.minecraft.block.FluidBlock;
|
||||||
@ -30,9 +30,6 @@ import net.minecraft.world.WorldAccess;
|
|||||||
import net.minecraft.world.biome.Biome;
|
import net.minecraft.world.biome.Biome;
|
||||||
import net.minecraft.world.chunk.Chunk;
|
import net.minecraft.world.chunk.Chunk;
|
||||||
import net.minecraft.world.chunk.ChunkSection;
|
import net.minecraft.world.chunk.ChunkSection;
|
||||||
import net.minecraft.world.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.chunk.WorldChunk;
|
|
||||||
|
|
||||||
import org.dynmap.*;
|
import org.dynmap.*;
|
||||||
import org.dynmap.common.BiomeMap;
|
import org.dynmap.common.BiomeMap;
|
||||||
import org.dynmap.common.DynmapCommandSender;
|
import org.dynmap.common.DynmapCommandSender;
|
||||||
@ -48,9 +45,7 @@ import org.dynmap.fabric_1_19.event.CustomServerChunkEvents;
|
|||||||
import org.dynmap.fabric_1_19.event.CustomServerLifecycleEvents;
|
import org.dynmap.fabric_1_19.event.CustomServerLifecycleEvents;
|
||||||
import org.dynmap.fabric_1_19.event.PlayerEvents;
|
import org.dynmap.fabric_1_19.event.PlayerEvents;
|
||||||
import org.dynmap.fabric_1_19.mixin.BiomeEffectsAccessor;
|
import org.dynmap.fabric_1_19.mixin.BiomeEffectsAccessor;
|
||||||
import org.dynmap.fabric_1_19.permissions.FilePermissions;
|
import org.dynmap.fabric_1_19.permissions.*;
|
||||||
import org.dynmap.fabric_1_19.permissions.OpPermissions;
|
|
||||||
import org.dynmap.fabric_1_19.permissions.PermissionProvider;
|
|
||||||
import org.dynmap.permissions.PermissionsHandler;
|
import org.dynmap.permissions.PermissionsHandler;
|
||||||
import org.dynmap.renderer.DynmapBlockState;
|
import org.dynmap.renderer.DynmapBlockState;
|
||||||
|
|
||||||
@ -396,9 +391,19 @@ public class DynmapPlugin {
|
|||||||
registerPlayerLoginListener();
|
registerPlayerLoginListener();
|
||||||
|
|
||||||
/* Initialize permissions handler */
|
/* Initialize permissions handler */
|
||||||
permissions = FilePermissions.create();
|
if (FabricLoader.getInstance().isModLoaded("luckperms")) {
|
||||||
if (permissions == null) {
|
Log.info("Using luckperms for access control");
|
||||||
permissions = new OpPermissions(new String[]{"webchat", "marker.icons", "marker.list", "webregister", "stats", "hide.self", "show.self"});
|
permissions = new LuckPermissions();
|
||||||
|
}
|
||||||
|
else if (FabricLoader.getInstance().isModLoaded("fabric-permissions-api-v0")) {
|
||||||
|
Log.info("Using fabric-permissions-api for access control");
|
||||||
|
permissions = new FabricPermissions();
|
||||||
|
} else {
|
||||||
|
/* Initialize permissions handler */
|
||||||
|
permissions = FilePermissions.create();
|
||||||
|
if (permissions == null) {
|
||||||
|
permissions = new OpPermissions(new String[]{"webchat", "marker.icons", "marker.list", "webregister", "stats", "hide.self", "show.self"});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Get and initialize data folder */
|
/* Get and initialize data folder */
|
||||||
File dataDirectory = new File("dynmap");
|
File dataDirectory = new File("dynmap");
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package org.dynmap.fabric_1_19.permissions;
|
||||||
|
|
||||||
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import org.dynmap.Log;
|
||||||
|
import org.dynmap.fabric_1_19.DynmapPlugin;
|
||||||
|
import org.dynmap.json.simple.parser.JSONParser;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class FabricPermissions implements PermissionProvider {
|
||||||
|
|
||||||
|
private String permissionKey(String perm) {
|
||||||
|
return "dynmap." + perm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> hasOfflinePermissions(String player, Set<String> perms) {
|
||||||
|
return perms.stream()
|
||||||
|
.filter(perm -> hasOfflinePermission(player, perm))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasOfflinePermission(String player, String perm) {
|
||||||
|
return DynmapPlugin.plugin.isOp(player.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean has(PlayerEntity player, String permission) {
|
||||||
|
if (player == null) return false;
|
||||||
|
String name = player.getName().getString().toLowerCase();
|
||||||
|
if (DynmapPlugin.plugin.isOp(name)) return true;
|
||||||
|
return Permissions.check(player, permissionKey(permission));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionNode(PlayerEntity player, String permission) {
|
||||||
|
if (player != null) {
|
||||||
|
String name = player.getName().getString().toLowerCase();
|
||||||
|
return DynmapPlugin.plugin.isOp(name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package org.dynmap.fabric_1_19.permissions;
|
||||||
|
|
||||||
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
|
import net.luckperms.api.LuckPerms;
|
||||||
|
import net.luckperms.api.LuckPermsProvider;
|
||||||
|
import net.luckperms.api.cacheddata.CachedPermissionData;
|
||||||
|
import net.luckperms.api.model.user.User;
|
||||||
|
import net.luckperms.api.util.Tristate;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.dynmap.Log;
|
||||||
|
import org.dynmap.fabric_1_19.DynmapPlugin;
|
||||||
|
import org.dynmap.json.simple.JSONArray;
|
||||||
|
import org.dynmap.json.simple.JSONObject;
|
||||||
|
import org.dynmap.json.simple.parser.JSONParser;
|
||||||
|
import org.dynmap.json.simple.parser.ParseException;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class LuckPermissions implements PermissionProvider {
|
||||||
|
|
||||||
|
private final JSONParser parser = new JSONParser();
|
||||||
|
private LuckPerms api = null;
|
||||||
|
|
||||||
|
private Optional<LuckPerms> getApi() {
|
||||||
|
if (api != null) return Optional.of(api);
|
||||||
|
try {
|
||||||
|
api = LuckPermsProvider.get();
|
||||||
|
return Optional.of(api);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.warning("Trying to access LuckPerms before it has loaded");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<UUID> cachedUUID(String username) {
|
||||||
|
try {
|
||||||
|
BufferedReader reader = new BufferedReader(new FileReader("usercache.json"));
|
||||||
|
JSONArray cache = (JSONArray) parser.parse(reader);
|
||||||
|
for (Object it : cache) {
|
||||||
|
JSONObject user = (JSONObject) it;
|
||||||
|
if (user.get("name").toString().equalsIgnoreCase(username)) {
|
||||||
|
String uuid = user.get("uuid").toString();
|
||||||
|
return Optional.of(UUID.fromString(uuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException | ParseException ex) {
|
||||||
|
Log.warning("Unable to read usercache.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String permissionKey(String perm) {
|
||||||
|
return "dynmap." + perm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> hasOfflinePermissions(String player, Set<String> perms) {
|
||||||
|
return perms.stream()
|
||||||
|
.filter(perm -> hasOfflinePermission(player, perm))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasOfflinePermission(String player, String perm) {
|
||||||
|
if (DynmapPlugin.plugin.isOp(player.toLowerCase())) return true;
|
||||||
|
Optional<LuckPerms> api = getApi();
|
||||||
|
Optional<UUID> uuid = cachedUUID(player);
|
||||||
|
if (!uuid.isPresent() || !api.isPresent()) return false;
|
||||||
|
User user = api.get().getUserManager().loadUser(uuid.get()).join();
|
||||||
|
CachedPermissionData permissions = user.getCachedData().getPermissionData();
|
||||||
|
Tristate state = permissions.checkPermission(permissionKey(perm));
|
||||||
|
return state.asBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean has(PlayerEntity player, String permission) {
|
||||||
|
if (player == null) return false;
|
||||||
|
String name = player.getName().getString().toLowerCase();
|
||||||
|
if (DynmapPlugin.plugin.isOp(name)) return true;
|
||||||
|
return Permissions.check(player, permissionKey(permission));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionNode(PlayerEntity player, String permission) {
|
||||||
|
if (player != null) {
|
||||||
|
String name = player.getName().getString().toLowerCase();
|
||||||
|
return DynmapPlugin.plugin.isOp(name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,20 +6,8 @@ import java.lang.reflect.Field;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.PriorityQueue;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@ -253,7 +241,10 @@ public class DynmapPlugin
|
|||||||
if (statename.length() > 0) {
|
if (statename.length() > 0) {
|
||||||
statename += ",";
|
statename += ",";
|
||||||
}
|
}
|
||||||
statename += p.getName() + "=" + bs.get(p).toString();
|
try {
|
||||||
|
statename += p.getName() + "=" + bs.get(p).toString();
|
||||||
|
} catch (IllegalFormatConversionException e){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int lightAtten = bs.isOpaqueCube(EmptyBlockReader.INSTANCE, BlockPos.ZERO) ? 15 : (bs.propagatesSkylightDown(EmptyBlockReader.INSTANCE, BlockPos.ZERO) ? 0 : 1);
|
int lightAtten = bs.isOpaqueCube(EmptyBlockReader.INSTANCE, BlockPos.ZERO) ? 15 : (bs.propagatesSkylightDown(EmptyBlockReader.INSTANCE, BlockPos.ZERO) ? 0 : 1);
|
||||||
//Log.info("statename=" + bn + "[" + statename + "], lightAtten=" + lightAtten);
|
//Log.info("statename=" + bn + "[" + statename + "], lightAtten=" + lightAtten);
|
||||||
|
Loading…
Reference in New Issue
Block a user