diff --git a/DynmapCore/build.gradle b/DynmapCore/build.gradle index 9946897c..d1eb853f 100644 --- a/DynmapCore/build.gradle +++ b/DynmapCore/build.gradle @@ -3,8 +3,11 @@ description = "DynmapCore" dependencies { implementation project(':DynmapCoreAPI') implementation 'javax.servlet:javax.servlet-api:3.1' - implementation'org.eclipse.jetty:jetty-server:9.4.26.v20200117' + implementation 'org.eclipse.jetty:jetty-server:9.4.26.v20200117' implementation 'org.eclipse.jetty:jetty-servlet:9.4.26.v20200117' + implementation 'org.eclipse.jetty:jetty-util:9.4.26.v20200117' + implementation 'org.eclipse.jetty:jetty-http:9.4.26.v20200117' + implementation 'org.eclipse.jetty:jetty-io:9.4.26.v20200117' implementation 'com.googlecode.json-simple:json-simple:1.1.1' implementation 'org.yaml:snakeyaml:1.23' // DON'T UPDATE - NEWER ONE TRIPS ON WINDOWS ENCODED FILES implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20180219.1' @@ -46,8 +49,12 @@ shadowJar { include(dependency('com.googlecode.json-simple:json-simple:')) include(dependency('org.yaml:snakeyaml:')) include(dependency('com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:')) - include(dependency('javax.servlet::')) - include(dependency('org.eclipse.jetty::')) + include(dependency('javax.servlet:javax.servlet-api:')) + include(dependency('org.eclipse.jetty:jetty-server:')) + include(dependency('org.eclipse.jetty:jetty-servlet:')) + include(dependency('org.eclipse.jetty:jetty-util:')) + include(dependency('org.eclipse.jetty:jetty-http:')) + include(dependency('org.eclipse.jetty:jetty-io:')) include(dependency('org.eclipse.jetty.orbit:javax.servlet:')) include(dependency('org.postgresql:postgresql:')) include(dependency('io.github.linktosriram.s3lite:core:')) @@ -55,8 +62,8 @@ shadowJar { include(dependency('io.github.linktosriram.s3lite:http-client-url-connection:')) include(dependency('io.github.linktosriram.s3lite:http-client-spi:')) include(dependency('io.github.linktosriram.s3lite:util:')) - include(dependency('jakarta.xml.bind::')) - include(dependency('com.sun.xml.bind::')) + include(dependency('jakarta.xml.bind:jakarta.xml.bind-api:')) + include(dependency('com.sun.xml.bind:jaxb-impl:')) include(dependency(':DynmapCoreAPI')) exclude("META-INF/maven/**") exclude("META-INF/services/**") diff --git a/build.gradle b/build.gradle index 4d243991..05eb7299 100644 --- a/build.gradle +++ b/build.gradle @@ -1,19 +1,5 @@ -// Workaround for Shadow not supporting Java 19 classes. -// Remove this once Shadow updates. -// See: https://github.com/johnrengelman/shadow/pull/770 -// See: https://discord.com/channels/722722769950998560/793019909055578113/978939925061857315 -buildscript { - configurations.all { - resolutionStrategy { - force("org.ow2.asm:asm:9.5") - force("org.ow2.asm:asm-commons:9.5") - } - } -} - plugins { - //id "com.github.johnrengelman.shadow" version "7.1.0" - id "io.github.goooler.shadow" version "8.1.7" + id "com.gradleup.shadow" version "9.4.1" id 'java' id 'maven-publish' } @@ -46,7 +32,6 @@ allprojects { group = 'us.dynmap' version = '3.7-beta-11' - } class Globals { @@ -57,17 +42,20 @@ ext { } subprojects { - apply plugin: "io.github.goooler.shadow" + apply plugin: "com.gradleup.shadow" apply plugin: 'java' apply plugin: 'maven-publish' - sourceCompatibility = 1.8 - targetCompatibility = 1.8 tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } } +java { + sourceCompatibility = 25 + targetCompatibility = 25 +} + clean { delete "target" } diff --git a/bukkit-helper-121-11/build.gradle b/bukkit-helper-121-11/build.gradle index 3260411f..6ee8ffd3 100644 --- a/bukkit-helper-121-11/build.gradle +++ b/bukkit-helper-121-11/build.gradle @@ -1,10 +1,6 @@ description = 'bukkit-helper-1.21.11' -// Ensure application is buildable using java 17 or above. -sourceCompatibility = 17 -targetCompatibility = 17 - dependencies { implementation project(':bukkit-helper') implementation project(':dynmap-api') @@ -13,4 +9,4 @@ dependencies { compileOnly ('org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT') { exclude group: "com.mojang", module: "jtracy" } -} +} \ No newline at end of file diff --git a/bukkit-helper-26-1-2/.gitignore b/bukkit-helper-26-1-2/.gitignore new file mode 100644 index 00000000..d1638636 --- /dev/null +++ b/bukkit-helper-26-1-2/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/bukkit-helper-26-1-2/build.gradle b/bukkit-helper-26-1-2/build.gradle new file mode 100644 index 00000000..80ba8a3d --- /dev/null +++ b/bukkit-helper-26-1-2/build.gradle @@ -0,0 +1,13 @@ + +description = 'bukkit-helper-26-1-2' + +dependencies { + implementation project(':bukkit-helper') + implementation project(':dynmap-api') + implementation project(path: ':DynmapCore', configuration: 'shadow') + implementation project(path: ':DynmapCoreAPI', configuration: 'shadow') + compileOnly group: 'org.spigotmc', name: 'spigot-api', version:'26.1.2-R0.1-SNAPSHOT' + compileOnly ('org.spigotmc:spigot:26.1.2-R0.1-SNAPSHOT') { + exclude group: "com.mojang", module: "jtracy" + } +} diff --git a/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/BukkitVersionHelperSpigot26_1_2.java b/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/BukkitVersionHelperSpigot26_1_2.java new file mode 100644 index 00000000..8686c67b --- /dev/null +++ b/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/BukkitVersionHelperSpigot26_1_2.java @@ -0,0 +1,450 @@ +package org.dynmap.bukkit.helper.v26_1_2; + +import org.bukkit.*; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.dynmap.DynmapChunk; +import org.dynmap.Log; +import org.dynmap.bukkit.helper.BukkitMaterial; +import org.dynmap.bukkit.helper.BukkitVersionHelper; +import org.dynmap.bukkit.helper.BukkitWorld; +import org.dynmap.bukkit.helper.BukkitVersionHelperGeneric.TexturesPayload; +import org.dynmap.renderer.DynmapBlockState; +import org.dynmap.utils.MapChunkCache; +import org.dynmap.utils.Polygon; + +import com.google.common.collect.Iterables; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; + +import net.minecraft.core.IdMapper; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.core.Registry; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.ByteTag; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.LongTag; +import net.minecraft.nbt.ShortTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.resources.Identifier; +import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.status.ChunkStatus; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collection; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + + +/** + * Helper for isolation of bukkit version specific issues + */ +public class BukkitVersionHelperSpigot26_1_2 extends BukkitVersionHelper { + + @Override + public boolean isUnsafeAsync() { + return false; + } + + /** + * Get block short name list + */ + @Override + public String[] getBlockNames() { + IdMapper bsids = Block.BLOCK_STATE_REGISTRY; + Block baseb = null; + Iterator iter = bsids.iterator(); + ArrayList names = new ArrayList(); + while (iter.hasNext()) { + BlockState bs = iter.next(); + Block b = bs.getBlock(); + // If this is new block vs last, it's the base block state + if (b != baseb) { + baseb = b; + continue; + } + Identifier id = BuiltInRegistries.BLOCK.getKey(b); // BuiltInRegistries.BLOCK.getKey(b) + String bn = id.toString(); + if (bn != null) { + names.add(bn); + Log.info("block=" + bn); + } + } + return names.toArray(new String[0]); + } + + private static Registry reg = null; + + private static Registry getBiomeReg() { + if (reg == null) { + reg = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + } + return reg; + } + + private Object[] biomelist; + /** + * Get list of defined Biome objects + */ + @Override + public Object[] getBiomeBaseList() { + if (biomelist == null) { + biomelist = new Biome[256]; + Iterator iter = getBiomeReg().iterator(); + while (iter.hasNext()) { + Biome b = iter.next(); + int bidx = getBiomeReg().getId(b); + if (bidx >= biomelist.length) { + biomelist = Arrays.copyOf(biomelist, bidx + biomelist.length); + } + biomelist[bidx] = b; + } + } + return biomelist; + } + + /** Get ID from Biome */ + @Override + public int getBiomeBaseID(Object bb) { + return getBiomeReg().getId((Biome)bb); + } + + public static IdentityHashMap dataToState; + + /** + * Initialize block states (org.dynmap.blockstate.DynmapBlockState) + */ + @Override + public void initializeBlockStates() { + dataToState = new IdentityHashMap(); + HashMap lastBlockState = new HashMap(); + IdMapper bsids = Block.BLOCK_STATE_REGISTRY; + Block baseb = null; + Iterator iter = bsids.iterator(); + ArrayList names = new ArrayList(); + + // Loop through block data states + DynmapBlockState.Builder bld = new DynmapBlockState.Builder(); + while (iter.hasNext()) { + BlockState bd = iter.next(); + Block b = bd.getBlock(); + Identifier id = BuiltInRegistries.BLOCK.getKey(b); + String bname = id.toString(); + DynmapBlockState lastbs = lastBlockState.get(bname); // See if we have seen this one + int idx = 0; + if (lastbs != null) { // Yes + idx = lastbs.getStateCount(); // Get number of states so far, since this is next + } + // Build state name + String sb = ""; + String fname = bd.toString(); + int off1 = fname.indexOf('['); + if (off1 >= 0) { + int off2 = fname.indexOf(']'); + sb = fname.substring(off1+1, off2); + } + int lightAtten = bd.getLightDampening(); + //Log.info("statename=" + bname + "[" + sb + "], lightAtten=" + lightAtten); + // Fill in base attributes + bld.setBaseState(lastbs).setStateIndex(idx).setBlockName(bname).setStateName(sb).setAttenuatesLight(lightAtten); + if (bd.isSolid()) { bld.setSolid(); } + if (bd.isAir()) { bld.setAir(); } + if (bd.is(BlockTags.OVERWORLD_NATURAL_LOGS)) { bld.setLog(); } + if (bd.is(BlockTags.LEAVES)) { bld.setLeaves(); } + // BlockBehaviour$BlockStateBase.getFluidState.isEmpty(), BlockBehaviour$BlockStateBase.getBlock + if (!bd.getFluidState().isEmpty() && !(bd.getBlock() instanceof LiquidBlock)) { // Test if fluid type for block is not empty + bld.setWaterlogged(); + //Log.info("statename=" + bname + "[" + sb + "] = waterlogged"); + } + DynmapBlockState dbs = bld.build(); // Build state + + dataToState.put(bd, dbs); + lastBlockState.put(bname, (lastbs == null) ? dbs : lastbs); + Log.verboseinfo("blk=" + bname + ", idx=" + idx + ", state=" + sb + ", waterlogged=" + dbs.isWaterlogged()); + } + } + /** + * Create chunk cache for given chunks of given world + * @param dw - world + * @param chunks - chunk list + * @return cache + */ + @Override + public MapChunkCache getChunkCache(BukkitWorld dw, List chunks) { + MapChunkCache26_1_2 c = new MapChunkCache26_1_2(gencache); + c.setChunks(dw, chunks); + return c; + } + + /** + * Get biome base water multiplier + */ + @Override + public int getBiomeBaseWaterMult(Object bb) { + Biome biome = (Biome) bb; + return biome.getWaterColor(); + } + + /** Get temperature from Biome */ + @Override + public float getBiomeBaseTemperature(Object bb) { + return ((Biome)bb).getBaseTemperature(); + } + + /** Get humidity from Biome */ + @Override + public float getBiomeBaseHumidity(Object bb) { + String vals = ((Biome)bb).climateSettings.toString(); + float humidity = 0.5F; + int idx = vals.indexOf("downfall="); + if (idx >= 0) { + humidity = Float.parseFloat(vals.substring(idx+9, vals.indexOf(']', idx))); + } + return humidity; + } + + @Override + public Polygon getWorldBorder(World world) { + Polygon p = null; + WorldBorder wb = world.getWorldBorder(); + if (wb != null) { + Location c = wb.getCenter(); + double size = wb.getSize(); + if ((size > 1) && (size < 1E7)) { + size = size / 2; + p = new Polygon(); + p.addVertex(c.getX()-size, c.getZ()-size); + p.addVertex(c.getX()+size, c.getZ()-size); + p.addVertex(c.getX()+size, c.getZ()+size); + p.addVertex(c.getX()-size, c.getZ()+size); + } + } + return p; + } + // Send title/subtitle to user + public void sendTitleText(Player p, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTIcks) { + if (p != null) { + p.sendTitle(title, subtitle, fadeInTicks, stayTicks, fadeOutTIcks); + } + } + + /** + * Get material map by block ID + */ + @Override + public BukkitMaterial[] getMaterialList() { + return new BukkitMaterial[4096]; // Not used + } + + @Override + public void unloadChunkNoSave(World w, Chunk c, int cx, int cz) { + Log.severe("unloadChunkNoSave not implemented"); + } + + private String[] biomenames; + @Override + public String[] getBiomeNames() { + if (biomenames == null) { + biomenames = new String[256]; + Iterator iter = getBiomeReg().iterator(); + while (iter.hasNext()) { + Biome b = iter.next(); + int bidx = getBiomeReg().getId(b); + if (bidx >= biomenames.length) { + biomenames = Arrays.copyOf(biomenames, bidx + biomenames.length); + } + biomenames[bidx] = b.toString(); + } + } + return biomenames; + } + + @Override + public String getStateStringByCombinedId(int blkid, int meta) { + Log.severe("getStateStringByCombinedId not implemented"); + return null; + } + @Override + /** Get ID string from Biome */ + public String getBiomeBaseIDString(Object bb) { + return getBiomeReg().getKey((Biome)bb).getPath(); + } + @Override + public String getBiomeBaseResourceLocsation(Object bb) { + return getBiomeReg().getKey((Biome)bb).toString(); + } + + @Override + public Object getUnloadQueue(World world) { + Log.warning("getUnloadQueue not implemented yet"); + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isInUnloadQueue(Object unloadqueue, int x, int z) { + Log.warning("isInUnloadQueue not implemented yet"); + // TODO Auto-generated method stub + return false; + } + + @Override + public Object[] getBiomeBaseFromSnapshot(ChunkSnapshot css) { + Log.warning("getBiomeFromSnapshot not implemented yet"); + // TODO Auto-generated method stub + return new Object[256]; + } + + @Override + public long getInhabitedTicks(Chunk c) { + return ((CraftChunk)c).getHandle(ChunkStatus.FULL).getInhabitedTime(); + } + + @Override + public Map getTileEntitiesForChunk(Chunk c) { + return ((CraftChunk)c).getHandle(ChunkStatus.FULL).blockEntities; + } + + @Override + public int getTileEntityX(Object te) { + BlockEntity tileent = (BlockEntity) te; + return tileent.getBlockPos().getX(); + } + + @Override + public int getTileEntityY(Object te) { + BlockEntity tileent = (BlockEntity) te; + return tileent.getBlockPos().getY(); + } + + @Override + public int getTileEntityZ(Object te) { + BlockEntity tileent = (BlockEntity) te; + return tileent.getBlockPos().getZ(); + } + + @Override + public Object readTileEntityNBT(Object te, World w) { + BlockEntity tileent = (BlockEntity) te; + CraftWorld cw = (CraftWorld) w; + return tileent.saveCustomOnly(cw.getHandle().registryAccess()); + } + + @Override + public Object getFieldValue(Object nbt, String field) { + CompoundTag rec = (CompoundTag) nbt; + Tag val = rec.get(field); + if(val == null) return null; + if(val instanceof ByteTag) { + return ((ByteTag)val).value(); + } + else if(val instanceof ShortTag) { + return ((ShortTag)val).value(); + } + else if(val instanceof IntTag) { + return ((IntTag)val).value(); + } + else if(val instanceof LongTag) { + return ((LongTag)val).value(); + } + else if(val instanceof FloatTag) { + return ((FloatTag)val).value(); + } + else if(val instanceof DoubleTag) { + return ((DoubleTag)val).value(); + } + else if(val instanceof ByteArrayTag) { + return ((ByteArrayTag)val).getAsByteArray(); + } + else if(val instanceof StringTag) { + return ((StringTag)val).value(); + } + else if(val instanceof IntArrayTag) { + return ((IntArrayTag)val).getAsIntArray(); + } + return null; + } + + @Override + public Player[] getOnlinePlayers() { + Collection p = Bukkit.getServer().getOnlinePlayers(); + return p.toArray(new Player[0]); + } + + @Override + public double getHealth(Player p) { + return p.getHealth(); + } + + private static final Gson gson = new GsonBuilder().create(); + + /** + * Get skin URL for player + * @param player + */ + @Override + public String getSkinURL(Player player) { + String url = null; + CraftPlayer cp = (CraftPlayer)player; + GameProfile profile = cp.getProfile(); + if (profile != null) { + PropertyMap pm = profile.properties(); + if (pm != null) { + Collection txt = pm.get("textures"); + Property textureProperty = Iterables.getFirst(pm.get("textures"), null); + if (textureProperty != null) { + String val = textureProperty.value(); + if (val != null) { + TexturesPayload result = null; + try { + String json = new String(Base64.getDecoder().decode(val), StandardCharsets.UTF_8); + result = gson.fromJson(json, TexturesPayload.class); + } catch (JsonParseException e) { + } catch (IllegalArgumentException x) { + Log.warning("Malformed response from skin URL check: " + val); + } + if ((result != null) && (result.textures != null) && (result.textures.containsKey("SKIN"))) { + url = result.textures.get("SKIN").url; + } + } + } + } + } + return url; + } + // Get minY for world + @Override + public int getWorldMinY(World w) { + CraftWorld cw = (CraftWorld) w; + return cw.getMinHeight(); + } + @Override + public boolean useGenericCache() { + return true; + } + +} diff --git a/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/MapChunkCache26_1_2.java b/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/MapChunkCache26_1_2.java new file mode 100644 index 00000000..ceff5028 --- /dev/null +++ b/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/MapChunkCache26_1_2.java @@ -0,0 +1,105 @@ +package org.dynmap.bukkit.helper.v26_1_2; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSpecialEffects; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.storage.SerializableChunkData; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.dynmap.DynmapChunk; +import org.dynmap.bukkit.helper.BukkitWorld; +import org.dynmap.common.BiomeMap; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericChunkCache; +import org.dynmap.common.chunk.GenericMapChunkCache; + +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +/** + * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread + */ +public class MapChunkCache26_1_2 extends GenericMapChunkCache { + private World w; + /** + * Construct empty cache + */ + public MapChunkCache26_1_2(GenericChunkCache cc) { + super(cc); + } + + @Override + protected Supplier getLoadedChunkAsync(DynmapChunk chunk) { + CompletableFuture> chunkData = CompletableFuture.supplyAsync(() -> { + CraftWorld cw = (CraftWorld) w; + LevelChunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); + if (c == null || !c.loaded) { + return Optional.empty(); + } + return Optional.of(SerializableChunkData.copyOf(cw.getHandle(), c)); + }, ((CraftServer) Bukkit.getServer()).getServer()); + return () -> chunkData.join().map(SerializableChunkData::write).map(NBT.NBTCompound::new).map(this::parseChunkFromNBT).orElse(null); + } + + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { + CraftWorld cw = (CraftWorld) w; + if (!cw.isChunkLoaded(chunk.x, chunk.z)) return null; + LevelChunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); + if (c == null || !c.loaded) return null; + SerializableChunkData chunkData = SerializableChunkData.copyOf(cw.getHandle(), c); + CompoundTag nbt = chunkData.write(); + return nbt != null ? parseChunkFromNBT(new NBT.NBTCompound(nbt)) : null; + } + + @Override + protected Supplier loadChunkAsync(DynmapChunk chunk) { + CraftWorld cw = (CraftWorld) w; + CompletableFuture> genericChunk = cw.getHandle().getChunkSource().chunkMap.read(new ChunkPos(chunk.x, chunk.z)); + return () -> genericChunk.join().map(NBT.NBTCompound::new).map(this::parseChunkFromNBT).orElse(null); + } + + protected GenericChunk loadChunk(DynmapChunk chunk) { + CraftWorld cw = (CraftWorld) w; + CompoundTag nbt = null; + ChunkPos cc = new ChunkPos(chunk.x, chunk.z); + GenericChunk gc = null; + try { // BUGBUG - convert this all to asyn properly, since now native async + nbt = cw.getHandle() + .getChunkSource() + .chunkMap + .read(cc) + .join().get(); + } catch (CancellationException cx) { + } catch (NoSuchElementException snex) { + } + if (nbt != null) { + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + } + return gc; + } + + public void setChunks(BukkitWorld dw, List chunks) { + this.w = dw.getWorld(); + super.setChunks(dw, chunks); + } + + @Override + public int getFoliageColor(BiomeMap bm, int[] colormap, int x, int z) { + return bm.getBiomeObject().map(Biome::getSpecialEffects).flatMap(BiomeSpecialEffects::foliageColorOverride).orElse(colormap[bm.biomeLookup()]); + } + + @Override + public int getGrassColor(BiomeMap bm, int[] colormap, int x, int z) { + BiomeSpecialEffects fog = bm.getBiomeObject().map(Biome::getSpecialEffects).orElse(null); + if (fog == null) return colormap[bm.biomeLookup()]; + return fog.grassColorModifier().modifyColor(x, z, fog.grassColorOverride().orElse(colormap[bm.biomeLookup()])); + } +} diff --git a/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/NBT.java b/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/NBT.java new file mode 100644 index 00000000..251bd2fd --- /dev/null +++ b/bukkit-helper-26-1-2/src/main/java/org/dynmap/bukkit/helper/v26_1_2/NBT.java @@ -0,0 +1,144 @@ +package org.dynmap.bukkit.helper.v26_1_2; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import java.util.Optional; +import java.util.Set; +import net.minecraft.nbt.Tag; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.util.SimpleBitStorage; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final CompoundTag obj; + public NBTCompound(CompoundTag t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.keySet(); + } + @Override + public boolean contains(String s) { + return obj.contains(s); + } + @Override + public boolean contains(String s, int i) { + // Like contains, but with an extra constraint on type + Tag base = obj.get(s); + if (base == null) + return false; + byte type = base.getId(); + if (type == i) + return true; + else if (i != TAG_ANY_NUMERIC) + return false; + return type == TAG_BYTE || type == TAG_SHORT || type == TAG_INT || type == TAG_LONG || type == TAG_FLOAT + || type == TAG_DOUBLE; + } + @Override + public byte getByte(String s) { + return obj.getByteOr(s, (byte)0); + } + @Override + public short getShort(String s) { + return obj.getShortOr(s, (short)0); + } + @Override + public int getInt(String s) { + return obj.getIntOr(s, 0); + } + @Override + public long getLong(String s) { + return obj.getLongOr(s, 0L); + } + @Override + public float getFloat(String s) { + return obj.getFloatOr(s, 0.0f); + } + @Override + public double getDouble(String s) { + return obj.getDoubleOr(s, 0.0); + } + @Override + public String getString(String s) { + return obj.getStringOr(s, ""); + } + @Override + public byte[] getByteArray(String s) { + Optional byteArr = obj.getByteArray(s); + return byteArr.orElseGet(() -> new byte[0]); + } + @Override + public int[] getIntArray(String s) { + Optional intArr = obj.getIntArray(s); + return intArr.orElseGet(() -> new int[0]); + } + @Override + public long[] getLongArray(String s) { + Optional longArr = obj.getLongArray(s); + return longArr.orElseGet(() -> new long[0]); + } + @Override + public GenericNBTCompound getCompound(String s) { + return new NBTCompound(obj.getCompoundOrEmpty(s)); + } + @Override + public GenericNBTList getList(String s, int i) { + // i argument used to be used to constrain list type, but nbt lists no longer have types as of 1.21.5 + return new NBTList(obj.getListOrEmpty(s)); + } + @Override + public boolean getBoolean(String s) { + return getByte(s) != 0; + } + @Override + public String getAsString(String s) { + return obj.get(s).asString().orElseGet(() -> ""); + } + @Override + public GenericBitStorage makeBitStorage(int bits, int count, long[] data) { + return new OurBitStorage(bits, count, data); + } + public String toString() { + return obj.toString(); + } + } + + public static class NBTList implements GenericNBTList { + private final ListTag obj; + public NBTList(ListTag t) { + obj = t; + } + @Override + public int size() { + return obj.size(); + } + @Override + public String getString(int idx) { + return obj.getStringOr(idx, ""); + } + @Override + public GenericNBTCompound getCompound(int idx) { + return new NBTCompound(obj.getCompoundOrEmpty(idx)); + } + public String toString() { + return obj.toString(); + } + } + + public static class OurBitStorage implements GenericBitStorage { + private final SimpleBitStorage bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new SimpleBitStorage(bits, count, data); + } + @Override + public int get(int idx) { + return bs.get(idx); + } + } +} diff --git a/doc/dev/new_spigot_version.md b/doc/dev/new_spigot_version.md new file mode 100644 index 00000000..abadfd24 --- /dev/null +++ b/doc/dev/new_spigot_version.md @@ -0,0 +1,26 @@ +# Develop a new spigot version + +This documentation gives the keys to implement a new spigot version for this project, step by step. + +## Get a new bukkit-helper version + +Firstly, take the last bukkit-helper version and copy it to a new folder called `bukkit-helper-`. You will need to update + +- The names of classes `BukkitVersionHelperSpigot.java` and `MapChunkCache` + - Add the appropriate project section: `project(':bukkit-helper-').projectDir = "$rootDir/" as File` +- Open `build.gradle` of the spigot project. Copy the project include from the last bukkit version. +- Update the `Helper.java` class inside the Spigot project. Follow the existing structure to ensure the right version is loaded. You can find the right version naming by starting your minecraft server. + +## Implement the bukkit-helper version + +Make the code changes necessary to ensure this new version is running with the current version of NMS. \ No newline at end of file diff --git a/doc/records/REC_0000_template.md b/doc/records/REC_0000_template.md new file mode 100644 index 00000000..9111d111 --- /dev/null +++ b/doc/records/REC_0000_template.md @@ -0,0 +1,12 @@ +# Title + +Date +Quick description + +# Context + +Why this decision must be made + +# Other options available + +When the decision record were written, what were the other options available ? Why making this decision and not the other available ? diff --git a/doc/records/REC_0001_switching_back_default_shadowJar_implem.md b/doc/records/REC_0001_switching_back_default_shadowJar_implem.md new file mode 100644 index 00000000..223f13c8 --- /dev/null +++ b/doc/records/REC_0001_switching_back_default_shadowJar_implem.md @@ -0,0 +1,17 @@ +# Switching back to the default implementation of gradle ShadowJar plugin + +02/05/2026 +Removing the `io.github.gooler.shadow` plugin and switch back to the official shadowJar plugin (`com.gradleup.shadow`) + +## Context + +After taking back the dynmap project, one of the first thing that I implemented was the 26.1 compatibility. +In the vision of upgrading the dynmap codebase, I choosed to switch to Java version 25. The old plugin was not updated anymore. Switching back to `com.gradleup.shadow` was mandatory in this context. + +> I don't know if updating java version was mandatory + +By doing so, I needed to update the import list because the syntax `include(dependency("commons-code::"))` using the double `:` seems to create bugs : The decompiled JAR didn't contain the included dependency. + +## Other options + +I could have stayed in Java 17 version. Why updating ? I want to upgrade the codebase to progressivly bring back codebase to the last versions. \ No newline at end of file diff --git a/forge-1.21.6/build.gradle b/forge-1.21.6/build.gradle index 75a3b9d1..78d142fd 100644 --- a/forge-1.21.6/build.gradle +++ b/forge-1.21.6/build.gradle @@ -9,7 +9,6 @@ buildscript { } } apply plugin: 'net.minecraftforge.gradle' -//apply plugin: 'com.github.johnrengelman.shadow' println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a793..dbc3ce4a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index 626b54d7..f31d17c6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,23 +12,18 @@ include ':spigot' include ':bukkit-helper-121-6' include ':bukkit-helper-121-10' include ':bukkit-helper-121-11' +include ":bukkit-helper-26-1-2" include ':bukkit-helper' include ':dynmap-api' include ':DynmapCore' include ':DynmapCoreAPI' -// include ':fabric-1.21.6' -// include ':fabric-1.21.11' -// include ':forge-1.21.6' project(':spigot').projectDir = "$rootDir/spigot" as File project(':bukkit-helper-121-6').projectDir = "$rootDir/bukkit-helper-121-6" as File project(':bukkit-helper-121-10').projectDir = "$rootDir/bukkit-helper-121-10" as File project(':bukkit-helper-121-11').projectDir = "$rootDir/bukkit-helper-121-11" as File +project(":bukkit-helper-26-1-2").projectDir = "$rootDir/bukkit-helper-26-1-2" as File project(':bukkit-helper').projectDir = "$rootDir/bukkit-helper" as File project(':dynmap-api').projectDir = "$rootDir/dynmap-api" as File project(':DynmapCore').projectDir = "$rootDir/DynmapCore" as File project(':DynmapCoreAPI').projectDir = "$rootDir/DynmapCoreAPI" as File -// project(':fabric-1.21.6').projectDir = "$rootDir/fabric-1.21.6" as File -// project(':fabric-1.21.11').projectDir = "$rootDir/fabric-1.21.11" as File -// project(':forge-1.21.6').projectDir = "$rootDir/forge-1.21.6" as File - diff --git a/spigot/build.gradle b/spigot/build.gradle index 55efe3a7..34d9ddd6 100644 --- a/spigot/build.gradle +++ b/spigot/build.gradle @@ -23,13 +23,14 @@ dependencies { compileOnly('de.bananaco:bPermissions:2.9.1') { transitive = false } compileOnly('com.platymuus.bukkit.permissions:PermissionsBukkit:1.6') { transitive = false } compileOnly('org.anjocaido:EssentialsGroupManager:2.10.1') { transitive = false } - implementation group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.2' + implementation group: 'org.bstats', name: 'bstats-bukkit', version: '3.2.1' + implementation group: 'org.bstats', name: 'bstats-base', version: '3.2.1' compileOnly('com.googlecode.json-simple:json-simple:1.1.1') { transitive = false } compileOnly('com.google.code.gson:gson:2.8.9') { transitive = false } implementation(project(':bukkit-helper')) { transitive = false } - implementation(project(':bukkit-helper-121-11')) { + implementation(project(':bukkit-helper-26-1-2')) { transitive = false } } @@ -51,21 +52,18 @@ jar { shadowJar { dependencies { - include(dependency('org.bstats::')) + include(dependency('org.bstats:bstats-base:')) + include(dependency('org.bstats:bstats-bukkit:')) include(dependency(':dynmap-api')) include(dependency(":DynmapCore")) include(dependency(':bukkit-helper')) - include(dependency(':bukkit-helper-121-11')) + include(dependency(':bukkit-helper-26-1-2')) } relocate('org.bstats', 'org.dynmap.bstats') destinationDirectory = file '../target' archiveBaseName = "Dynmap" archiveClassifier = 'spigot' } -shadowJar.doLast { - task -> - ant.checksum file: task.archivePath -} artifacts { archives shadowJar diff --git a/spigot/src/main/java/org/dynmap/bukkit/Helper.java b/spigot/src/main/java/org/dynmap/bukkit/Helper.java index 2a41f9dc..d82b031c 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/Helper.java +++ b/spigot/src/main/java/org/dynmap/bukkit/Helper.java @@ -49,6 +49,9 @@ else if (v.contains("(MC: 1.21.9)") || v.contains("(MC: 1.21.10)") || v.contains else if (v.contains("(MC: 1.21.11)") || v.contains("(MC: 1.21.11 Unobfuscated)")) { BukkitVersionHelper.helper = loadVersionHelper("org.dynmap.bukkit.helper.v121_11.BukkitVersionHelperSpigot121_11"); } + else if (v.contains("(MC: 26.1.2)") || v.contains("(MC: 26.1.1)") || v.contains("(MC: 26.1)")) { + BukkitVersionHelper.helper = loadVersionHelper("org.dynmap.bukkit.helper.v26_1_2.BukkitVersionHelperSpigot26_1_2"); + } else { BukkitVersionHelper.helper = loadVersionHelper("org.dynmap.bukkit.helper.BukkitVersionHelperCB"); }