diff --git a/API/build.gradle b/API/build.gradle index aaae920..cc9ddc0 100644 --- a/API/build.gradle +++ b/API/build.gradle @@ -1,3 +1,11 @@ +plugins { + id 'maven-publish' +} + +java { + withSourcesJar() +} + group 'API' dependencies { diff --git a/Hooks/Hook_EpicSpawners6/build.gradle b/Hooks/EpicSpawners6/build.gradle similarity index 100% rename from Hooks/Hook_EpicSpawners6/build.gradle rename to Hooks/EpicSpawners6/build.gradle diff --git a/Hooks/Hook_EpicSpawners6/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners6.java b/Hooks/EpicSpawners6/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners6.java similarity index 100% rename from Hooks/Hook_EpicSpawners6/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners6.java rename to Hooks/EpicSpawners6/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners6.java diff --git a/Hooks/Hook_EpicSpawners7/build.gradle b/Hooks/EpicSpawners7/build.gradle similarity index 93% rename from Hooks/Hook_EpicSpawners7/build.gradle rename to Hooks/EpicSpawners7/build.gradle index 31e10be..e76a03b 100644 --- a/Hooks/Hook_EpicSpawners7/build.gradle +++ b/Hooks/EpicSpawners7/build.gradle @@ -1,4 +1,4 @@ -group 'Hooks:EpicSpawners6' +group 'Hooks:EpicSpawners7' dependencies { compileOnly "com.songoda:EpicSpawners:7.0.2" diff --git a/Hooks/Hook_EpicSpawners7/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners7.java b/Hooks/EpicSpawners7/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners7.java similarity index 100% rename from Hooks/Hook_EpicSpawners7/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners7.java rename to Hooks/EpicSpawners7/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners7.java diff --git a/Hooks/EpicSpawners8/build.gradle b/Hooks/EpicSpawners8/build.gradle new file mode 100644 index 0000000..76e8b8c --- /dev/null +++ b/Hooks/EpicSpawners8/build.gradle @@ -0,0 +1,13 @@ +group 'Hooks:EpicSpawners8' + +dependencies { + compileOnly "com.songoda:EpicSpawners:8.1.0" + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('hook.compile_epicspawners8') && + !Boolean.valueOf(project.findProperty("hook.compile_epicspawners8").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/Hooks/EpicSpawners8/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners8.java b/Hooks/EpicSpawners8/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners8.java new file mode 100644 index 0000000..dd0b27c --- /dev/null +++ b/Hooks/EpicSpawners8/src/main/java/com/bgsoftware/wildloaders/hooks/TickableProvider_EpicSpawners8.java @@ -0,0 +1,59 @@ +package com.bgsoftware.wildloaders.hooks; + +import com.bgsoftware.wildloaders.api.hooks.TickableProvider; +import com.craftaro.epicspawners.api.EpicSpawnersApi; +import org.bukkit.Chunk; +import org.bukkit.Location; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class TickableProvider_EpicSpawners8 implements TickableProvider { + + private final Map spawnerDelays = new HashMap<>(); + + @Override + public void tick(Chunk[] chunks) { + if (EpicSpawnersApi.getSpawnerManager() == null) + return; + + List chunkList = Stream.of(chunks).map(chunk -> pair(chunk.getX(), chunk.getZ())).collect(Collectors.toList()); + + EpicSpawnersApi.getSpawnerManager().getSpawners().stream() + .filter(spawner -> chunkList.contains(pair(spawner.getX() >> 4, spawner.getZ() >> 4))) + .forEach(spawner -> { + Location location = spawner.getLocation(); + TickDelay tickDelay = spawnerDelays.get(location); + + if (tickDelay == null) { + spawnerDelays.put(location, new TickDelay(spawner.updateDelay())); + return; + } + + tickDelay.delay -= 1; + + if (tickDelay.delay <= 0) { + spawner.spawn(); + spawnerDelays.remove(location); + } + }); + } + + private long pair(int x, int z) { + return (x & 0xFFFFFFFFL) | (z & 0xFFFFFFFFL) << 32; + } + + private static final class TickDelay { + + private int delay; + + TickDelay(int delay) { + this.delay = delay; + } + + } + +} diff --git a/Hooks/Hook_FactionsUUID/build.gradle b/Hooks/FactionsUUID/build.gradle similarity index 100% rename from Hooks/Hook_FactionsUUID/build.gradle rename to Hooks/FactionsUUID/build.gradle diff --git a/Hooks/Hook_FactionsUUID/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsUUID.java b/Hooks/FactionsUUID/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsUUID.java similarity index 100% rename from Hooks/Hook_FactionsUUID/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsUUID.java rename to Hooks/FactionsUUID/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsUUID.java diff --git a/Hooks/Hook_FactionsX/build.gradle b/Hooks/FactionsX/build.gradle similarity index 100% rename from Hooks/Hook_FactionsX/build.gradle rename to Hooks/FactionsX/build.gradle diff --git a/Hooks/Hook_FactionsX/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsX.java b/Hooks/FactionsX/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsX.java similarity index 100% rename from Hooks/Hook_FactionsX/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsX.java rename to Hooks/FactionsX/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_FactionsX.java diff --git a/Hooks/Hook_Lands/build.gradle b/Hooks/Lands/build.gradle similarity index 100% rename from Hooks/Hook_Lands/build.gradle rename to Hooks/Lands/build.gradle diff --git a/Hooks/Hook_Lands/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_Lands.java b/Hooks/Lands/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_Lands.java similarity index 100% rename from Hooks/Hook_Lands/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_Lands.java rename to Hooks/Lands/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_Lands.java diff --git a/Hooks/Hook_MassiveFactions/build.gradle b/Hooks/MassiveFactions/build.gradle similarity index 100% rename from Hooks/Hook_MassiveFactions/build.gradle rename to Hooks/MassiveFactions/build.gradle diff --git a/Hooks/Hook_MassiveFactions/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_MassiveFactions.java b/Hooks/MassiveFactions/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_MassiveFactions.java similarity index 100% rename from Hooks/Hook_MassiveFactions/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_MassiveFactions.java rename to Hooks/MassiveFactions/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_MassiveFactions.java diff --git a/Hooks/Hook_SuperiorSkyblock/build.gradle b/Hooks/SuperiorSkyblock/build.gradle similarity index 100% rename from Hooks/Hook_SuperiorSkyblock/build.gradle rename to Hooks/SuperiorSkyblock/build.gradle diff --git a/Hooks/Hook_SuperiorSkyblock/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_SuperiorSkyblock.java b/Hooks/SuperiorSkyblock/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_SuperiorSkyblock.java similarity index 100% rename from Hooks/Hook_SuperiorSkyblock/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_SuperiorSkyblock.java rename to Hooks/SuperiorSkyblock/src/main/java/com/bgsoftware/wildloaders/hooks/ClaimsProvider_SuperiorSkyblock.java diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/NMSAdapter.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/NMSAdapter.java rename to NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/NMSAdapterImpl.java index 0026988..300a1cb 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/NMSAdapter.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/NMSAdapterImpl.java @@ -3,6 +3,7 @@ package com.bgsoftware.wildloaders.nms.v1_12_R1; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_12_R1.loader.TileEntityChunkLoader; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; @@ -23,7 +24,7 @@ import org.bukkit.craftbukkit.v1_12_R1.util.LongHash; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { private static final ReflectMethod TILE_ENTITY_LOAD = new ReflectMethod<>(TileEntity.class, "load", NBTTagCompound.class); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/loader/TileEntityChunkLoader.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/loader/TileEntityChunkLoader.java index 288b1f2..390904e 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/loader/TileEntityChunkLoader.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/wildloaders/nms/v1_12_R1/loader/TileEntityChunkLoader.java @@ -27,6 +27,7 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable public final List holograms = new ArrayList<>(); private final WChunkLoader chunkLoader; private final Block loaderBlock; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -40,6 +41,8 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable loaderBlock = world.getType(blockPosition).getBlock(); + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -117,9 +120,8 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable } private void updateName(EntityHolograms hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/NMSAdapter.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/NMSAdapter.java rename to NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/NMSAdapterImpl.java index 43b2a4f..1fe8c25 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/NMSAdapter.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/NMSAdapterImpl.java @@ -1,8 +1,8 @@ package com.bgsoftware.wildloaders.nms.v1_16_R3; -import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_16_R3.loader.TileEntityChunkLoader; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; @@ -24,7 +24,7 @@ import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) { diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/loader/TileEntityChunkLoader.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/loader/TileEntityChunkLoader.java index 7c818ec..8875802 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/loader/TileEntityChunkLoader.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_16_R3/loader/TileEntityChunkLoader.java @@ -28,6 +28,7 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable public final List holograms = new ArrayList<>(); private final WChunkLoader chunkLoader; private final Block loaderBlock; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -48,6 +49,8 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable } catch (Throwable ignored) { } + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -131,9 +134,8 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable } private void updateName(EntityHolograms hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/NMS/v1_17/build.gradle b/NMS/v1_17/build.gradle index 8915365..fd58971 100644 --- a/NMS/v1_17/build.gradle +++ b/NMS/v1_17/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.3.8" + id("io.papermc.paperweight.userdev") version "1.6.0" } java { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/NMSAdapter.java b/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/NMSAdapter.java rename to NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/NMSAdapterImpl.java index 73f1fe6..9747554 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/NMSAdapter.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/NMSAdapterImpl.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders.nms.v1_17; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_17.loader.ChunkLoaderBlockEntity; import com.bgsoftware.wildloaders.nms.v1_17.npc.ChunkLoaderNPCWrapper; import net.minecraft.core.BlockPos; @@ -24,7 +25,7 @@ import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String def) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/loader/ChunkLoaderBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/loader/ChunkLoaderBlockEntity.java index 71f3e63..1552acd 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/loader/ChunkLoaderBlockEntity.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/wildloaders/nms/v1_17/loader/ChunkLoaderBlockEntity.java @@ -30,6 +30,7 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn private final ChunkLoaderBlockEntityTicker ticker; private final ServerLevel serverLevel; private final BlockPos blockPos; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -47,6 +48,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn loaderBlock = serverLevel.getBlockState(blockPos).getBlock(); + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -133,9 +136,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn } private void updateName(EntityHologram hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/NMS/v1_18/build.gradle b/NMS/v1_18/build.gradle index 7c10c7b..fcf94d1 100644 --- a/NMS/v1_18/build.gradle +++ b/NMS/v1_18/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.3.8" + id("io.papermc.paperweight.userdev") version "1.6.0" } java { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/NMSAdapter.java b/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/NMSAdapter.java rename to NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/NMSAdapterImpl.java index 7e92783..5672bfb 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/NMSAdapter.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/NMSAdapterImpl.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders.nms.v1_18; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_18.loader.ChunkLoaderBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -23,7 +24,7 @@ import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String def) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/loader/ChunkLoaderBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/loader/ChunkLoaderBlockEntity.java index 8517e03..42d9524 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/loader/ChunkLoaderBlockEntity.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/wildloaders/nms/v1_18/loader/ChunkLoaderBlockEntity.java @@ -30,6 +30,7 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn private final ChunkLoaderBlockEntityTicker ticker; private final ServerLevel serverLevel; private final BlockPos blockPos; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -47,6 +48,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn loaderBlock = serverLevel.getBlockState(blockPos).getBlock(); + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -133,9 +136,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn } private void updateName(EntityHologram hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/NMS/v1_19/build.gradle b/NMS/v1_19/build.gradle index bb320b3..a92e995 100644 --- a/NMS/v1_19/build.gradle +++ b/NMS/v1_19/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.3.8" + id("io.papermc.paperweight.userdev") version "1.6.0" } java { diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/NMSAdapter.java b/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/NMSAdapter.java rename to NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/NMSAdapterImpl.java index 66a2ced..386bec5 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/NMSAdapter.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/NMSAdapterImpl.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders.nms.v1_19; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_19.loader.ChunkLoaderBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -22,7 +23,7 @@ import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String def) { diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/loader/ChunkLoaderBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/loader/ChunkLoaderBlockEntity.java index fa87a6f..979c641 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/loader/ChunkLoaderBlockEntity.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/wildloaders/nms/v1_19/loader/ChunkLoaderBlockEntity.java @@ -30,6 +30,7 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn private final ChunkLoaderBlockEntityTicker ticker; private final ServerLevel serverLevel; private final BlockPos blockPos; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -47,6 +48,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn loaderBlock = serverLevel.getBlockState(blockPos).getBlock(); + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -133,9 +136,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn } private void updateName(EntityHologram hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/NMS/v1_20_1/build.gradle b/NMS/v1_20_1/build.gradle index 52ec7c7..57cf5fa 100644 --- a/NMS/v1_20_1/build.gradle +++ b/NMS/v1_20_1/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.3.8" + id("io.papermc.paperweight.userdev") version "1.6.0" } java { diff --git a/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/NMSAdapter.java b/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/NMSAdapter.java rename to NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/NMSAdapterImpl.java index 2c7e550..2e90ef5 100644 --- a/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/NMSAdapter.java +++ b/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/NMSAdapterImpl.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders.nms.v1_20_1; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_20_1.loader.ChunkLoaderBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -22,7 +23,7 @@ import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String def) { diff --git a/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/loader/ChunkLoaderBlockEntity.java b/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/loader/ChunkLoaderBlockEntity.java index f343766..88aee63 100644 --- a/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/loader/ChunkLoaderBlockEntity.java +++ b/NMS/v1_20_1/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_1/loader/ChunkLoaderBlockEntity.java @@ -30,6 +30,7 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn private final ChunkLoaderBlockEntityTicker ticker; private final ServerLevel serverLevel; private final BlockPos blockPos; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -47,6 +48,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn loaderBlock = serverLevel.getBlockState(blockPos).getBlock(); + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -133,9 +136,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn } private void updateName(EntityHologram hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/NMS/v1_20_2/build.gradle b/NMS/v1_20_2/build.gradle index fcb0ca7..8c28c06 100644 --- a/NMS/v1_20_2/build.gradle +++ b/NMS/v1_20_2/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.3.8" + id("io.papermc.paperweight.userdev") version "1.6.0" } java { diff --git a/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/ChunkLoaderNPCImpl.java b/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/ChunkLoaderNPCImpl.java index 8905379..2b01030 100644 --- a/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/ChunkLoaderNPCImpl.java +++ b/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/ChunkLoaderNPCImpl.java @@ -64,9 +64,13 @@ public final class ChunkLoaderNPCImpl extends ServerPlayer implements ChunkLoade this.advancements = new DummyPlayerAdvancements(minecraftServer, this); SET_GAMEMODE.invoke(this.gameMode, GameType.CREATIVE, null); - setLoadViewDistance(2); - setTickViewDistance(2); - setSendViewDistance(2); + try { + setLoadViewDistance(2); + setTickViewDistance(2); + setSendViewDistance(2); + } catch (Throwable ignored) { + // Doesn't exist on Spigot + } fauxSleeping = true; @@ -136,7 +140,7 @@ public final class ChunkLoaderNPCImpl extends ServerPlayer implements ChunkLoade public class DummyServerGamePacketListenerImpl extends ServerGamePacketListenerImpl { DummyServerGamePacketListenerImpl(MinecraftServer minecraftServer, ServerPlayer serverPlayer) { - super(minecraftServer, new DummyConnection(), serverPlayer, CommonListenerCookie.createInitial(ChunkLoaderNPCImpl.this.gameProfile)); + super(minecraftServer, new DummyConnection(), serverPlayer, CommonListenerCookie.createInitial(ChunkLoaderNPCImpl.this.getGameProfile())); } @Override diff --git a/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/NMSAdapter.java b/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/NMSAdapter.java rename to NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/NMSAdapterImpl.java index 42ebd74..6f8ca17 100644 --- a/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/NMSAdapter.java +++ b/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/NMSAdapterImpl.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders.nms.v1_20_2; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_20_2.loader.ChunkLoaderBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -22,7 +23,7 @@ import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String def) { diff --git a/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/loader/ChunkLoaderBlockEntity.java b/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/loader/ChunkLoaderBlockEntity.java index 4961da0..c06756f 100644 --- a/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/loader/ChunkLoaderBlockEntity.java +++ b/NMS/v1_20_2/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_2/loader/ChunkLoaderBlockEntity.java @@ -30,6 +30,7 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn private final ChunkLoaderBlockEntityTicker ticker; private final ServerLevel serverLevel; private final BlockPos blockPos; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -47,6 +48,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn loaderBlock = serverLevel.getBlockState(blockPos).getBlock(); + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -133,9 +136,8 @@ public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEn } private void updateName(EntityHologram hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/NMS/v1_20_3/build.gradle b/NMS/v1_20_3/build.gradle new file mode 100644 index 0000000..c62db38 --- /dev/null +++ b/NMS/v1_20_3/build.gradle @@ -0,0 +1,36 @@ +plugins { + id("io.papermc.paperweight.userdev") version "1.6.0" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +group 'NMS:v1_20_3' + +dependencies { + paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.4-R0.1-SNAPSHOT") + compileOnly project(":API") + compileOnly rootProject +} + +shadowJar { + archiveFileName = "${project.name}-exclude.jar" +} + +assemble { + dependsOn(reobfJar) +} + +tasks { + reobfJar { + File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") + outputJar.set(layout.buildDirectory.file(outputFile.getPath())) + } +} + +if (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty("nms.compile_v1_20").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/ChunkLoaderNPCImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/ChunkLoaderNPCImpl.java new file mode 100644 index 0000000..c65ae02 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/ChunkLoaderNPCImpl.java @@ -0,0 +1,251 @@ +package com.bgsoftware.wildloaders.nms.v1_20_3; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC; +import com.bgsoftware.wildloaders.handlers.NPCHandler; +import com.bgsoftware.wildloaders.npc.DummyChannel; +import com.mojang.authlib.GameProfile; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.advancements.AdvancementProgress; +import net.minecraft.core.BlockPos; +import net.minecraft.network.Connection; +import net.minecraft.network.PacketListener; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.ServerboundChatPacket; +import net.minecraft.network.protocol.game.ServerboundContainerClickPacket; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket; +import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket; +import net.minecraft.network.protocol.game.ServerboundUseItemPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerAdvancements; +import net.minecraft.server.ServerAdvancementManager; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.storage.LevelResource; +import net.minecraft.world.phys.AABB; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.nio.file.Path; +import java.util.UUID; + +public final class ChunkLoaderNPCImpl extends ServerPlayer implements ChunkLoaderNPC { + + private static final ReflectMethod SET_GAMEMODE = new ReflectMethod<>(ServerPlayerGameMode.class, + 1, GameType.class, GameType.class); + + private final ServerLevel serverLevel; + private final AABB boundingBox; + private final PlayerAdvancements advancements; + + private boolean dieCall = false; + + public ChunkLoaderNPCImpl(MinecraftServer minecraftServer, Location location, UUID uuid) { + super(minecraftServer, ((CraftWorld) location.getWorld()).getHandle(), + new GameProfile(uuid, NPCHandler.getName(location.getWorld().getName())), + ClientInformation.createDefault()); + + this.serverLevel = serverLevel(); + this.boundingBox = new AABB(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + + this.connection = new DummyServerGamePacketListenerImpl(minecraftServer, this); + + this.advancements = new DummyPlayerAdvancements(minecraftServer, this); + + SET_GAMEMODE.invoke(this.gameMode, GameType.CREATIVE, null); + try { + setLoadViewDistance(2); + setTickViewDistance(2); + setSendViewDistance(2); + } catch (Throwable ignored) { + // Doesn't exist on Spigot + } + + fauxSleeping = true; + + spawnIn(this.serverLevel); + moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + this.serverLevel.addNewPlayer(this); + + super.setBoundingBox(this.boundingBox); + } + + @Override + public UUID getUniqueId() { + return super.getUUID(); + } + + @Override + public void die() { + discard(); + } + + @Override + public AABB getBoundingBoxForCulling() { + return this.boundingBox; + } + + @Override + public void remove(RemovalReason removalReason) { + if (!dieCall) { + dieCall = true; + this.serverLevel.removePlayerImmediately(this, RemovalReason.UNLOADED_WITH_PLAYER); + dieCall = false; + } else { + super.remove(removalReason); + } + } + + @Override + public Location getLocation() { + return getBukkitEntity().getLocation(); + } + + @Override + public Player getPlayer() { + return getBukkitEntity(); + } + + @Override + public PlayerAdvancements getAdvancements() { + return this.advancements; + } + + public static class DummyConnection extends Connection { + + DummyConnection() { + super(PacketFlow.SERVERBOUND); + this.channel = new DummyChannel(); + this.address = null; + } + + @Override + public void setListener(PacketListener packetListener) { + // Do nothing. + } + } + + public class DummyServerGamePacketListenerImpl extends ServerGamePacketListenerImpl { + + DummyServerGamePacketListenerImpl(MinecraftServer minecraftServer, ServerPlayer serverPlayer) { + super(minecraftServer, new DummyConnection(), serverPlayer, CommonListenerCookie.createInitial(ChunkLoaderNPCImpl.this.getGameProfile())); + } + + @Override + public void handleContainerClick(ServerboundContainerClickPacket containerClickPacket) { + // Do nothing. + } + + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket movePlayerPacket) { + // Do nothing. + } + + @Override + public void handleSignUpdate(ServerboundSignUpdatePacket signUpdatePacket) { + // Do nothing. + } + + @Override + public void handlePlayerAction(ServerboundPlayerActionPacket playerActionPacket) { + // Do nothing. + } + + @Override + public void handleUseItem(ServerboundUseItemPacket useItemPacket) { + // Do nothing. + } + + @Override + public void handleSetCarriedItem(ServerboundSetCarriedItemPacket setCarriedItemPacket) { + // Do nothing. + } + + @Override + public void handleChat(ServerboundChatPacket chatPacket) { + // Do nothing. + } + + @Override + public void disconnect(String s) { + // Do nothing. + } + + public void send(Packet packet) { + // Do nothing. + } + + } + + private static class DummyPlayerAdvancements extends PlayerAdvancements { + + DummyPlayerAdvancements(MinecraftServer server, ServerPlayer serverPlayer) { + super(server.getFixerUpper(), server.getPlayerList(), server.getAdvancements(), + getAdvancementsFile(server, serverPlayer), serverPlayer); + } + + private static Path getAdvancementsFile(MinecraftServer server, ServerPlayer serverPlayer) { + File advancementsDir = server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).toFile(); + return new File(advancementsDir, serverPlayer.getUUID() + ".json").toPath(); + } + + @Override + public void setPlayer(ServerPlayer owner) { + // Do nothing. + } + + @Override + public void stopListening() { + // Do nothing. + } + + @Override + public void reload(ServerAdvancementManager advancementLoader) { + // Do nothing. + } + + @Override + public void save() { + // Do nothing. + } + + @Override + public boolean award(AdvancementHolder advancement, String criterionName) { + return false; + } + + @Override + public boolean revoke(AdvancementHolder advancement, String criterionName) { + return false; + } + + @Override + public void flushDirty(ServerPlayer player) { + // Do nothing. + } + + @Override + public void setSelectedTab(@Nullable AdvancementHolder advancement) { + // Do nothing. + } + + @Override + public AdvancementProgress getOrStartProgress(AdvancementHolder advancement) { + return new AdvancementProgress(); + } + + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/EntityHologram.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/EntityHologram.java new file mode 100644 index 0000000..14e24dd --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/EntityHologram.java @@ -0,0 +1,165 @@ +package com.bgsoftware.wildloaders.nms.v1_20_3; + +import com.bgsoftware.wildloaders.api.holograms.Hologram; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftArmorStand; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; + +public final class EntityHologram extends ArmorStand implements Hologram { + + private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); + + private CraftEntity bukkitEntity; + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + + setInvisible(true); + setSmall(true); + setShowArms(false); + setNoGravity(true); + setNoBasePlate(true); + setMarker(true); + + super.collides = false; + super.setCustomNameVisible(true); // Custom name visible + super.setBoundingBox(EMPTY_BOUND); + } + + @Override + public void setHologramName(String name) { + super.setCustomName(CraftChatMessage.fromStringOrNull(name)); + } + + @Override + public void removeHologram() { + super.remove(RemovalReason.DISCARDED); + } + + @Override + public org.bukkit.entity.Entity getEntity() { + return getBukkitEntity(); + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean isInvulnerableTo(DamageSource source) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public boolean repositionEntityAfterLoad() { + return false; + } + + @Override + public void setCustomName(Component component) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean visible) { + // Locks the custom name. + } + + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + + @Override + public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silent) { + // Prevent stand being equipped + } + + @Override + public AABB getBoundingBoxForCulling() { + return EMPTY_BOUND; + } + + @Override + public void playSound(SoundEvent soundEvent, float volume, float pitch) { + // Remove sounds. + } + + @Override + public void remove(RemovalReason removalReason) { + // Prevent being killed. + } + + @Override + public CraftEntity getBukkitEntity() { + if (bukkitEntity == null) { + bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); + } + return bukkitEntity; + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/NMSAdapterImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/NMSAdapterImpl.java new file mode 100644 index 0000000..5d45b9b --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/NMSAdapterImpl.java @@ -0,0 +1,170 @@ +package com.bgsoftware.wildloaders.nms.v1_20_3; + +import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; +import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; +import com.bgsoftware.wildloaders.nms.v1_20_3.loader.ChunkLoaderBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; + +import java.util.UUID; + +public final class NMSAdapterImpl implements NMSAdapter { + + @Override + public String getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String def) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + CompoundTag compoundTag = itemStack.getTag(); + return compoundTag == null || !compoundTag.contains(key, 8) ? def : compoundTag.getString(key); + } + + @Override + public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String value) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + CompoundTag compoundTag = itemStack.getOrCreateTag(); + + compoundTag.putString(key, value); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + public long getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, long def) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + CompoundTag compoundTag = itemStack.getTag(); + return compoundTag == null || !compoundTag.contains(key, 4) ? def : compoundTag.getLong(key); + } + + @Override + public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack bukkitItem, String key, long value) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + CompoundTag compoundTag = itemStack.getOrCreateTag(); + + compoundTag.putLong(key, value); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + CompoundTag compoundTag = itemStack.getOrCreateTag(); + + CompoundTag skullOwner = compoundTag.contains("SkullOwner") ? + compoundTag.getCompound("SkullOwner") : new CompoundTag(); + + CompoundTag properties = new CompoundTag(); + ListTag textures = new ListTag(); + CompoundTag signature = new CompoundTag(); + + signature.putString("Value", texture); + textures.add(signature); + + properties.put("textures", textures); + + skullOwner.put("Properties", properties); + skullOwner.putString("Id", UUID.randomUUID().toString()); + + compoundTag.put("SkullOwner", skullOwner); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + public com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC createNPC(Location location, UUID uuid) { + return new ChunkLoaderNPCImpl(((CraftServer) Bukkit.getServer()).getServer(), location, uuid); + } + + @Override + public ITileEntityChunkLoader createLoader(ChunkLoader chunkLoader) { + Location loaderLoc = chunkLoader.getLocation(); + World bukkitWorld = loaderLoc.getWorld(); + + if (bukkitWorld == null) + throw new IllegalArgumentException("Cannot create loader in null world."); + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(loaderLoc.getBlockX(), loaderLoc.getBlockY(), loaderLoc.getBlockZ()); + + ChunkLoaderBlockEntity ChunkLoaderBlockEntity = new ChunkLoaderBlockEntity(chunkLoader, serverLevel, blockPos); + serverLevel.addBlockEntityTicker(ChunkLoaderBlockEntity.getTicker()); + + for (org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) { + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); + levelChunk.getBlockEntities().values().stream() + .filter(blockEntity -> blockEntity instanceof SpawnerBlockEntity) + .forEach(blockEntity -> { + ((SpawnerBlockEntity) blockEntity).getSpawner().requiredPlayerRange = -1; + }); + + ChunkPos chunkPos = levelChunk.getPos(); + serverLevel.setChunkForced(chunkPos.x, chunkPos.z, true); + } + + return ChunkLoaderBlockEntity; + } + + @Override + public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) { + Location loaderLoc = chunkLoader.getLocation(); + World bukkitWorld = loaderLoc.getWorld(); + + if (bukkitWorld == null) + throw new IllegalArgumentException("Cannot remove loader in null world."); + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(loaderLoc.getBlockX(), loaderLoc.getBlockY(), loaderLoc.getBlockZ()); + + long chunkPosLong = ChunkPos.asLong(blockPos.getX() >> 4, blockPos.getZ() >> 4); + ChunkLoaderBlockEntity chunkLoaderBlockEntity = ChunkLoaderBlockEntity.chunkLoaderBlockEntityMap.remove(chunkPosLong); + + if (chunkLoaderBlockEntity != null) { + chunkLoaderBlockEntity.holograms.forEach(EntityHologram::removeHologram); + chunkLoaderBlockEntity.removed = true; + } + + if (spawnParticle) + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + + for (org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) { + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); + levelChunk.getBlockEntities().values().stream() + .filter(blockEntity -> blockEntity instanceof SpawnerBlockEntity) + .forEach(blockEntity -> { + ((SpawnerBlockEntity) blockEntity).getSpawner().requiredPlayerRange = 16; + }); + + ChunkPos chunkPos = levelChunk.getPos(); + serverLevel.setChunkForced(chunkPos.x, chunkPos.z, false); + } + } + + @Override + public void updateSpawner(Location location, boolean reset) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + throw new IllegalArgumentException("Cannot remove loader in null world."); + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + if (blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity) + spawnerBlockEntity.getSpawner().requiredPlayerRange = reset ? 16 : -1; + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/loader/ChunkLoaderBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/loader/ChunkLoaderBlockEntity.java new file mode 100644 index 0000000..d5b0a4c --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/loader/ChunkLoaderBlockEntity.java @@ -0,0 +1,149 @@ +package com.bgsoftware.wildloaders.nms.v1_20_3.loader; + +import com.bgsoftware.wildloaders.api.holograms.Hologram; +import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; +import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.loaders.WChunkLoader; +import com.bgsoftware.wildloaders.nms.v1_20_3.EntityHologram; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEntityChunkLoader { + + public static final Map chunkLoaderBlockEntityMap = new HashMap<>(); + + public final List holograms = new ArrayList<>(); + private final WChunkLoader chunkLoader; + private final Block loaderBlock; + private final ChunkLoaderBlockEntityTicker ticker; + private final ServerLevel serverLevel; + private final BlockPos blockPos; + private final String cachedPlacerName; + + private short currentTick = 20; + private short daysAmount, hoursAmount, minutesAmount, secondsAmount; + public boolean removed = false; + + public ChunkLoaderBlockEntity(ChunkLoader chunkLoader, ServerLevel serverLevel, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, serverLevel.getBlockState(blockPos)); + + this.chunkLoader = (WChunkLoader) chunkLoader; + this.ticker = new ChunkLoaderBlockEntityTicker(this); + this.blockPos = blockPos; + this.serverLevel = serverLevel; + + setLevel(serverLevel); + + loaderBlock = serverLevel.getBlockState(blockPos).getBlock(); + + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + + if (!this.chunkLoader.isInfinite()) { + long timeLeft = chunkLoader.getTimeLeft(); + + daysAmount = (short) (timeLeft / 86400); + timeLeft = timeLeft % 86400; + + hoursAmount = (short) (timeLeft / 3600); + timeLeft = timeLeft % 3600; + + minutesAmount = (short) (timeLeft / 60); + timeLeft = timeLeft % 60; + + secondsAmount = (short) timeLeft; + } + + long chunkPosLong = ChunkPos.asLong(blockPos.getX() >> 4, blockPos.getZ() >> 4); + chunkLoaderBlockEntityMap.put(chunkPosLong, this); + + List hologramLines = this.chunkLoader.getHologramLines(); + + double currentY = blockPos.getY() + 1; + for (int i = hologramLines.size(); i > 0; i--) { + EntityHologram hologram = new EntityHologram(serverLevel, blockPos.getX() + 0.5, currentY, blockPos.getZ() + 0.5); + updateName(hologram, hologramLines.get(i - 1)); + serverLevel.addFreshEntity(hologram); + currentY += 0.23; + holograms.add(hologram); + } + } + + public void tick() { + if (removed || ++currentTick <= 20) + return; + + currentTick = 0; + + if (chunkLoader.isNotActive() || this.serverLevel.getBlockState(this.blockPos).getBlock() != loaderBlock) { + chunkLoader.remove(); + return; + } + + if (chunkLoader.isInfinite()) + return; + + List hologramLines = chunkLoader.getHologramLines(); + + int hologramsAmount = holograms.size(); + for (int i = hologramsAmount; i > 0; i--) { + EntityHologram hologram = holograms.get(hologramsAmount - i); + updateName(hologram, hologramLines.get(i - 1)); + } + + chunkLoader.tick(); + + if (!removed) { + secondsAmount--; + if (secondsAmount < 0) { + secondsAmount = 59; + minutesAmount--; + if (minutesAmount < 0) { + minutesAmount = 59; + hoursAmount--; + if (hoursAmount < 0) { + hoursAmount = 23; + daysAmount--; + } + } + } + } + } + + @Override + public Collection getHolograms() { + return Collections.unmodifiableList(holograms); + } + + @Override + public boolean isRemoved() { + return removed || super.isRemoved(); + } + + public ChunkLoaderBlockEntityTicker getTicker() { + return ticker; + } + + private void updateName(EntityHologram hologram, String line) { + hologram.setHologramName(line + .replace("{0}", this.cachedPlacerName) + .replace("{1}", daysAmount + "") + .replace("{2}", hoursAmount + "") + .replace("{3}", minutesAmount + "") + .replace("{4}", secondsAmount + "") + ); + } + +} + diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/loader/ChunkLoaderBlockEntityTicker.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/loader/ChunkLoaderBlockEntityTicker.java new file mode 100644 index 0000000..f919777 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_3/loader/ChunkLoaderBlockEntityTicker.java @@ -0,0 +1,30 @@ +package com.bgsoftware.wildloaders.nms.v1_20_3.loader; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +public record ChunkLoaderBlockEntityTicker( + ChunkLoaderBlockEntity chunkLoaderBlockEntity) implements TickingBlockEntity { + + @Override + public void tick() { + chunkLoaderBlockEntity.tick(); + } + + @Override + public boolean isRemoved() { + return chunkLoaderBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return chunkLoaderBlockEntity.getBlockPos(); + } + + @Override + public String getType() { + return BlockEntityType.getKey(chunkLoaderBlockEntity.getType()) + ""; + } + +} diff --git a/NMS/v1_20_4/build.gradle b/NMS/v1_20_4/build.gradle new file mode 100644 index 0000000..eefb5d1 --- /dev/null +++ b/NMS/v1_20_4/build.gradle @@ -0,0 +1,36 @@ +plugins { + id("io.papermc.paperweight.userdev") version "1.6.0" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +group 'NMS:v1_20_4' + +dependencies { + paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.6-R0.1-SNAPSHOT") + compileOnly project(":API") + compileOnly rootProject +} + +shadowJar { + archiveFileName = "${project.name}-exclude.jar" +} + +assemble { + dependsOn(reobfJar) +} + +tasks { + reobfJar { + File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") + outputJar.set(layout.buildDirectory.file(outputFile.getPath())) + } +} + +if (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty("nms.compile_v1_20").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/ChunkLoaderNPCImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/ChunkLoaderNPCImpl.java new file mode 100644 index 0000000..eac163a --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/ChunkLoaderNPCImpl.java @@ -0,0 +1,252 @@ +package com.bgsoftware.wildloaders.nms.v1_20_4; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC; +import com.bgsoftware.wildloaders.handlers.NPCHandler; +import com.bgsoftware.wildloaders.npc.DummyChannel; +import com.mojang.authlib.GameProfile; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.advancements.AdvancementProgress; +import net.minecraft.core.BlockPos; +import net.minecraft.network.Connection; +import net.minecraft.network.PacketListener; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.ServerboundChatPacket; +import net.minecraft.network.protocol.game.ServerboundContainerClickPacket; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket; +import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket; +import net.minecraft.network.protocol.game.ServerboundUseItemPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerAdvancements; +import net.minecraft.server.ServerAdvancementManager; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.storage.LevelResource; +import net.minecraft.world.phys.AABB; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.nio.file.Path; +import java.util.UUID; + +public final class ChunkLoaderNPCImpl extends ServerPlayer implements ChunkLoaderNPC { + + private static final ReflectMethod SET_GAMEMODE = new ReflectMethod<>(ServerPlayerGameMode.class, + 1, GameType.class, GameType.class); + + private final ServerLevel serverLevel; + private final AABB boundingBox; + private final PlayerAdvancements advancements; + + private boolean dieCall = false; + + public ChunkLoaderNPCImpl(MinecraftServer minecraftServer, Location location, UUID uuid) { + super(minecraftServer, ((CraftWorld) location.getWorld()).getHandle(), + new GameProfile(uuid, NPCHandler.getName(location.getWorld().getName())), + ClientInformation.createDefault()); + + this.serverLevel = serverLevel(); + this.boundingBox = new AABB(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + + this.connection = new DummyServerGamePacketListenerImpl(minecraftServer, this); + + this.advancements = new DummyPlayerAdvancements(minecraftServer, this); + + SET_GAMEMODE.invoke(this.gameMode, GameType.CREATIVE, null); + try { + setLoadViewDistance(2); + setTickViewDistance(2); + setSendViewDistance(2); + } catch (Throwable ignored) { + // Doesn't exist on Spigot + } + + fauxSleeping = true; + + spawnIn(this.serverLevel); + moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + this.serverLevel.addNewPlayer(this); + + super.setBoundingBox(this.boundingBox); + } + + @Override + public UUID getUniqueId() { + return super.getUUID(); + } + + @Override + public void die() { + discard(); + } + + @Override + public AABB getBoundingBoxForCulling() { + return this.boundingBox; + } + + @Override + public void remove(RemovalReason removalReason) { + if (!dieCall) { + dieCall = true; + this.serverLevel.removePlayerImmediately(this, RemovalReason.UNLOADED_WITH_PLAYER); + dieCall = false; + } else { + super.remove(removalReason); + } + } + + @Override + public Location getLocation() { + return getBukkitEntity().getLocation(); + } + + @Override + public Player getPlayer() { + return getBukkitEntity(); + } + + @Override + public PlayerAdvancements getAdvancements() { + return this.advancements; + } + + public static class DummyConnection extends Connection { + + DummyConnection() { + super(PacketFlow.SERVERBOUND); + this.channel = new DummyChannel(); + this.address = null; + } + + @Override + public void setListenerForServerboundHandshake(PacketListener packetListener) { + // Do nothing. + } + } + + public class DummyServerGamePacketListenerImpl extends ServerGamePacketListenerImpl { + + DummyServerGamePacketListenerImpl(MinecraftServer minecraftServer, ServerPlayer serverPlayer) { + super(minecraftServer, new DummyConnection(), serverPlayer, + CommonListenerCookie.createInitial(ChunkLoaderNPCImpl.this.getGameProfile(), false)); + } + + @Override + public void handleContainerClick(ServerboundContainerClickPacket containerClickPacket) { + // Do nothing. + } + + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket movePlayerPacket) { + // Do nothing. + } + + @Override + public void handleSignUpdate(ServerboundSignUpdatePacket signUpdatePacket) { + // Do nothing. + } + + @Override + public void handlePlayerAction(ServerboundPlayerActionPacket playerActionPacket) { + // Do nothing. + } + + @Override + public void handleUseItem(ServerboundUseItemPacket useItemPacket) { + // Do nothing. + } + + @Override + public void handleSetCarriedItem(ServerboundSetCarriedItemPacket setCarriedItemPacket) { + // Do nothing. + } + + @Override + public void handleChat(ServerboundChatPacket chatPacket) { + // Do nothing. + } + + @Override + public void disconnect(String s) { + // Do nothing. + } + + public void send(Packet packet) { + // Do nothing. + } + + } + + private static class DummyPlayerAdvancements extends PlayerAdvancements { + + DummyPlayerAdvancements(MinecraftServer server, ServerPlayer serverPlayer) { + super(server.getFixerUpper(), server.getPlayerList(), server.getAdvancements(), + getAdvancementsFile(server, serverPlayer), serverPlayer); + } + + private static Path getAdvancementsFile(MinecraftServer server, ServerPlayer serverPlayer) { + File advancementsDir = server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).toFile(); + return new File(advancementsDir, serverPlayer.getUUID() + ".json").toPath(); + } + + @Override + public void setPlayer(ServerPlayer owner) { + // Do nothing. + } + + @Override + public void stopListening() { + // Do nothing. + } + + @Override + public void reload(ServerAdvancementManager advancementLoader) { + // Do nothing. + } + + @Override + public void save() { + // Do nothing. + } + + @Override + public boolean award(AdvancementHolder advancement, String criterionName) { + return false; + } + + @Override + public boolean revoke(AdvancementHolder advancement, String criterionName) { + return false; + } + + @Override + public void flushDirty(ServerPlayer player) { + // Do nothing. + } + + @Override + public void setSelectedTab(@Nullable AdvancementHolder advancement) { + // Do nothing. + } + + @Override + public AdvancementProgress getOrStartProgress(AdvancementHolder advancement) { + return new AdvancementProgress(); + } + + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/EntityHologram.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/EntityHologram.java new file mode 100644 index 0000000..fb977c0 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/EntityHologram.java @@ -0,0 +1,165 @@ +package com.bgsoftware.wildloaders.nms.v1_20_4; + +import com.bgsoftware.wildloaders.api.holograms.Hologram; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftArmorStand; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftChatMessage; + +public final class EntityHologram extends ArmorStand implements Hologram { + + private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); + + private CraftEntity bukkitEntity; + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + + setInvisible(true); + setSmall(true); + setShowArms(false); + setNoGravity(true); + setNoBasePlate(true); + setMarker(true); + + super.collides = false; + super.setCustomNameVisible(true); // Custom name visible + super.setBoundingBox(EMPTY_BOUND); + } + + @Override + public void setHologramName(String name) { + super.setCustomName(CraftChatMessage.fromStringOrNull(name)); + } + + @Override + public void removeHologram() { + super.remove(RemovalReason.DISCARDED); + } + + @Override + public org.bukkit.entity.Entity getEntity() { + return getBukkitEntity(); + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean isInvulnerableTo(DamageSource source) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public boolean repositionEntityAfterLoad() { + return false; + } + + @Override + public void setCustomName(Component component) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean visible) { + // Locks the custom name. + } + + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + + @Override + public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silent) { + // Prevent stand being equipped + } + + @Override + public AABB getBoundingBoxForCulling() { + return EMPTY_BOUND; + } + + @Override + public void playSound(SoundEvent soundEvent, float volume, float pitch) { + // Remove sounds. + } + + @Override + public void remove(RemovalReason removalReason) { + // Prevent being killed. + } + + @Override + public CraftEntity getBukkitEntity() { + if (bukkitEntity == null) { + bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); + } + return bukkitEntity; + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/NMSAdapterImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/NMSAdapterImpl.java new file mode 100644 index 0000000..7837519 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/NMSAdapterImpl.java @@ -0,0 +1,176 @@ +package com.bgsoftware.wildloaders.nms.v1_20_4; + +import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; +import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; +import com.bgsoftware.wildloaders.nms.v1_20_4.loader.ChunkLoaderBlockEntity; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftItemStack; + +import java.util.Optional; +import java.util.UUID; + +public final class NMSAdapterImpl implements NMSAdapter { + + @Override + public String getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String def) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + CustomData customData = itemStack.get(DataComponents.CUSTOM_DATA); + if (customData != null) { + CompoundTag compoundTag = customData.getUnsafe(); + if (compoundTag.contains(key, 8)) + return compoundTag.getString(key); + } + return def; + } + + @Override + public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String value) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + CustomData customData = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); + customData = customData.update(compoundTag -> compoundTag.putString(key, value)); + itemStack.set(DataComponents.CUSTOM_DATA, customData); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + public long getTag(org.bukkit.inventory.ItemStack bukkitItem, String key, long def) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + CustomData customData = itemStack.get(DataComponents.CUSTOM_DATA); + if (customData != null) { + CompoundTag compoundTag = customData.getUnsafe(); + if (compoundTag.contains(key, 4)) + return compoundTag.getLong(key); + } + return def; + } + + @Override + public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack bukkitItem, String key, long value) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + CustomData customData = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); + customData = customData.update(compoundTag -> compoundTag.putLong(key, value)); + itemStack.set(DataComponents.CUSTOM_DATA, customData); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + PropertyMap propertyMap = new PropertyMap(); + propertyMap.put("textures", new Property("textures", texture)); + + ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + public com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC createNPC(Location location, UUID uuid) { + return new ChunkLoaderNPCImpl(((CraftServer) Bukkit.getServer()).getServer(), location, uuid); + } + + @Override + public ITileEntityChunkLoader createLoader(ChunkLoader chunkLoader) { + Location loaderLoc = chunkLoader.getLocation(); + World bukkitWorld = loaderLoc.getWorld(); + + if (bukkitWorld == null) + throw new IllegalArgumentException("Cannot create loader in null world."); + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(loaderLoc.getBlockX(), loaderLoc.getBlockY(), loaderLoc.getBlockZ()); + + ChunkLoaderBlockEntity ChunkLoaderBlockEntity = new ChunkLoaderBlockEntity(chunkLoader, serverLevel, blockPos); + serverLevel.addBlockEntityTicker(ChunkLoaderBlockEntity.getTicker()); + + for (org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) { + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); + levelChunk.getBlockEntities().values().stream() + .filter(blockEntity -> blockEntity instanceof SpawnerBlockEntity) + .forEach(blockEntity -> { + ((SpawnerBlockEntity) blockEntity).getSpawner().requiredPlayerRange = -1; + }); + + ChunkPos chunkPos = levelChunk.getPos(); + serverLevel.setChunkForced(chunkPos.x, chunkPos.z, true); + } + + return ChunkLoaderBlockEntity; + } + + @Override + public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) { + Location loaderLoc = chunkLoader.getLocation(); + World bukkitWorld = loaderLoc.getWorld(); + + if (bukkitWorld == null) + throw new IllegalArgumentException("Cannot remove loader in null world."); + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(loaderLoc.getBlockX(), loaderLoc.getBlockY(), loaderLoc.getBlockZ()); + + long chunkPosLong = ChunkPos.asLong(blockPos.getX() >> 4, blockPos.getZ() >> 4); + ChunkLoaderBlockEntity chunkLoaderBlockEntity = ChunkLoaderBlockEntity.chunkLoaderBlockEntityMap.remove(chunkPosLong); + + if (chunkLoaderBlockEntity != null) { + chunkLoaderBlockEntity.holograms.forEach(EntityHologram::removeHologram); + chunkLoaderBlockEntity.removed = true; + } + + if (spawnParticle) + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + + for (org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) { + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); + levelChunk.getBlockEntities().values().stream() + .filter(blockEntity -> blockEntity instanceof SpawnerBlockEntity) + .forEach(blockEntity -> { + ((SpawnerBlockEntity) blockEntity).getSpawner().requiredPlayerRange = 16; + }); + + ChunkPos chunkPos = levelChunk.getPos(); + serverLevel.setChunkForced(chunkPos.x, chunkPos.z, false); + } + } + + @Override + public void updateSpawner(Location location, boolean reset) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + throw new IllegalArgumentException("Cannot remove loader in null world."); + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + if (blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity) + spawnerBlockEntity.getSpawner().requiredPlayerRange = reset ? 16 : -1; + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/loader/ChunkLoaderBlockEntity.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/loader/ChunkLoaderBlockEntity.java new file mode 100644 index 0000000..dbd8252 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/loader/ChunkLoaderBlockEntity.java @@ -0,0 +1,149 @@ +package com.bgsoftware.wildloaders.nms.v1_20_4.loader; + +import com.bgsoftware.wildloaders.api.holograms.Hologram; +import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; +import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.loaders.WChunkLoader; +import com.bgsoftware.wildloaders.nms.v1_20_4.EntityHologram; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEntityChunkLoader { + + public static final Map chunkLoaderBlockEntityMap = new HashMap<>(); + + public final List holograms = new ArrayList<>(); + private final WChunkLoader chunkLoader; + private final Block loaderBlock; + private final ChunkLoaderBlockEntityTicker ticker; + private final ServerLevel serverLevel; + private final BlockPos blockPos; + private final String cachedPlacerName; + + private short currentTick = 20; + private short daysAmount, hoursAmount, minutesAmount, secondsAmount; + public boolean removed = false; + + public ChunkLoaderBlockEntity(ChunkLoader chunkLoader, ServerLevel serverLevel, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, serverLevel.getBlockState(blockPos)); + + this.chunkLoader = (WChunkLoader) chunkLoader; + this.ticker = new ChunkLoaderBlockEntityTicker(this); + this.blockPos = blockPos; + this.serverLevel = serverLevel; + + setLevel(serverLevel); + + loaderBlock = serverLevel.getBlockState(blockPos).getBlock(); + + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + + if (!this.chunkLoader.isInfinite()) { + long timeLeft = chunkLoader.getTimeLeft(); + + daysAmount = (short) (timeLeft / 86400); + timeLeft = timeLeft % 86400; + + hoursAmount = (short) (timeLeft / 3600); + timeLeft = timeLeft % 3600; + + minutesAmount = (short) (timeLeft / 60); + timeLeft = timeLeft % 60; + + secondsAmount = (short) timeLeft; + } + + long chunkPosLong = ChunkPos.asLong(blockPos.getX() >> 4, blockPos.getZ() >> 4); + chunkLoaderBlockEntityMap.put(chunkPosLong, this); + + List hologramLines = this.chunkLoader.getHologramLines(); + + double currentY = blockPos.getY() + 1; + for (int i = hologramLines.size(); i > 0; i--) { + EntityHologram hologram = new EntityHologram(serverLevel, blockPos.getX() + 0.5, currentY, blockPos.getZ() + 0.5); + updateName(hologram, hologramLines.get(i - 1)); + serverLevel.addFreshEntity(hologram); + currentY += 0.23; + holograms.add(hologram); + } + } + + public void tick() { + if (removed || ++currentTick <= 20) + return; + + currentTick = 0; + + if (chunkLoader.isNotActive() || this.serverLevel.getBlockState(this.blockPos).getBlock() != loaderBlock) { + chunkLoader.remove(); + return; + } + + if (chunkLoader.isInfinite()) + return; + + List hologramLines = chunkLoader.getHologramLines(); + + int hologramsAmount = holograms.size(); + for (int i = hologramsAmount; i > 0; i--) { + EntityHologram hologram = holograms.get(hologramsAmount - i); + updateName(hologram, hologramLines.get(i - 1)); + } + + chunkLoader.tick(); + + if (!removed) { + secondsAmount--; + if (secondsAmount < 0) { + secondsAmount = 59; + minutesAmount--; + if (minutesAmount < 0) { + minutesAmount = 59; + hoursAmount--; + if (hoursAmount < 0) { + hoursAmount = 23; + daysAmount--; + } + } + } + } + } + + @Override + public Collection getHolograms() { + return Collections.unmodifiableList(holograms); + } + + @Override + public boolean isRemoved() { + return removed || super.isRemoved(); + } + + public ChunkLoaderBlockEntityTicker getTicker() { + return ticker; + } + + private void updateName(EntityHologram hologram, String line) { + hologram.setHologramName(line + .replace("{0}", this.cachedPlacerName) + .replace("{1}", daysAmount + "") + .replace("{2}", hoursAmount + "") + .replace("{3}", minutesAmount + "") + .replace("{4}", secondsAmount + "") + ); + } + +} + diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/loader/ChunkLoaderBlockEntityTicker.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/loader/ChunkLoaderBlockEntityTicker.java new file mode 100644 index 0000000..3023867 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/wildloaders/nms/v1_20_4/loader/ChunkLoaderBlockEntityTicker.java @@ -0,0 +1,30 @@ +package com.bgsoftware.wildloaders.nms.v1_20_4.loader; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +public record ChunkLoaderBlockEntityTicker( + ChunkLoaderBlockEntity chunkLoaderBlockEntity) implements TickingBlockEntity { + + @Override + public void tick() { + chunkLoaderBlockEntity.tick(); + } + + @Override + public boolean isRemoved() { + return chunkLoaderBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return chunkLoaderBlockEntity.getBlockPos(); + } + + @Override + public String getType() { + return BlockEntityType.getKey(chunkLoaderBlockEntity.getType()) + ""; + } + +} diff --git a/NMS/v1_7_R4/src/main/java/com/bgsoftware/wildloaders/nms/v1_7_R4/NMSAdapter.java b/NMS/v1_7_R4/src/main/java/com/bgsoftware/wildloaders/nms/v1_7_R4/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_7_R4/src/main/java/com/bgsoftware/wildloaders/nms/v1_7_R4/NMSAdapter.java rename to NMS/v1_7_R4/src/main/java/com/bgsoftware/wildloaders/nms/v1_7_R4/NMSAdapterImpl.java index 81e2bfc..bfb44b8 100644 --- a/NMS/v1_7_R4/src/main/java/com/bgsoftware/wildloaders/nms/v1_7_R4/NMSAdapter.java +++ b/NMS/v1_7_R4/src/main/java/com/bgsoftware/wildloaders/nms/v1_7_R4/NMSAdapterImpl.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders.nms.v1_7_R4; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_7_R4.loader.TileEntityChunkLoader; import net.minecraft.server.v1_7_R4.Block; import net.minecraft.server.v1_7_R4.Chunk; @@ -21,7 +22,7 @@ import org.bukkit.craftbukkit.v1_7_R4.util.LongHash; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) { diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/NMSAdapter.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/NMSAdapterImpl.java similarity index 98% rename from NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/NMSAdapter.java rename to NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/NMSAdapterImpl.java index 7cc80ec..b988102 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/NMSAdapter.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/NMSAdapterImpl.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders.nms.v1_8_R3; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader; +import com.bgsoftware.wildloaders.nms.NMSAdapter; import com.bgsoftware.wildloaders.nms.v1_8_R3.loader.TileEntityChunkLoader; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; @@ -21,7 +22,7 @@ import org.bukkit.craftbukkit.v1_8_R3.util.LongHash; import java.util.UUID; -public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter { +public final class NMSAdapterImpl implements NMSAdapter { @Override public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) { diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/loader/TileEntityChunkLoader.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/loader/TileEntityChunkLoader.java index 96d2ae5..9fcffab 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/loader/TileEntityChunkLoader.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/wildloaders/nms/v1_8_R3/loader/TileEntityChunkLoader.java @@ -27,6 +27,7 @@ public final class TileEntityChunkLoader extends TileEntity implements IUpdatePl public final List holograms = new ArrayList<>(); private final WChunkLoader chunkLoader; private final Block loaderBlock; + private final String cachedPlacerName; private short currentTick = 20; private short daysAmount, hoursAmount, minutesAmount, secondsAmount; @@ -40,6 +41,8 @@ public final class TileEntityChunkLoader extends TileEntity implements IUpdatePl loaderBlock = world.getType(blockPosition).getBlock(); + this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse(""); + if (!this.chunkLoader.isInfinite()) { long timeLeft = chunkLoader.getTimeLeft(); @@ -117,9 +120,8 @@ public final class TileEntityChunkLoader extends TileEntity implements IUpdatePl } private void updateName(EntityHolograms hologram, String line) { - String placerName = Optional.ofNullable(chunkLoader.getWhoPlaced().getName()).orElse(""); hologram.setHologramName(line - .replace("{0}", placerName) + .replace("{0}", this.cachedPlacerName) .replace("{1}", daysAmount + "") .replace("{2}", hoursAmount + "") .replace("{3}", minutesAmount + "") diff --git a/build.gradle b/build.gradle index 9818ebd..a0d30a2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ plugins { id 'java' - id 'com.github.johnrengelman.shadow' version '7.1.2' + id 'io.github.goooler.shadow' version '8.1.7' id 'maven-publish' } group 'WildLoaders' -version = "2023.3" +version = "2024.1" project.ext { archiveFolder = file("archive/") @@ -16,7 +16,13 @@ project.ext { allprojects { apply plugin: 'java' - apply plugin: 'com.github.johnrengelman.shadow' + apply plugin: 'io.github.goooler.shadow' + + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(8)) + } + } repositories { maven { url 'https://repo.bg-software.com/repository/nms/' } @@ -26,7 +32,7 @@ allprojects { } dependencies { - compileOnly "com.bgsoftware.common.reflection:ReflectionUtils:latest" + compileOnly "com.bgsoftware.common.reflection:ReflectionUtils:b5" } task checkDebug() { @@ -51,13 +57,21 @@ subprojects { } } +repositories { + mavenCentral() +} + dependencies { implementation fileTree(rootProject.archiveFolder.getAbsolutePath()) implementation project(":API") - implementation 'com.bgsoftware.common.reflection:ReflectionUtils:latest' - implementation 'com.bgsoftware.common.config:CommentedConfiguration:1.0.3' + implementation 'com.bgsoftware.common.reflection:ReflectionUtils:b5' + implementation 'com.bgsoftware.common.updater:Updater:b1' + implementation 'com.bgsoftware.common.config:CommentedConfiguration:b1' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b4' + + implementation 'org.bstats:bstats-bukkit:3.0.0' // Spigot jars compileOnly "org.spigotmc:v1_8_R3:latest" @@ -86,6 +100,9 @@ processResources { shadowJar { dependsOn(jar) + relocate 'org.bstats', 'com.bgsoftware.wildloaders.libs.org.bstats' + relocate 'com.bgsoftware.common', 'com.bgsoftware.wildloaders.libs.com.bgsoftware.common' + archiveFileName = rootProject.name + "-" + rootProject.buildVersion + ".jar" delete fileTree(rootProject.targetFolder.getAbsolutePath()) @@ -97,7 +114,7 @@ shadowJar { configurations = [project.configurations.getByName("runtimeClasspath")] } -task copyAPI(type: Copy) { +task copyAPI(type: Copy, dependsOn: ':API:build') { from rootProject.archiveFolder.getAbsolutePath() + '/API.jar' into rootProject.targetFolder.getAbsolutePath() rename('API.jar', rootProject.name + 'API.jar') @@ -115,4 +132,8 @@ build { publish.shouldRunAfter shadowJar shadowJar.shouldRunAfter build -build.shouldRunAfter subprojects.build \ No newline at end of file +build.shouldRunAfter subprojects.build +clean.shouldRunAfter copyAPI + +shadowJar.dependsOn subprojects.build +compileJava.dependsOn childProjects.values().shadowJar \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa991fc..48c0a02 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle index 53466d7..ae955e2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,6 +11,7 @@ include 'API' include 'Hooks' include 'Hooks:EpicSpawners6' include 'Hooks:EpicSpawners7' +include 'Hooks:EpicSpawners8' include 'Hooks:FactionsUUID' include 'Hooks:FactionsX' include 'Hooks:Lands' @@ -26,5 +27,6 @@ include 'NMS:v1_18' include 'NMS:v1_19' include 'NMS:v1_20_1' include 'NMS:v1_20_2' -findProject(':NMS:v1_20_2')?.name = 'v1_20_2' +include 'NMS:v1_20_3' +include 'NMS:v1_20_4' diff --git a/src/main/java/com/bgsoftware/wildloaders/Updater.java b/src/main/java/com/bgsoftware/wildloaders/Updater.java deleted file mode 100644 index 3804143..0000000 --- a/src/main/java/com/bgsoftware/wildloaders/Updater.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.bgsoftware.wildloaders; - -import javax.net.ssl.HttpsURLConnection; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; - -public final class Updater { - - private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin(); - - private static String latestVersion, versionDescription; - - static{ - setLatestVersion(); - } - - //Just so no one would be able to call the constructor - private Updater(){} - - public static boolean isOutdated(){ - return !plugin.getDescription().getVersion().startsWith(latestVersion); - } - - public static String getLatestVersion(){ - return latestVersion; - } - - static String getVersionDescription(){ - return versionDescription; - } - - private static void setLatestVersion(){ - try { - HttpsURLConnection connection = (HttpsURLConnection) new URL("https://bg-software.com/versions.json").openConnection(); - - connection.setRequestMethod("GET"); - connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 (.NET CLR 3.5.30729)"); - connection.setDoInput(true); - - try(InputStream reader = connection.getInputStream()){ - Class jsonObjectClass, gsonClass; - - try{ - jsonObjectClass = Class.forName("net.minecraft.util.com.google.gson.JsonObject"); - gsonClass = Class.forName("net.minecraft.util.com.google.gson.Gson"); - }catch(ClassNotFoundException ex){ - jsonObjectClass = Class.forName("com.google.gson.JsonObject"); - gsonClass = Class.forName("com.google.gson.Gson"); - } - - Object jsonObject = gsonClass.getMethod("fromJson", Reader.class, Class.class) - .invoke(gsonClass.newInstance(), new InputStreamReader(reader), jsonObjectClass); - - Object jsonElement = jsonObjectClass.getMethod("get", String.class).invoke(jsonObject, "wildloaders"); - Object plugin = jsonElement.getClass().getMethod("getAsJsonObject").invoke(jsonElement); - - Object versionElement = plugin.getClass().getMethod("get", String.class).invoke(plugin, "version"); - Object descriptionElement = plugin.getClass().getMethod("get", String.class).invoke(plugin, "description"); - - latestVersion = (String) versionElement.getClass().getMethod("getAsString").invoke(versionElement); - versionDescription = (String) descriptionElement.getClass().getMethod("getAsString").invoke(descriptionElement); - } - } catch(Exception ex){ - //Something went wrong... - latestVersion = plugin.getDescription().getVersion(); - } - } - -} diff --git a/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java b/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java index 8d94f29..08fdfe8 100644 --- a/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java +++ b/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java @@ -1,6 +1,10 @@ package com.bgsoftware.wildloaders; -import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.common.dependencies.DependenciesManager; +import com.bgsoftware.common.nmsloader.INMSLoader; +import com.bgsoftware.common.nmsloader.NMSHandlersFactory; +import com.bgsoftware.common.nmsloader.NMSLoadException; +import com.bgsoftware.common.updater.Updater; import com.bgsoftware.wildloaders.api.WildLoaders; import com.bgsoftware.wildloaders.api.WildLoadersAPI; import com.bgsoftware.wildloaders.command.CommandsHandler; @@ -12,21 +16,18 @@ import com.bgsoftware.wildloaders.handlers.SettingsHandler; import com.bgsoftware.wildloaders.listeners.BlocksListener; import com.bgsoftware.wildloaders.listeners.ChunksListener; import com.bgsoftware.wildloaders.listeners.PlayersListener; -import com.bgsoftware.wildloaders.metrics.Metrics; import com.bgsoftware.wildloaders.nms.NMSAdapter; -import com.bgsoftware.wildloaders.utils.Pair; -import com.bgsoftware.wildloaders.utils.ServerVersion; import com.bgsoftware.wildloaders.utils.database.Database; +import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; -import org.bukkit.UnsafeValues; import org.bukkit.plugin.java.JavaPlugin; import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { + private final Updater updater = new Updater(this, "wildloaders"); + private static WildLoadersPlugin plugin; private SettingsHandler settingsHandler; @@ -42,7 +43,10 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { @Override public void onLoad() { plugin = this; - new Metrics(this); + + DependenciesManager.inject(this); + + new Metrics(this, 21732); shouldEnable = loadNMSAdapter(); loadAPI(); @@ -76,10 +80,10 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { Locale.reload(); - if (Updater.isOutdated()) { + if (updater.isOutdated()) { log(""); - log("A new version is available (v" + Updater.getLatestVersion() + ")!"); - log("Version's description: \"" + Updater.getVersionDescription() + "\""); + log("A new version is available (v" + updater.getLatestVersion() + ")!"); + log("Version's description: \"" + updater.getVersionDescription() + "\""); log(""); } @@ -96,50 +100,18 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { } private boolean loadNMSAdapter() { - String version = null; + try { + INMSLoader nmsLoader = NMSHandlersFactory.createNMSLoader(this); + this.nmsAdapter = nmsLoader.loadNMSHandler(NMSAdapter.class); - if (ServerVersion.isLessThan(ServerVersion.v1_17)) { - version = getServer().getClass().getPackage().getName().split("\\.")[3]; - } else { - ReflectMethod getDataVersion = new ReflectMethod<>(UnsafeValues.class, "getDataVersion"); - int dataVersion = getDataVersion.invoke(Bukkit.getUnsafe()); + return true; + } catch (NMSLoadException error) { + log("&cThe plugin doesn't support your minecraft version."); + log("&cPlease try a different version."); + error.printStackTrace(); - List> versions = Arrays.asList( - new Pair<>(2729, null), - new Pair<>(2730, "v1_17"), - new Pair<>(2974, null), - new Pair<>(2975, "v1_18"), - new Pair<>(3336, null), - new Pair<>(3337, "v1_19"), - new Pair<>(3465, "v1_20_1"), - new Pair<>(3578, "v1_20_2") - ); - - for (Pair versionData : versions) { - if (dataVersion <= versionData.first) { - version = versionData.second; - break; - } - } - - if (version == null) { - log("Data version: " + dataVersion); - } + return false; } - - if (version != null) { - try { - nmsAdapter = (NMSAdapter) Class.forName(String.format("com.bgsoftware.wildloaders.nms.%s.NMSAdapter", version)).newInstance(); - return true; - } catch (Exception error) { - error.printStackTrace(); - } - } - - log("&cThe plugin doesn't support your minecraft version."); - log("&cPlease try a different version."); - - return false; } private void loadAPI() { @@ -181,6 +153,10 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { return dataHandler; } + public Updater getUpdater() { + return updater; + } + public static void log(String message) { plugin.getLogger().info(message); } diff --git a/src/main/java/com/bgsoftware/wildloaders/handlers/ProvidersHandler.java b/src/main/java/com/bgsoftware/wildloaders/handlers/ProvidersHandler.java index 04d688f..4a1f7ae 100644 --- a/src/main/java/com/bgsoftware/wildloaders/handlers/ProvidersHandler.java +++ b/src/main/java/com/bgsoftware/wildloaders/handlers/ProvidersHandler.java @@ -60,12 +60,16 @@ public final class ProvidersHandler implements ProvidersManager { // Loading the tickable providers if (Bukkit.getPluginManager().isPluginEnabled("EpicSpawners")) { Plugin epicSpawners = Bukkit.getPluginManager().getPlugin("EpicSpawners"); - if (epicSpawners.getDescription().getVersion().startsWith("6")) { + String version = epicSpawners.getDescription().getVersion(); + if (version.startsWith("6")) { Optional tickableProvider = createInstance("TickableProvider_EpicSpawners6"); tickableProvider.ifPresent(this::addTickableProvider); - } else { + } else if(version.startsWith("7")) { Optional tickableProvider = createInstance("TickableProvider_EpicSpawners7"); tickableProvider.ifPresent(this::addTickableProvider); + } else { + Optional tickableProvider = createInstance("TickableProvider_EpicSpawners8"); + tickableProvider.ifPresent(this::addTickableProvider); } } } diff --git a/src/main/java/com/bgsoftware/wildloaders/listeners/PlayersListener.java b/src/main/java/com/bgsoftware/wildloaders/listeners/PlayersListener.java index 9ff28fe..1f14a16 100644 --- a/src/main/java/com/bgsoftware/wildloaders/listeners/PlayersListener.java +++ b/src/main/java/com/bgsoftware/wildloaders/listeners/PlayersListener.java @@ -1,6 +1,5 @@ package com.bgsoftware.wildloaders.listeners; -import com.bgsoftware.wildloaders.Updater; import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC; import com.bgsoftware.wildloaders.utils.threads.Executor; @@ -37,9 +36,9 @@ public final class PlayersListener implements Listener { ChatColor.GRAY + "This server is using WildLoaders v" + plugin.getDescription().getVersion()), 5L); } - if (e.getPlayer().isOp() && Updater.isOutdated()) { + if (e.getPlayer().isOp() && plugin.getUpdater().isOutdated()) { Executor.sync(() -> e.getPlayer().sendMessage(ChatColor.GREEN + "" + ChatColor.BOLD + "WildLoaders" + - ChatColor.GRAY + " A new version is available (v" + Updater.getLatestVersion() + ")!"), 20L); + ChatColor.GRAY + " A new version is available (v" + plugin.getUpdater().getLatestVersion() + ")!"), 20L); } } diff --git a/src/main/java/com/bgsoftware/wildloaders/metrics/Metrics.java b/src/main/java/com/bgsoftware/wildloaders/metrics/Metrics.java deleted file mode 100644 index 0a86b92..0000000 --- a/src/main/java/com/bgsoftware/wildloaders/metrics/Metrics.java +++ /dev/null @@ -1,707 +0,0 @@ -package com.bgsoftware.wildloaders.metrics; - -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.ServicePriority; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import javax.net.ssl.HttpsURLConnection; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; - -/** - * bStats collects some data for plugin authors. - *

- * Check out https://bStats.org/ to learn more about bStats! - */ -@SuppressWarnings("all") -public class Metrics { - - static { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D - final String defaultPackage = new String( - new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); - final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); - // We want to make sure nobody just copy & pastes the example and use the wrong package names - if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - } - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bukkit"; - - // Is bStats enabled on this server? - private boolean enabled; - - // Should failed requests be logged? - private static boolean logFailedRequests; - - // Should the sent data be logged? - private static boolean logSentData; - - // Should the response text be logged? - private static boolean logResponseStatusText; - - // The uuid of the server - private static String serverUUID; - - // The plugin - private final Plugin plugin; - - // A list with all custom charts - private final List charts = new ArrayList<>(); - - /** - * Class constructor. - * - * @param plugin The plugin which stats should be submitted. - */ - public Metrics(Plugin plugin) { - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null!"); - } - this.plugin = plugin; - - // Get the config file - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - File configFile = new File(bStatsFolder, "config.yml"); - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - - // Check if the config file exists - if (!config.isSet("serverUuid")) { - - // Add default values - config.addDefault("enabled", true); - // Every server gets it's unique random id. - config.addDefault("serverUuid", UUID.randomUUID().toString()); - // Should failed request be logged? - config.addDefault("logFailedRequests", false); - // Should the sent data be logged? - config.addDefault("logSentData", false); - // Should the response text be logged? - config.addDefault("logResponseStatusText", false); - - // Inform the server owners about bStats - config.options().header( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + - "To honor their work, you should not disable it.\n" + - "This has nearly no effect on the server performance!\n" + - "Check out https://bStats.org/ to learn more :)" - ).copyDefaults(true); - try { - config.save(configFile); - } catch (IOException ignored) { } - } - - // Load the data - enabled = config.getBoolean("enabled", true); - serverUUID = config.getString("serverUuid"); - logFailedRequests = config.getBoolean("logFailedRequests", false); - logSentData = config.getBoolean("logSentData", false); - logResponseStatusText = config.getBoolean("logResponseStatusText", false); - - if (enabled) { - boolean found = false; - // Search for all other bStats Metrics classes to see if we are the first one - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - found = true; // We aren't the first - break; - } catch (NoSuchFieldException ignored) { } - } - // Register our service - Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); - if (!found) { - // We are the first! - startSubmitting(); - } - } - } - - /** - * Checks if bStats is enabled. - * - * @return Whether bStats is enabled or not. - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - if (chart == null) { - throw new IllegalArgumentException("Chart cannot be null!"); - } - charts.add(chart); - } - - /** - * Starts the Scheduler which submits our data every 30 minutes. - */ - private void startSubmitting() { - final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - if (!plugin.isEnabled()) { // Plugin was disabled - timer.cancel(); - return; - } - // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler - // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) - Bukkit.getScheduler().runTask(plugin, () -> submitData()); - } - }, 1000 * 60 * 5, 1000 * 60 * 30); - // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start - // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! - // WARNING: Just don't do it! - } - - /** - * Gets the plugin specific data. - * This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JSONObject getPluginData() { - JSONObject data = new JSONObject(); - - String pluginName = plugin.getDescription().getName(); - String pluginVersion = plugin.getDescription().getVersion(); - - data.put("pluginName", pluginName); // Append the name of the plugin - data.put("pluginVersion", pluginVersion); // Append the version of the plugin - JSONArray customCharts = new JSONArray(); - for (CustomChart customChart : charts) { - // Add the data of the custom charts - JSONObject chart = customChart.getRequestJsonObject(); - if (chart == null) { // If the chart is null, we skip it - continue; - } - customCharts.add(chart); - } - data.put("customCharts", customCharts); - - return data; - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JSONObject getServerData() { - // Minecraft specific data - int playerAmount; - try { - // Around MC 1.8 the return type was changed to a collection from an array, - // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; - Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); - playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) - ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() - : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; - } catch (Exception e) { - playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed - } - int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; - String bukkitVersion = Bukkit.getVersion(); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JSONObject data = new JSONObject(); - - data.put("serverUUID", serverUUID); - - data.put("playerAmount", playerAmount); - data.put("onlineMode", onlineMode); - data.put("bukkitVersion", bukkitVersion); - - data.put("javaVersion", javaVersion); - data.put("osName", osName); - data.put("osArch", osArch); - data.put("osVersion", osVersion); - data.put("coreCount", coreCount); - - return data; - } - - /** - * Collects the data and sends it afterwards. - */ - private void submitData() { - final JSONObject data = getServerData(); - - JSONArray pluginData = new JSONArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - - for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { - try { - pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider())); - } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } - } - } catch (NoSuchFieldException ignored) { } - } - - data.put("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread(new Runnable() { - @Override - public void run() { - try { - // Send the data - sendData(plugin, data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); - } - } - } - }).start(); - } - - /** - * Sends the data to the bStats server. - * - * @param plugin Any plugin. It's just used to get a logger instance. - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(Plugin plugin, JSONObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null!"); - } - if (Bukkit.isPrimaryThread()) { - throw new IllegalAccessException("This method must not be called from the main thread!"); - } - if (logSentData) { - plugin.getLogger().info("Sending data to bStats: " + data.toString()); - } - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); - outputStream.write(compressedData); - outputStream.flush(); - outputStream.close(); - - InputStream inputStream = connection.getInputStream(); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); - - StringBuilder builder = new StringBuilder(); - String line; - while ((line = bufferedReader.readLine()) != null) { - builder.append(line); - } - bufferedReader.close(); - if (logResponseStatusText) { - plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString()); - } - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - gzip.write(str.getBytes(StandardCharsets.UTF_8)); - gzip.close(); - return outputStream.toByteArray(); - } - - /** - * Represents a custom chart. - */ - public static abstract class CustomChart { - - // The id of the chart - final String chartId; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - */ - CustomChart(String chartId) { - if (chartId == null || chartId.isEmpty()) { - throw new IllegalArgumentException("ChartId cannot be null or empty!"); - } - this.chartId = chartId; - } - - private JSONObject getRequestJsonObject() { - JSONObject chart = new JSONObject(); - chart.put("chartId", chartId); - try { - JSONObject data = getChartData(); - if (data == null) { - // If the data is null we don't send the chart. - return null; - } - chart.put("data", data); - } catch (Throwable t) { - if (logFailedRequests) { - Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); - } - return null; - } - return chart; - } - - protected abstract JSONObject getChartData() throws Exception; - - } - - /** - * Represents a custom simple pie. - */ - public static class SimplePie extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimplePie(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - String value = callable.call(); - if (value == null || value.isEmpty()) { - // Null = skip the chart - return null; - } - data.put("value", value); - return data; - } - } - - /** - * Represents a custom advanced pie. - */ - public static class AdvancedPie extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedPie(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.put(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - - /** - * Represents a custom drilldown pie. - */ - public static class DrilldownPie extends CustomChart { - - private final Callable>> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public DrilldownPie(String chartId, Callable>> callable) { - super(chartId); - this.callable = callable; - } - - @Override - public JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map> map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JSONObject value = new JSONObject(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - value.put(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - values.put(entryValues.getKey(), value); - } - } - if (reallyAllSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - - /** - * Represents a custom single line chart. - */ - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - data.put("value", value); - return data; - } - - } - - /** - * Represents a custom multi line chart. - */ - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.put(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - - } - - /** - * Represents a custom simple bar chart. - */ - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - JSONArray categoryValues = new JSONArray(); - categoryValues.add(entry.getValue()); - values.put(entry.getKey(), categoryValues); - } - data.put("values", values); - return data; - } - - } - - /** - * Represents a custom advanced bar chart. - */ - public static class AdvancedBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - continue; // Skip this invalid - } - allSkipped = false; - JSONArray categoryValues = new JSONArray(); - for (int categoryValue : entry.getValue()) { - categoryValues.add(categoryValue); - } - values.put(entry.getKey(), categoryValues); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - -} \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/wildloaders/utils/ServerVersion.java b/src/main/java/com/bgsoftware/wildloaders/utils/ServerVersion.java index 31967a8..53a68ef 100644 --- a/src/main/java/com/bgsoftware/wildloaders/utils/ServerVersion.java +++ b/src/main/java/com/bgsoftware/wildloaders/utils/ServerVersion.java @@ -24,9 +24,9 @@ public enum ServerVersion { private static final boolean legacy; static { - bukkitVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; - String[] sections = bukkitVersion.split("_"); - currentVersion = ServerVersion.valueOf(sections[0] + "_" + sections[1]); + bukkitVersion = Bukkit.getBukkitVersion().split("-")[0]; + String[] sections = bukkitVersion.split("\\."); + currentVersion = ServerVersion.valueOf("v" + sections[0] + "_" + sections[1]); legacy = isLessThan(ServerVersion.v1_13); } diff --git a/src/main/java/com/bgsoftware/wildloaders/utils/database/DatabaseQueue.java b/src/main/java/com/bgsoftware/wildloaders/utils/database/DatabaseQueue.java index b759d37..9313f23 100644 --- a/src/main/java/com/bgsoftware/wildloaders/utils/database/DatabaseQueue.java +++ b/src/main/java/com/bgsoftware/wildloaders/utils/database/DatabaseQueue.java @@ -21,11 +21,11 @@ public final class DatabaseQueue { private static final Map> alreadyObjectsCalled = new ConcurrentHashMap<>(); private static final AtomicInteger currentIndex = new AtomicInteger(0); - public static void queue(Object caller, QueryParameters parameters){ + public static void queue(Object caller, QueryParameters parameters) { Map queryCalls = alreadyObjectsCalled.computeIfAbsent(parameters.getQuery(), q -> new ConcurrentHashMap<>()); Integer existingParametersIndex = queryCalls.get(caller); - if(existingParametersIndex != null) + if (existingParametersIndex != null) queuedCalls.remove(existingParametersIndex); int currentIndex = DatabaseQueue.currentIndex.getAndIncrement(); @@ -38,19 +38,37 @@ public final class DatabaseQueue { queueService.scheduleAtFixedRate(DatabaseQueue::processQueue, QUEUE_INTERVAL, QUEUE_INTERVAL, TimeUnit.SECONDS); } - static void stop(){ + static void stop() { // Stopping the queue timer, and calling the process queue manually - queueService.shutdownNow(); + shutdownAndAwaitTermination(); processQueue(); } - private static void processQueue(){ + private static void shutdownAndAwaitTermination() { + queueService.shutdown(); // Disable new tasks from being submitted + try { + // Wait a while for existing tasks to terminate + if (!queueService.awaitTermination(60, TimeUnit.SECONDS)) { + queueService.shutdownNow(); // Cancel currently executing tasks + // Wait a while for tasks to respond to being cancelled + if (!queueService.awaitTermination(60, TimeUnit.SECONDS)) + System.err.println("Pool did not terminate"); + } + } catch (InterruptedException ie) { + // (Re-)Cancel if current thread also interrupted + queueService.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } + } + + private static void processQueue() { int currentIndex = DatabaseQueue.currentIndex.getAndSet(0); - if(currentIndex > 0) { + if (currentIndex > 0) { Map preparedStatementMap = new EnumMap<>(Query.class); Connection connection = Database.getConnection(); - for(int i = 0; i < currentIndex; i++){ + for (int i = 0; i < currentIndex; i++) { try { QueryParameters parameters = queuedCalls.get(i); @@ -71,15 +89,15 @@ public final class DatabaseQueue { preparedStatement.executeUpdate(); preparedStatement.clearParameters(); } - }catch (Exception ex){ + } catch (Exception ex) { ex.printStackTrace(); } } preparedStatementMap.values().forEach(preparedStatement -> { - try{ + try { preparedStatement.close(); - }catch (Exception ex){ + } catch (Exception ex) { ex.printStackTrace(); } }); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index fdd29ac..3f98d89 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,19 +1,24 @@ name: WildLoaders version: ${project.version} -api-version: 1.13 main: com.bgsoftware.wildloaders.WildLoadersPlugin + description: Highly configurable and optimized chunk-loaders plugin. website: https://bg-software.com/ -authors: [Ome_R] -softdepend: +api-version: 1.13 +author: Ome_R + +# Custom section used by DependenciesManager, which replaces softdepend. +class-depends: - EpicSpawners - Factions - FactionsX - Lands - SuperiorSkyblock2 + commands: loader: description: Main command for wild loaders. + permissions: wildloaders.*: description: Gives access to all the commands.