Compare commits
53 Commits
Author | SHA1 | Date |
---|---|---|
OmerBenGera | 7657949441 | |
OmerBenGera | 2bcc77a115 | |
OmerBenGera | 60d68b7b80 | |
OmerBenGera | 9a0c852b35 | |
OmerBenGera | 6ec87b736f | |
OmerBenGera | adcbffe853 | |
OmerBenGera | ed6932b903 | |
OmerBenGera | a9c1541013 | |
Ome_R | 3d021891a8 | |
OmerBenGera | a07499aa66 | |
OmerBenGera | 901f630d89 | |
OmerBenGera | 2b05c098d5 | |
OmerBenGera | dcd20b0245 | |
OmerBenGera | 6d1adf07cc | |
OmerBenGera | acafffd6a8 | |
OmerBenGera | 3bd4b37958 | |
OmerBenGera | a131f95a20 | |
OmerBenGera | aded0e8b06 | |
OmerBenGera | b5f80816c3 | |
OmerBenGera | 9f65c62a0c | |
OmerBenGera | eddaf54c99 | |
OmerBenGera | 6ba614dab1 | |
OmerBenGera | 264666d974 | |
OmerBenGera | 7396fd7b41 | |
OmerBenGera | 6a23928c55 | |
OmerBenGera | 6a88e4ac18 | |
OmerBenGera | c64e6b2342 | |
OmerBenGera | 740b24b9e9 | |
OmerBenGera | d850a9bdf4 | |
OmerBenGera | ddb36f8d28 | |
OmerBenGera | 7da9f07005 | |
OmerBenGera | b8400695ba | |
OmerBenGera | a137e258b7 | |
OmerBenGera | 1d3df3e171 | |
OmerBenGera | 5efb72564e | |
OmerBenGera | 2df28a1bab | |
OmerBenGera | 22d8f0d1fb | |
OmerBenGera | 6e0d1fa310 | |
OmerBenGera | 5ae2876a61 | |
OmerBenGera | a891a18ee9 | |
OmerBenGera | db2b49fbde | |
OmerBenGera | 19e383ad0b | |
OmerBenGera | cad5d1ada5 | |
OmerBenGera | 3fd922a027 | |
OmerBenGera | 4d91255bac | |
OmerBenGera | 0094475513 | |
OmerBenGera | 67af75f37a | |
OmerBenGera | a76ed53ee7 | |
OmerBenGera | 4dd84d53be | |
OmerBenGera | 4ee9bc0960 | |
OmerBenGera | c0829d8e19 | |
OmerBenGera | 723558145c | |
OmerBenGera | a13e760e8b |
|
@ -1,3 +1,11 @@
|
|||
plugins {
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
group 'API'
|
||||
|
||||
dependencies {
|
||||
|
@ -16,8 +24,8 @@ publishing {
|
|||
}
|
||||
|
||||
repositories {
|
||||
String mavenUsername = System.getenv('mavenUsername') == null ? project.mavenUsername : System.getenv('mavenUsername');
|
||||
String mavenPassword = System.getenv('mavenPassword') == null ? project.mavenUsername : System.getenv('mavenPassword');
|
||||
String mavenUsername = System.getenv('mavenUsername');
|
||||
String mavenPassword = System.getenv('mavenPassword');
|
||||
|
||||
if (mavenUsername != null && mavenPassword != null) {
|
||||
maven {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
group 'Hook_EpicSpawners6'
|
||||
group 'Hooks:EpicSpawners6'
|
||||
|
||||
dependencies {
|
||||
compileOnly "com.songoda:EpicSpawners-6:latest"
|
||||
compileOnly "com.songoda:EpicSpawners:6.0.6"
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('hook.compile_epicspawners6') &&
|
|
@ -1,10 +1,10 @@
|
|||
group 'Hook_EpicSpawners6'
|
||||
group 'Hooks:EpicSpawners7'
|
||||
|
||||
dependencies {
|
||||
compileOnly "com.songoda:EpicSpawners-7:latest"
|
||||
compileOnly "com.songoda:EpicSpawners:7.0.2"
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('hook.compile_epicspawners7') &&
|
|
@ -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 }
|
||||
}
|
|
@ -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<Location, TickDelay> spawnerDelays = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void tick(Chunk[] chunks) {
|
||||
if (EpicSpawnersApi.getSpawnerManager() == null)
|
||||
return;
|
||||
|
||||
List<Long> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
group 'Hook_FactionsUUID'
|
||||
group 'Hooks:FactionsUUID'
|
||||
|
||||
dependencies {
|
||||
compileOnly "com.drtshock:FactionsUUID:latest"
|
||||
compileOnly "com.drtshock:Factions:1.6.9.5-U0.6.22-b309"
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('hook.compile_factionsuuid') &&
|
|
@ -1,10 +1,10 @@
|
|||
group 'Hook_FactionsX'
|
||||
group 'Hooks:FactionsX'
|
||||
|
||||
dependencies {
|
||||
compileOnly "net.prosavage:FactionsX:latest"
|
||||
compileOnly "net.prosavage:FactionsX:0.4.2"
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('hook.compile_factionsx') &&
|
|
@ -1,10 +1,10 @@
|
|||
group 'Hook_Lands'
|
||||
group 'Hooks:Lands'
|
||||
|
||||
dependencies {
|
||||
compileOnly 'me.angeschossen:Lands:latest'
|
||||
compileOnly 'me.angeschossen:Lands:4.5.2.7'
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('hook.compile_lands') &&
|
|
@ -1,11 +1,11 @@
|
|||
group 'Hook_MassiveFactions'
|
||||
group 'Hooks:MassiveFactions'
|
||||
|
||||
dependencies {
|
||||
compileOnly "com.massivecraft:Factions:latest"
|
||||
compileOnly "com.massivecraft:MassiveCore:latest"
|
||||
compileOnly "com.massivecraft:Factions:2.13.6"
|
||||
compileOnly "com.massivecraft:MassiveCore:2.13.6"
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('hook.compile_massivefactions') &&
|
|
@ -1,10 +1,10 @@
|
|||
group 'Hook_SuperiorSkyblock'
|
||||
group 'Hooks:SuperiorSkyblock'
|
||||
|
||||
dependencies {
|
||||
compileOnly "com.bgsoftware:SuperiorSkyblockAPI:1.8.2"
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('hook.compile_superiorskyblock') &&
|
|
@ -0,0 +1 @@
|
|||
group 'Hooks'
|
|
@ -0,0 +1 @@
|
|||
group 'NMS'
|
|
@ -1,9 +1,9 @@
|
|||
group 'v1_12_R1'
|
||||
group 'NMS:v1_12_R1'
|
||||
|
||||
dependencies {
|
||||
compileOnly "org.spigotmc:v1_12_R1:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('nms.compile_v1_12') && !Boolean.valueOf(project.findProperty("nms.compile_v1_12").toString())) {
|
|
@ -3,7 +3,11 @@ package com.bgsoftware.wildloaders.nms.v1_12_R1;
|
|||
import com.bgsoftware.wildloaders.handlers.NPCHandler;
|
||||
import com.bgsoftware.wildloaders.npc.DummyChannel;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.server.v1_12_R1.Advancement;
|
||||
import net.minecraft.server.v1_12_R1.AdvancementDataPlayer;
|
||||
import net.minecraft.server.v1_12_R1.AdvancementProgress;
|
||||
import net.minecraft.server.v1_12_R1.AxisAlignedBB;
|
||||
import net.minecraft.server.v1_12_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_12_R1.DamageSource;
|
||||
import net.minecraft.server.v1_12_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_12_R1.EnumGamemode;
|
||||
|
@ -28,20 +32,25 @@ import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
|
|||
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC {
|
||||
|
||||
private static final AxisAlignedBB EMPTY_BOUND = new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D);
|
||||
private final AxisAlignedBB boundingBox;
|
||||
private final AdvancementDataPlayer advancements;
|
||||
|
||||
public ChunkLoaderNPC(Location location, UUID uuid){
|
||||
public ChunkLoaderNPC(Location location, UUID uuid) {
|
||||
super(((CraftServer) Bukkit.getServer()).getServer(),
|
||||
((CraftWorld) location.getWorld()).getHandle(),
|
||||
new GameProfile(uuid, NPCHandler.getName(location.getWorld().getName())),
|
||||
new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
|
||||
|
||||
playerConnection = new DummyPlayerConnection(server, this);
|
||||
this.boundingBox = new AxisAlignedBB(new BlockPosition(location.getX(), location.getY(), location.getZ()));
|
||||
|
||||
this.playerConnection = new DummyPlayerConnection(server, this);
|
||||
this.advancements = new DummyPlayerAdvancements(server, this);
|
||||
|
||||
this.playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
|
||||
fauxSleeping = true;
|
||||
|
@ -52,7 +61,7 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
world.players.add(this);
|
||||
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
|
||||
|
||||
super.a(EMPTY_BOUND);
|
||||
super.a(this.boundingBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +71,9 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox() {
|
||||
return EMPTY_BOUND;
|
||||
// boundingBox is null on initialization of the class, which fixes:
|
||||
// https://github.com/BG-Software-LLC/WildLoaders/issues/61
|
||||
return this.boundingBox == null ? super.getBoundingBox() : this.boundingBox;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,7 +98,12 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
return false;
|
||||
}
|
||||
|
||||
public static class DummyNetworkManager extends NetworkManager{
|
||||
@Override
|
||||
public AdvancementDataPlayer getAdvancementData() {
|
||||
return this.advancements;
|
||||
}
|
||||
|
||||
public static class DummyNetworkManager extends NetworkManager {
|
||||
|
||||
private static Field channelField;
|
||||
private static Field socketAddressField;
|
||||
|
@ -103,7 +119,7 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
}
|
||||
}
|
||||
|
||||
DummyNetworkManager(){
|
||||
DummyNetworkManager() {
|
||||
super(EnumProtocolDirection.SERVERBOUND);
|
||||
updateFields();
|
||||
}
|
||||
|
@ -172,4 +188,62 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
|
||||
}
|
||||
|
||||
private static class DummyPlayerAdvancements extends AdvancementDataPlayer {
|
||||
|
||||
DummyPlayerAdvancements(MinecraftServer server, EntityPlayer entityPlayer) {
|
||||
super(server, getAdvancementsFile(server, entityPlayer), entityPlayer);
|
||||
}
|
||||
|
||||
private static File getAdvancementsFile(MinecraftServer server, EntityPlayer entityPlayer) {
|
||||
File advancementsDir = new File(server.getWorldServer(0).getDataManager().getDirectory(), "advancements");
|
||||
return new File(advancementsDir, entityPlayer.getUniqueID() + ".json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(EntityPlayer owner) {
|
||||
// setPlayer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a() {
|
||||
// stopListening
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
// reload
|
||||
}
|
||||
|
||||
@Override
|
||||
public void c() {
|
||||
// save
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean grantCriteria(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean revokeCritera(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b(EntityPlayer player) {
|
||||
// flushDirty
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Advancement advancement) {
|
||||
// setSelectedTab
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementProgress getProgress(Advancement advancement) {
|
||||
return new AdvancementProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_12_R1;
|
||||
|
||||
import com.bgsoftware.common.reflection.ReflectMethod;
|
||||
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_12_R1.loader.TileEntityChunkLoader;
|
||||
import net.minecraft.server.v1_12_R1.Block;
|
||||
import net.minecraft.server.v1_12_R1.BlockPosition;
|
||||
|
@ -24,27 +24,15 @@ import org.bukkit.craftbukkit.v1_12_R1.util.LongHash;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings({"ConstantConditions", "unused"})
|
||||
public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter {
|
||||
|
||||
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
|
||||
public final class NMSAdapterImpl implements NMSAdapter {
|
||||
|
||||
private static final ReflectMethod<Void> TILE_ENTITY_LOAD = new ReflectMethod<>(TileEntity.class, "load", NBTTagCompound.class);
|
||||
|
||||
@Override
|
||||
public boolean isMappingsSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
|
||||
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
|
||||
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
|
||||
|
||||
if (!tagCompound.hasKeyOfType(key, 8))
|
||||
return def;
|
||||
|
||||
return tagCompound.getString(key);
|
||||
NBTTagCompound tagCompound = nmsItem.getTag();
|
||||
return tagCompound == null || !tagCompound.hasKeyOfType(key, 8) ? def : tagCompound.getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,6 +40,8 @@ public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapt
|
|||
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
|
||||
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
|
||||
|
||||
assert tagCompound != null;
|
||||
|
||||
tagCompound.set(key, new NBTTagString(value));
|
||||
|
||||
nmsItem.setTag(tagCompound);
|
||||
|
@ -62,12 +52,8 @@ public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapt
|
|||
@Override
|
||||
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
|
||||
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
|
||||
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
|
||||
|
||||
if (!tagCompound.hasKeyOfType(key, 4))
|
||||
return def;
|
||||
|
||||
return tagCompound.getLong(key);
|
||||
NBTTagCompound tagCompound = nmsItem.getTag();
|
||||
return tagCompound == null || !tagCompound.hasKeyOfType(key, 4) ? def : tagCompound.getLong(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,6 +61,8 @@ public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapt
|
|||
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
|
||||
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
|
||||
|
||||
assert tagCompound != null;
|
||||
|
||||
tagCompound.set(key, new NBTTagLong(value));
|
||||
|
||||
nmsItem.setTag(tagCompound);
|
||||
|
@ -88,6 +76,8 @@ public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapt
|
|||
|
||||
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
|
||||
|
||||
assert nbtTagCompound != null;
|
||||
|
||||
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
|
||||
|
||||
NBTTagCompound properties = new NBTTagCompound();
|
|
@ -18,6 +18,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class TileEntityChunkLoader extends TileEntity implements ITickable, ITileEntityChunkLoader {
|
||||
|
||||
|
@ -26,6 +27,7 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable
|
|||
public final List<EntityHolograms> 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;
|
||||
|
@ -39,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,7 +121,7 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable
|
|||
|
||||
private void updateName(EntityHolograms hologram, String line) {
|
||||
hologram.setHologramName(line
|
||||
.replace("{0}", chunkLoader.getWhoPlaced().getName())
|
||||
.replace("{0}", this.cachedPlacerName)
|
||||
.replace("{1}", daysAmount + "")
|
||||
.replace("{2}", hoursAmount + "")
|
||||
.replace("{3}", minutesAmount + "")
|
|
@ -1,9 +1,9 @@
|
|||
group 'v1_16_R3'
|
||||
group 'NMS:v1_16_R3'
|
||||
|
||||
dependencies {
|
||||
compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('nms.compile_v1_16') && !Boolean.valueOf(project.findProperty("nms.compile_v1_16").toString())) {
|
|
@ -3,7 +3,12 @@ package com.bgsoftware.wildloaders.nms.v1_16_R3;
|
|||
import com.bgsoftware.wildloaders.handlers.NPCHandler;
|
||||
import com.bgsoftware.wildloaders.npc.DummyChannel;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.server.v1_16_R3.Advancement;
|
||||
import net.minecraft.server.v1_16_R3.AdvancementDataPlayer;
|
||||
import net.minecraft.server.v1_16_R3.AdvancementDataWorld;
|
||||
import net.minecraft.server.v1_16_R3.AdvancementProgress;
|
||||
import net.minecraft.server.v1_16_R3.AxisAlignedBB;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||
import net.minecraft.server.v1_16_R3.EnumGamemode;
|
||||
import net.minecraft.server.v1_16_R3.EnumProtocolDirection;
|
||||
|
@ -20,19 +25,23 @@ import net.minecraft.server.v1_16_R3.PacketPlayInUpdateSign;
|
|||
import net.minecraft.server.v1_16_R3.PacketPlayInWindowClick;
|
||||
import net.minecraft.server.v1_16_R3.PlayerConnection;
|
||||
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
|
||||
import net.minecraft.server.v1_16_R3.SavedFile;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC {
|
||||
|
||||
private static final AxisAlignedBB EMPTY_BOUND = new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D);
|
||||
private final AxisAlignedBB boundingBox;
|
||||
private final AdvancementDataPlayer advancements;
|
||||
|
||||
private boolean dieCall = false;
|
||||
|
||||
|
@ -42,7 +51,10 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
new GameProfile(uuid, NPCHandler.getName(location.getWorld().getName())),
|
||||
new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
|
||||
|
||||
playerConnection = new DummyPlayerConnection(server, this);
|
||||
this.boundingBox = new AxisAlignedBB(new BlockPosition(location.getX(), location.getY(), location.getZ()));
|
||||
|
||||
this.playerConnection = new DummyPlayerConnection(server, this);
|
||||
this.advancements = new DummyPlayerAdvancements(server, this);
|
||||
|
||||
this.playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
|
||||
clientViewDistance = 1;
|
||||
|
@ -54,7 +66,7 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
|
||||
((WorldServer) world).addPlayerJoin(this);
|
||||
|
||||
super.a(EMPTY_BOUND);
|
||||
super.a(this.boundingBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,7 +76,7 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox() {
|
||||
return EMPTY_BOUND;
|
||||
return this.boundingBox;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,6 +100,11 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
return getBukkitEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementDataPlayer getAdvancementData() {
|
||||
return this.advancements;
|
||||
}
|
||||
|
||||
public static class DummyNetworkManager extends NetworkManager {
|
||||
|
||||
private static Field channelField;
|
||||
|
@ -173,4 +190,63 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
|
||||
}
|
||||
|
||||
private static class DummyPlayerAdvancements extends AdvancementDataPlayer {
|
||||
|
||||
DummyPlayerAdvancements(MinecraftServer server, EntityPlayer entityPlayer) {
|
||||
super(server.getDataFixer(), server.getPlayerList(), server.getAdvancementData(),
|
||||
getAdvancementsFile(server, entityPlayer), entityPlayer);
|
||||
}
|
||||
|
||||
private static File getAdvancementsFile(MinecraftServer server, EntityPlayer entityPlayer) {
|
||||
File advancementsDir = server.a(SavedFile.ADVANCEMENTS).toFile();
|
||||
return new File(advancementsDir, entityPlayer.getUniqueID() + ".json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(EntityPlayer owner) {
|
||||
// setPlayer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a() {
|
||||
// stopListening
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(AdvancementDataWorld advancementLoader) {
|
||||
// reload
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
// save
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean grantCriteria(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean revokeCritera(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b(EntityPlayer player) {
|
||||
// flushDirty
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(@Nullable Advancement advancement) {
|
||||
// setSelectedTab
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementProgress getProgress(Advancement advancement) {
|
||||
return new AdvancementProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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,15 +24,7 @@ import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter {
|
||||
|
||||
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
|
||||
|
||||
@Override
|
||||
public boolean isMappingsSupported() {
|
||||
return true;
|
||||
}
|
||||
public final class NMSAdapterImpl implements NMSAdapter {
|
||||
|
||||
@Override
|
||||
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
|
|
@ -19,6 +19,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class TileEntityChunkLoader extends TileEntity implements ITickable, ITileEntityChunkLoader {
|
||||
|
||||
|
@ -27,6 +28,7 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable
|
|||
public final List<EntityHolograms> 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;
|
||||
|
@ -47,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();
|
||||
|
||||
|
@ -130,9 +134,8 @@ public final class TileEntityChunkLoader extends TileEntity implements ITickable
|
|||
}
|
||||
|
||||
private void updateName(EntityHolograms hologram, String line) {
|
||||
assert chunkLoader.getWhoPlaced().getName() != null;
|
||||
hologram.setHologramName(line
|
||||
.replace("{0}", chunkLoader.getWhoPlaced().getName())
|
||||
.replace("{0}", this.cachedPlacerName)
|
||||
.replace("{1}", daysAmount + "")
|
||||
.replace("{2}", hoursAmount + "")
|
||||
.replace("{3}", minutesAmount + "")
|
|
@ -0,0 +1,36 @@
|
|||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "1.6.0"
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(16))
|
||||
}
|
||||
}
|
||||
|
||||
group 'NMS:v1_17'
|
||||
|
||||
dependencies {
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.17.1-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_17') && !Boolean.valueOf(project.findProperty("nms.compile_v1_17").toString())) {
|
||||
project.tasks.all { task -> task.enabled = false }
|
||||
}
|
|
@ -1,56 +1,54 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_17_R1;
|
||||
package com.bgsoftware.wildloaders.nms.v1_17;
|
||||
|
||||
import com.bgsoftware.wildloaders.api.holograms.Hologram;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.sounds.SoundEffect;
|
||||
import net.minecraft.world.EnumHand;
|
||||
import net.minecraft.world.EnumInteractionResult;
|
||||
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.Entity;
|
||||
import net.minecraft.world.entity.EnumItemSlot;
|
||||
import net.minecraft.world.entity.decoration.EntityArmorStand;
|
||||
import net.minecraft.world.entity.player.EntityHuman;
|
||||
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.level.World;
|
||||
import net.minecraft.world.phys.AxisAlignedBB;
|
||||
import net.minecraft.world.phys.Vec3D;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftArmorStand;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
public final class EntityHologram extends ArmorStand implements Hologram {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class EntityHolograms extends EntityArmorStand implements Hologram {
|
||||
|
||||
private static final AxisAlignedBB EMPTY_BOUND = new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D);
|
||||
private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D);
|
||||
|
||||
private CraftEntity bukkitEntity;
|
||||
|
||||
public EntityHolograms(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {
|
||||
super(serverLevel, x, y, z);
|
||||
|
||||
setInvisible(true);
|
||||
setSmall(true);
|
||||
setArms(false);
|
||||
setShowArms(false);
|
||||
setNoGravity(true);
|
||||
setBasePlate(true);
|
||||
setNoBasePlate(true);
|
||||
setMarker(true);
|
||||
|
||||
super.collides = false;
|
||||
super.setCustomNameVisible(true);
|
||||
super.a(EMPTY_BOUND);
|
||||
super.setCustomNameVisible(true); // Custom name visible
|
||||
super.setBoundingBox(EMPTY_BOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHologramName(String name) {
|
||||
super.setCustomName(CraftChatMessage.fromString(name)[0]);
|
||||
super.setCustomName(CraftChatMessage.fromStringOrNull(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeHologram() {
|
||||
super.a(Entity.RemovalReason.b);
|
||||
super.remove(RemovalReason.DISCARDED);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,8 +61,8 @@ public final class EntityHolograms extends EntityArmorStand implements Hologram
|
|||
// Disable normal ticking for this entity.
|
||||
|
||||
// Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.
|
||||
if (this.z) {
|
||||
this.z = false;
|
||||
if (this.onGround) {
|
||||
this.onGround = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,40 +71,40 @@ public final class EntityHolograms extends EntityArmorStand implements Hologram
|
|||
// Disable normal ticking for this entity.
|
||||
|
||||
// Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.
|
||||
if (this.z) {
|
||||
this.z = false;
|
||||
if (this.onGround) {
|
||||
this.onGround = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData(NBTTagCompound nbttagcompound) {
|
||||
public void addAdditionalSaveData(CompoundTag compoundTag) {
|
||||
// Do not save NBT.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean d(NBTTagCompound nbttagcompound) {
|
||||
public boolean saveAsPassenger(CompoundTag compoundTag) {
|
||||
// Do not save NBT.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
|
||||
public CompoundTag saveWithoutId(CompoundTag compoundTag) {
|
||||
// Do not save NBT.
|
||||
return nbttagcompound;
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(NBTTagCompound nbttagcompound) {
|
||||
public void readAdditionalSaveData(CompoundTag compoundTag) {
|
||||
// Do not load NBT.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadData(NBTTagCompound nbttagcompound) {
|
||||
public void load(CompoundTag compoundTag) {
|
||||
// Do not load NBT.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvulnerable(DamageSource source) {
|
||||
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
|
||||
|
@ -116,47 +114,43 @@ public final class EntityHolograms extends EntityArmorStand implements Hologram
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollidable() {
|
||||
public boolean repositionEntityAfterLoad() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomName(@Nullable IChatBaseComponent ichatbasecomponent) {
|
||||
public void setCustomName(Component component) {
|
||||
// Locks the custom name.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomNameVisible(boolean flag) {
|
||||
public void setCustomNameVisible(boolean visible) {
|
||||
// Locks the custom name.
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumInteractionResult a(EntityHuman human, Vec3D vec3d, EnumHand enumhand) {
|
||||
public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {
|
||||
// Prevent stand being equipped
|
||||
return EnumInteractionResult.d;
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) {
|
||||
public void setSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silent) {
|
||||
// Prevent stand being equipped
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB cs() {
|
||||
public AABB getBoundingBoxForCulling() {
|
||||
return EMPTY_BOUND;
|
||||
}
|
||||
|
||||
public void forceSetBoundingBox(AxisAlignedBB boundingBox) {
|
||||
super.a(boundingBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(SoundEffect soundeffect, float f, float f1) {
|
||||
public void playSound(SoundEvent soundEvent, float volume, float pitch) {
|
||||
// Remove sounds.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Entity.RemovalReason entity_removalreason) {
|
||||
public void remove(RemovalReason removalReason) {
|
||||
// Prevent being killed.
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
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;
|
||||
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_17_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.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 ChunkLoaderNPCWrapper(((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.getX(), loaderLoc.getY(), loaderLoc.getZ());
|
||||
|
||||
ChunkLoaderBlockEntity ChunkLoaderBlockEntity = new ChunkLoaderBlockEntity(chunkLoader, serverLevel, blockPos);
|
||||
serverLevel.addBlockEntityTicker(ChunkLoaderBlockEntity.getTicker());
|
||||
|
||||
for (org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) {
|
||||
LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle();
|
||||
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.getX(), loaderLoc.getY(), loaderLoc.getZ());
|
||||
|
||||
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 = ((CraftChunk) bukkitChunk).getHandle();
|
||||
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.getX(), location.getY(), location.getZ());
|
||||
BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos);
|
||||
if (blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)
|
||||
spawnerBlockEntity.getSpawner().requiredPlayerRange = reset ? 16 : -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_17_R1.loader;
|
||||
package com.bgsoftware.wildloaders.nms.v1_17.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_17_R1.EntityHolograms;
|
||||
import com.bgsoftware.wildloaders.nms.v1_17_R1.NMSAdapter;
|
||||
import net.minecraft.core.BlockPosition;
|
||||
import net.minecraft.world.level.ChunkCoordIntPair;
|
||||
import net.minecraft.world.level.World;
|
||||
import com.bgsoftware.wildloaders.nms.v1_17.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.TileEntity;
|
||||
import net.minecraft.world.level.block.entity.TileEntityTypes;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -19,29 +18,37 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class TileEntityChunkLoader extends TileEntity implements ITileEntityChunkLoader {
|
||||
public final class ChunkLoaderBlockEntity extends BlockEntity implements ITileEntityChunkLoader {
|
||||
|
||||
public static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
|
||||
public static final Map<Long, ChunkLoaderBlockEntity> chunkLoaderBlockEntityMap = new HashMap<>();
|
||||
|
||||
public final List<EntityHolograms> holograms = new ArrayList<>();
|
||||
public final List<EntityHologram> holograms = new ArrayList<>();
|
||||
private final WChunkLoader chunkLoader;
|
||||
private final Block loaderBlock;
|
||||
public final TileEntityChunkLoaderTicker ticker;
|
||||
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 TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition) {
|
||||
super(TileEntityTypes.v, blockPosition, world.getType(blockPosition));
|
||||
public ChunkLoaderBlockEntity(ChunkLoader chunkLoader, ServerLevel serverLevel, BlockPos blockPos) {
|
||||
super(BlockEntityType.COMMAND_BLOCK, blockPos, serverLevel.getBlockState(blockPos));
|
||||
|
||||
this.chunkLoader = (WChunkLoader) chunkLoader;
|
||||
this.ticker = new TileEntityChunkLoaderTicker(this);
|
||||
this.ticker = new ChunkLoaderBlockEntityTicker(this);
|
||||
this.blockPos = blockPos;
|
||||
this.serverLevel = serverLevel;
|
||||
|
||||
setWorld(world);
|
||||
setLevel(serverLevel);
|
||||
|
||||
loaderBlock = world.getType(blockPosition).getBlock();
|
||||
loaderBlock = serverLevel.getBlockState(blockPos).getBlock();
|
||||
|
||||
this.cachedPlacerName = Optional.ofNullable(this.chunkLoader.getWhoPlaced().getName()).orElse("");
|
||||
|
||||
if (!this.chunkLoader.isInfinite()) {
|
||||
long timeLeft = chunkLoader.getTimeLeft();
|
||||
|
@ -58,16 +65,16 @@ public final class TileEntityChunkLoader extends TileEntity implements ITileEnti
|
|||
secondsAmount = (short) timeLeft;
|
||||
}
|
||||
|
||||
tileEntityChunkLoaderMap.put(ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
|
||||
long chunkPosLong = ChunkPos.asLong(blockPos.getX() >> 4, blockPos.getZ() >> 4);
|
||||
chunkLoaderBlockEntityMap.put(chunkPosLong, this);
|
||||
|
||||
List<String> hologramLines = this.chunkLoader.getHologramLines();
|
||||
|
||||
double currentY = getPosition().getY() + 1;
|
||||
double currentY = blockPos.getY() + 1;
|
||||
for (int i = hologramLines.size(); i > 0; i--) {
|
||||
EntityHolograms hologram = new EntityHolograms(world,
|
||||
getPosition().getX() + 0.5, currentY, getPosition().getZ() + 0.5);
|
||||
EntityHologram hologram = new EntityHologram(serverLevel, blockPos.getX() + 0.5, currentY, blockPos.getZ() + 0.5);
|
||||
updateName(hologram, hologramLines.get(i - 1));
|
||||
world.addEntity(hologram);
|
||||
serverLevel.addFreshEntity(hologram);
|
||||
currentY += 0.23;
|
||||
holograms.add(hologram);
|
||||
}
|
||||
|
@ -79,8 +86,7 @@ public final class TileEntityChunkLoader extends TileEntity implements ITileEnti
|
|||
|
||||
currentTick = 0;
|
||||
|
||||
assert this.n != null;
|
||||
if (chunkLoader.isNotActive() || this.n.getType(getPosition()).getBlock() != loaderBlock) {
|
||||
if (chunkLoader.isNotActive() || this.serverLevel.getBlockState(this.blockPos).getBlock() != loaderBlock) {
|
||||
chunkLoader.remove();
|
||||
return;
|
||||
}
|
||||
|
@ -92,7 +98,7 @@ public final class TileEntityChunkLoader extends TileEntity implements ITileEnti
|
|||
|
||||
int hologramsAmount = holograms.size();
|
||||
for (int i = hologramsAmount; i > 0; i--) {
|
||||
EntityHolograms hologram = holograms.get(hologramsAmount - i);
|
||||
EntityHologram hologram = holograms.get(hologramsAmount - i);
|
||||
updateName(hologram, hologramLines.get(i - 1));
|
||||
}
|
||||
|
||||
|
@ -125,10 +131,13 @@ public final class TileEntityChunkLoader extends TileEntity implements ITileEnti
|
|||
return removed || super.isRemoved();
|
||||
}
|
||||
|
||||
private void updateName(EntityHolograms hologram, String line) {
|
||||
assert chunkLoader.getWhoPlaced().getName() != null;
|
||||
public ChunkLoaderBlockEntityTicker getTicker() {
|
||||
return ticker;
|
||||
}
|
||||
|
||||
private void updateName(EntityHologram hologram, String line) {
|
||||
hologram.setHologramName(line
|
||||
.replace("{0}", chunkLoader.getWhoPlaced().getName())
|
||||
.replace("{0}", this.cachedPlacerName)
|
||||
.replace("{1}", daysAmount + "")
|
||||
.replace("{2}", hoursAmount + "")
|
||||
.replace("{3}", minutesAmount + "")
|
|
@ -0,0 +1,30 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_17.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()) + "";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_17.npc;
|
||||
|
||||
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ChunkLoaderNPCWrapper implements ChunkLoaderNPC {
|
||||
|
||||
private final ChunkLoaderPlayer chunkLoaderPlayer;
|
||||
|
||||
public ChunkLoaderNPCWrapper(MinecraftServer minecraftServer, Location location, UUID uuid) {
|
||||
this.chunkLoaderPlayer = new ChunkLoaderPlayer(minecraftServer, location, uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return this.chunkLoaderPlayer.getUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
this.chunkLoaderPlayer.discard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return getPlayer().getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return this.chunkLoaderPlayer.getBukkitEntity();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_17.npc;
|
||||
|
||||
import com.bgsoftware.common.reflection.ReflectMethod;
|
||||
import com.bgsoftware.wildloaders.handlers.NPCHandler;
|
||||
import com.bgsoftware.wildloaders.npc.DummyChannel;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.advancements.AdvancementProgress;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.Connection;
|
||||
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.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
||||
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_17_R1.CraftWorld;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class ChunkLoaderPlayer extends ServerPlayer {
|
||||
|
||||
private static final ReflectMethod<Void> 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 ChunkLoaderPlayer(MinecraftServer minecraftServer, Location location, UUID uuid) {
|
||||
super(minecraftServer, ((CraftWorld) location.getWorld()).getHandle(),
|
||||
new GameProfile(uuid, NPCHandler.getName(location.getWorld().getName())));
|
||||
|
||||
this.serverLevel = getLevel();
|
||||
this.boundingBox = new AABB(new BlockPos(location.getX(), location.getY(), location.getZ()));
|
||||
|
||||
this.connection = new DummyServerGamePacketListenerImpl(minecraftServer, this);
|
||||
this.advancements = new DummyPlayerAdvancements(minecraftServer, this);
|
||||
|
||||
SET_GAMEMODE.invoke(this.gameMode, GameType.CREATIVE, null);
|
||||
clientViewDistance = 1;
|
||||
|
||||
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 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 PlayerAdvancements getAdvancements() {
|
||||
return advancements;
|
||||
}
|
||||
|
||||
public static class DummyConnection extends Connection {
|
||||
|
||||
DummyConnection() {
|
||||
super(PacketFlow.SERVERBOUND);
|
||||
this.channel = new DummyChannel();
|
||||
this.address = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DummyServerGamePacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
DummyServerGamePacketListenerImpl(MinecraftServer minecraftServer, ServerPlayer serverPlayer) {
|
||||
super(minecraftServer, new DummyConnection(), serverPlayer);
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
||||
}
|
||||
|
||||
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 File getAdvancementsFile(MinecraftServer server, ServerPlayer serverPlayer) {
|
||||
File advancementsDir = server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).toFile();
|
||||
return new File(advancementsDir, serverPlayer.getUUID() + ".json");
|
||||
}
|
||||
|
||||
@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(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean revoke(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushDirty(ServerPlayer player) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedTab(@Nullable Advancement advancement) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementProgress getOrStartProgress(Advancement advancement) {
|
||||
return new AdvancementProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "1.6.0"
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
}
|
||||
|
||||
group 'NMS:v1_18'
|
||||
|
||||
dependencies {
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.18.2-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_18') && !Boolean.valueOf(project.findProperty("nms.compile_v1_18").toString())) {
|
||||
project.tasks.all { task -> task.enabled = false }
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_18;
|
||||
|
||||
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.Advancement;
|
||||
import net.minecraft.advancements.AdvancementProgress;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.Connection;
|
||||
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.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
||||
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_18_R2.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class ChunkLoaderNPCImpl extends ServerPlayer implements ChunkLoaderNPC {
|
||||
|
||||
private static final ReflectMethod<Void> 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())));
|
||||
|
||||
this.serverLevel = getLevel();
|
||||
this.boundingBox = new AABB(new BlockPos(location.getX(), location.getY(), location.getZ()));
|
||||
|
||||
this.connection = new DummyServerGamePacketListenerImpl(minecraftServer, this);
|
||||
this.advancements = new DummyPlayerAdvancements(minecraftServer, this);
|
||||
|
||||
SET_GAMEMODE.invoke(this.gameMode, GameType.CREATIVE, null);
|
||||
clientViewDistance = 1;
|
||||
|
||||
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 advancements;
|
||||
}
|
||||
|
||||
public static class DummyConnection extends Connection {
|
||||
|
||||
DummyConnection() {
|
||||
super(PacketFlow.SERVERBOUND);
|
||||
this.channel = new DummyChannel();
|
||||
this.address = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DummyServerGamePacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
DummyServerGamePacketListenerImpl(MinecraftServer minecraftServer, ServerPlayer serverPlayer) {
|
||||
super(minecraftServer, new DummyConnection(), serverPlayer);
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
||||
}
|
||||
|
||||
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 File getAdvancementsFile(MinecraftServer server, ServerPlayer serverPlayer) {
|
||||
File advancementsDir = server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).toFile();
|
||||
return new File(advancementsDir, serverPlayer.getUUID() + ".json");
|
||||
}
|
||||
|
||||
@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(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean revoke(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushDirty(ServerPlayer player) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedTab(@Nullable Advancement advancement) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementProgress getOrStartProgress(Advancement advancement) {
|
||||
return new AdvancementProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_18;
|
||||
|
||||
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_18_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftArmorStand;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
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;
|
||||
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_18_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.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.getX(), loaderLoc.getY(), loaderLoc.getZ());
|
||||
|
||||
ChunkLoaderBlockEntity ChunkLoaderBlockEntity = new ChunkLoaderBlockEntity(chunkLoader, serverLevel, blockPos);
|
||||
serverLevel.addBlockEntityTicker(ChunkLoaderBlockEntity.getTicker());
|
||||
|
||||
for (org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) {
|
||||
LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle();
|
||||
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.getX(), loaderLoc.getY(), loaderLoc.getZ());
|
||||
|
||||
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 = ((CraftChunk) bukkitChunk).getHandle();
|
||||
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.getX(), location.getY(), location.getZ());
|
||||
BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos);
|
||||
if (blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)
|
||||
spawnerBlockEntity.getSpawner().requiredPlayerRange = reset ? 16 : -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_18.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_18.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<Long, ChunkLoaderBlockEntity> chunkLoaderBlockEntityMap = new HashMap<>();
|
||||
|
||||
public final List<EntityHologram> 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<String> 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<String> 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<Hologram> 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 + "")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_18.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()) + "";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "1.6.0"
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
}
|
||||
|
||||
group 'NMS:v1_19'
|
||||
|
||||
dependencies {
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.19.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_19') && !Boolean.valueOf(project.findProperty("nms.compile_v1_19").toString())) {
|
||||
project.tasks.all { task -> task.enabled = false }
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_19;
|
||||
|
||||
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.Advancement;
|
||||
import net.minecraft.advancements.AdvancementProgress;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.Connection;
|
||||
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.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
||||
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_19_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<Void> 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())));
|
||||
|
||||
this.serverLevel = getLevel();
|
||||
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);
|
||||
clientViewDistance = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DummyServerGamePacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
DummyServerGamePacketListenerImpl(MinecraftServer minecraftServer, ServerPlayer serverPlayer) {
|
||||
super(minecraftServer, new DummyConnection(), serverPlayer);
|
||||
}
|
||||
|
||||
@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(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean revoke(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushDirty(ServerPlayer player) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedTab(@Nullable Advancement advancement) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementProgress getOrStartProgress(Advancement advancement) {
|
||||
return new AdvancementProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_19;
|
||||
|
||||
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_19_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftArmorStand;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_19_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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
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;
|
||||
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_19_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_19.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_19.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<Long, ChunkLoaderBlockEntity> chunkLoaderBlockEntityMap = new HashMap<>();
|
||||
|
||||
public final List<EntityHologram> 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<String> 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<String> 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<Hologram> 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 + "")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_19.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()) + "";
|
||||
}
|
||||
|
||||
}
|
|
@ -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_1'
|
||||
|
||||
dependencies {
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.1-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 }
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_1;
|
||||
|
||||
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.Advancement;
|
||||
import net.minecraft.advancements.AdvancementProgress;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.Connection;
|
||||
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.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
||||
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_R1.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<Void> 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())));
|
||||
|
||||
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);
|
||||
clientViewDistance = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DummyServerGamePacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
DummyServerGamePacketListenerImpl(MinecraftServer minecraftServer, ServerPlayer serverPlayer) {
|
||||
super(minecraftServer, new DummyConnection(), serverPlayer);
|
||||
}
|
||||
|
||||
@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(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean revoke(Advancement advancement, String criterionName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushDirty(ServerPlayer player) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedTab(@Nullable Advancement advancement) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementProgress getOrStartProgress(Advancement advancement) {
|
||||
return new AdvancementProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_1;
|
||||
|
||||
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_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftArmorStand;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
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;
|
||||
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_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_1.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_1.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<Long, ChunkLoaderBlockEntity> chunkLoaderBlockEntityMap = new HashMap<>();
|
||||
|
||||
public final List<EntityHologram> 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<String> 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<String> 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<Hologram> 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 + "")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_1.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()) + "";
|
||||
}
|
||||
|
||||
}
|
|
@ -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_2'
|
||||
|
||||
dependencies {
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.2-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 }
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_2;
|
||||
|
||||
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_R2.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<Void> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_2;
|
||||
|
||||
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_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftArmorStand;
|
||||
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_20_R2.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
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;
|
||||
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_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R2.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_2.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_2.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<Long, ChunkLoaderBlockEntity> chunkLoaderBlockEntityMap = new HashMap<>();
|
||||
|
||||
public final List<EntityHologram> 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<String> 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<String> 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<Hologram> 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 + "")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_20_2.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()) + "";
|
||||
}
|
||||
|
||||
}
|
|
@ -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 }
|
||||
}
|
|
@ -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<Void> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Long, ChunkLoaderBlockEntity> chunkLoaderBlockEntityMap = new HashMap<>();
|
||||
|
||||
public final List<EntityHologram> 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<String> 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<String> 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<Hologram> 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 + "")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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()) + "";
|
||||
}
|
||||
|
||||
}
|
|
@ -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 }
|
||||
}
|
|
@ -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<Void> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Long, ChunkLoaderBlockEntity> chunkLoaderBlockEntityMap = new HashMap<>();
|
||||
|
||||
public final List<EntityHologram> 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<String> 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<String> 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<Hologram> 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 + "")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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()) + "";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
group 'v1_7_R4'
|
||||
group 'NMS:v1_7_R4'
|
||||
|
||||
dependencies {
|
||||
compileOnly "org.spigotmc:v1_7_R4:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('nms.compile_v1_7') && !Boolean.valueOf(project.findProperty("nms.compile_v1_7").toString())) {
|
|
@ -18,6 +18,7 @@ import net.minecraft.server.v1_7_R4.PacketPlayInUpdateSign;
|
|||
import net.minecraft.server.v1_7_R4.PacketPlayInWindowClick;
|
||||
import net.minecraft.server.v1_7_R4.PlayerConnection;
|
||||
import net.minecraft.server.v1_7_R4.PlayerInteractManager;
|
||||
import net.minecraft.server.v1_7_R4.Statistic;
|
||||
import net.minecraft.server.v1_7_R4.WorldServer;
|
||||
import net.minecraft.util.com.mojang.authlib.GameProfile;
|
||||
import org.bukkit.Bukkit;
|
||||
|
@ -74,6 +75,16 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Statistic statistic, int i) {
|
||||
// Prevent achievements from being given to NPCs.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Statistic statistic) {
|
||||
// Prevent achievements from being given to NPCs.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return getBukkitEntity();
|
|
@ -1,8 +1,8 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_7_R4;
|
||||
|
||||
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_7_R4.loader.TileEntityChunkLoader;
|
||||
import net.minecraft.server.v1_7_R4.Block;
|
||||
import net.minecraft.server.v1_7_R4.Chunk;
|
||||
|
@ -22,15 +22,7 @@ import org.bukkit.craftbukkit.v1_7_R4.util.LongHash;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter {
|
||||
|
||||
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
|
||||
|
||||
@Override
|
||||
public boolean isMappingsSupported() {
|
||||
return true;
|
||||
}
|
||||
public final class NMSAdapterImpl implements NMSAdapter {
|
||||
|
||||
@Override
|
||||
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
|
|
@ -1,9 +1,9 @@
|
|||
group 'v1_8_R3'
|
||||
group 'NMS:v1_8_R3'
|
||||
|
||||
dependencies {
|
||||
compileOnly "org.spigotmc:v1_8_R3-Taco:latest"
|
||||
compileOnly project(":API")
|
||||
compileOnly parent
|
||||
compileOnly rootProject
|
||||
}
|
||||
|
||||
if (project.hasProperty('nms.compile_v1_8') && !Boolean.valueOf(project.findProperty("nms.compile_v1_8").toString())) {
|
|
@ -20,6 +20,7 @@ import net.minecraft.server.v1_8_R3.PacketPlayInUpdateSign;
|
|||
import net.minecraft.server.v1_8_R3.PacketPlayInWindowClick;
|
||||
import net.minecraft.server.v1_8_R3.PlayerConnection;
|
||||
import net.minecraft.server.v1_8_R3.PlayerInteractManager;
|
||||
import net.minecraft.server.v1_8_R3.Statistic;
|
||||
import net.minecraft.server.v1_8_R3.WorldServer;
|
||||
import net.minecraft.server.v1_8_R3.WorldSettings;
|
||||
import org.bukkit.Bukkit;
|
||||
|
@ -33,7 +34,7 @@ import java.util.UUID;
|
|||
|
||||
public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC {
|
||||
|
||||
private static final AxisAlignedBB EMPTY_BOUND = new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D);
|
||||
private final AxisAlignedBB boundingBox;
|
||||
|
||||
public ChunkLoaderNPC(Location location, UUID uuid) {
|
||||
super(((CraftServer) Bukkit.getServer()).getServer(),
|
||||
|
@ -41,6 +42,9 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
new GameProfile(uuid, NPCHandler.getName(location.getWorld().getName())),
|
||||
new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
|
||||
|
||||
this.boundingBox = new AxisAlignedBB(location.getX(), location.getY(), location.getZ(),
|
||||
location.getX() + 1, location.getY() + 1, location.getZ() + 1);
|
||||
|
||||
playerConnection = new DummyPlayerConnection(server, this);
|
||||
|
||||
playerInteractManager.setGameMode(WorldSettings.EnumGamemode.CREATIVE);
|
||||
|
@ -60,7 +64,7 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
world.players.add(this);
|
||||
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
|
||||
|
||||
super.a(EMPTY_BOUND);
|
||||
super.a(this.boundingBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,7 +74,9 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox() {
|
||||
return EMPTY_BOUND;
|
||||
// boundingBox is null on initialization of the class, which fixes:
|
||||
// https://github.com/BG-Software-LLC/WildLoaders/issues/61
|
||||
return this.boundingBox == null ? super.getBoundingBox() : this.boundingBox;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,6 +96,16 @@ public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Statistic statistic, int i) {
|
||||
// Prevent achievements from being given to NPCs.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Statistic statistic) {
|
||||
// Prevent achievements from being given to NPCs.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return getBukkitEntity();
|
|
@ -1,8 +1,8 @@
|
|||
package com.bgsoftware.wildloaders.nms.v1_8_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_8_R3.loader.TileEntityChunkLoader;
|
||||
import net.minecraft.server.v1_8_R3.Block;
|
||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||
|
@ -22,15 +22,7 @@ import org.bukkit.craftbukkit.v1_8_R3.util.LongHash;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class NMSAdapter implements com.bgsoftware.wildloaders.nms.NMSAdapter {
|
||||
|
||||
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
|
||||
|
||||
@Override
|
||||
public boolean isMappingsSupported() {
|
||||
return true;
|
||||
}
|
||||
public final class NMSAdapterImpl implements NMSAdapter {
|
||||
|
||||
@Override
|
||||
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
|
|
@ -18,6 +18,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class TileEntityChunkLoader extends TileEntity implements IUpdatePlayerListBox, ITileEntityChunkLoader {
|
||||
|
||||
|
@ -26,6 +27,7 @@ public final class TileEntityChunkLoader extends TileEntity implements IUpdatePl
|
|||
public final List<EntityHolograms> 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;
|
||||
|
@ -39,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,7 +121,7 @@ public final class TileEntityChunkLoader extends TileEntity implements IUpdatePl
|
|||
|
||||
private void updateName(EntityHolograms hologram, String line) {
|
||||
hologram.setHologramName(line
|
||||
.replace("{0}", chunkLoader.getWhoPlaced().getName())
|
||||
.replace("{0}", this.cachedPlacerName)
|
||||
.replace("{1}", daysAmount + "")
|
||||
.replace("{2}", hoursAmount + "")
|
||||
.replace("{3}", minutesAmount + "")
|
15
README.md
15
README.md
|
@ -6,7 +6,7 @@
|
|||
<p align="center">
|
||||
<a href="https://bg-software.com/discord/"><img src="https://img.shields.io/discord/293212540723396608?color=7289DA&label=Discord&logo=discord&logoColor=7289DA&link=https://bg-software.com/discord/"></a>
|
||||
<a href="https://bg-software.com/patreon/"><img src="https://img.shields.io/badge/-Support_on_Patreon-F96854.svg?logo=patreon&style=flat&logoColor=white&link=https://bg-software.com/patreon/"></a><br>
|
||||
<a href=""><img src="https://img.shields.io/maintenance/yes/2022"></a>
|
||||
<a href=""><img src="https://img.shields.io/maintenance/yes/2024"></a>
|
||||
<a href="https://www.codacy.com/gh/BG-Software-LLC/WildLoaders/dashboard?utm_source=github.com&utm_medium=referral&utm_content=BG-Software-LLC/WildLoaders&utm_campaign=Badge_Grade"><img src="https://app.codacy.com/project/badge/Grade/cbf4b6dc2e73440c941d021f1255cc95"/></a>
|
||||
</p>
|
||||
|
||||
|
@ -16,19 +16,6 @@ You can compile the project using gradlew.<br>
|
|||
Run `gradlew build` in console to build the project.<br>
|
||||
You can find already compiled jars on our [Jenkins](https://hub.bg-software.com/) hub!<br>
|
||||
|
||||
When compiling you will receive errors about missing dependencies.<br>
|
||||
These dependencies are premium plugins that cannot be published on a public repository.<br>
|
||||
You can do either of the followings in order to solve it:
|
||||
- Add manually all the jar files of the premium plugins.
|
||||
- Purchase access to our private repository.
|
||||
- Disabling compiling of the modules of these dependencies in the `gradle.properties` file.
|
||||
|
||||
<br>
|
||||
|
||||
##### Private Jars:
|
||||
- EpicSpawners by Songoda [[link]](https://songoda.com/marketplace/product/13)
|
||||
|
||||
|
||||
## API
|
||||
|
||||
The plugin is packed with a rich API for interacting with chunk loaders and more. When hooking into the plugin, it's highly recommended to only use the API and not the compiled plugin, as the API methods are not only commented, but also will not get removed or changed unless they are marked as deprecated. This means that when using the API, you won't have to do any additional changes to your code between updates.
|
||||
|
|
106
build.gradle
106
build.gradle
|
@ -1,41 +1,51 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||
id 'io.github.goooler.shadow' version '8.1.7'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
group 'WildLoaders'
|
||||
version = "1.2.1"
|
||||
version = "2024.1"
|
||||
|
||||
project.ext {
|
||||
archiveFolder = file("archive/")
|
||||
targetFolder = file("target/")
|
||||
buildVersion = System.getenv("BUILD_NUMBER") == null || Boolean.parseBoolean(System.getenv("STABLE_BUILD")) ?
|
||||
version : version + "-b" + System.getenv("BUILD_NUMBER")
|
||||
}
|
||||
|
||||
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/' }
|
||||
maven { url 'https://repo.bg-software.com/repository/api/' }
|
||||
maven { url 'https://repo.bg-software.com/repository/common/' }
|
||||
maven { url 'https://repo.bg-software.com/repository/public-libs/' }
|
||||
|
||||
String mavenUsername = System.getenv('mavenUsername') == null ? project.mavenUsername : System.getenv('mavenUsername');
|
||||
String mavenPassword = System.getenv('mavenPassword') == null ? project.mavenUsername : System.getenv('mavenPassword');
|
||||
|
||||
if (mavenUsername != null && mavenPassword != null) {
|
||||
maven {
|
||||
url 'https://repo.bg-software.com/repository/private-libs/'
|
||||
credentials {
|
||||
username mavenUsername
|
||||
password mavenPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
maven { url 'https://repo.bg-software.com/repository/dependencies/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly "com.bgsoftware.common.reflection:ReflectionUtils:latest"
|
||||
compileOnly "com.bgsoftware.common.reflection:ReflectionUtils:b5"
|
||||
}
|
||||
|
||||
task checkDebug() {
|
||||
Set<File> filesWithDebug = fileTree('src/main/java').filter { file ->
|
||||
file.text.contains('Bukkit.broadcastMessage')
|
||||
}.getFiles()
|
||||
|
||||
if(!filesWithDebug.isEmpty())
|
||||
throw new GradleException("Found debug messages: " + filesWithDebug)
|
||||
}
|
||||
|
||||
build {
|
||||
dependsOn checkDebug
|
||||
dependsOn shadowJar
|
||||
}
|
||||
}
|
||||
|
@ -43,16 +53,25 @@ allprojects {
|
|||
subprojects {
|
||||
shadowJar {
|
||||
archiveFileName = "${project.name}.jar"
|
||||
destinationDirectory = file("../archive/")
|
||||
destinationDirectory = rootProject.archiveFolder
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":API")
|
||||
implementation fileTree("archive")
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
implementation 'com.bgsoftware.common.reflection:ReflectionUtils:latest'
|
||||
implementation 'com.bgsoftware.common.config:CommentedConfiguration:1.0.3'
|
||||
dependencies {
|
||||
implementation fileTree(rootProject.archiveFolder.getAbsolutePath())
|
||||
implementation project(":API")
|
||||
|
||||
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"
|
||||
|
@ -61,19 +80,18 @@ dependencies {
|
|||
|
||||
jar {
|
||||
from {
|
||||
for (File file : new File("archive").listFiles()) {
|
||||
for (File file : rootProject.archiveFolder.listFiles()) {
|
||||
zipTree(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
outputs.upToDateWhen {false}
|
||||
String versionNumber = System.getenv("BUILD_NUMBER") == null ? version : version + "." + System.getenv("BUILD_NUMBER")
|
||||
outputs.upToDateWhen { false }
|
||||
eachFile { details ->
|
||||
if (details.name.contentEquals('plugin.yml')) {
|
||||
filter { String line ->
|
||||
line.replace('${project.version}', versionNumber)
|
||||
line.replace('${project.version}', rootProject.buildVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,30 +100,28 @@ processResources {
|
|||
shadowJar {
|
||||
dependsOn(jar)
|
||||
|
||||
if(System.getenv("BUILD_NUMBER") == null){
|
||||
archiveName = rootProject.name + "-" + version + ".jar"
|
||||
}
|
||||
else{
|
||||
archiveName = rootProject.name + "-" + version + "-b" + System.getenv("BUILD_NUMBER") + ".jar"
|
||||
}
|
||||
relocate 'org.bstats', 'com.bgsoftware.wildloaders.libs.org.bstats'
|
||||
relocate 'com.bgsoftware.common', 'com.bgsoftware.wildloaders.libs.com.bgsoftware.common'
|
||||
|
||||
delete fileTree('./target/') {
|
||||
exclude archiveName
|
||||
}
|
||||
archiveFileName = rootProject.name + "-" + rootProject.buildVersion + ".jar"
|
||||
|
||||
destinationDir = file("./target/")
|
||||
delete fileTree(rootProject.targetFolder.getAbsolutePath())
|
||||
|
||||
exclude '*exclude.jar'
|
||||
|
||||
destinationDirectory = rootProject.targetFolder
|
||||
from sourceSets.getByName("main").output
|
||||
configurations = [project.configurations.getByName("runtimeClasspath")]
|
||||
}
|
||||
|
||||
task copyAPI(type: Copy) {
|
||||
from './archive/API.jar'
|
||||
into './target/'
|
||||
task copyAPI(type: Copy, dependsOn: ':API:build') {
|
||||
from rootProject.archiveFolder.getAbsolutePath() + '/API.jar'
|
||||
into rootProject.targetFolder.getAbsolutePath()
|
||||
rename('API.jar', rootProject.name + 'API.jar')
|
||||
}
|
||||
|
||||
clean {
|
||||
delete file('./archive/')
|
||||
delete rootProject.archiveFolder
|
||||
}
|
||||
|
||||
build {
|
||||
|
@ -116,4 +132,8 @@ build {
|
|||
|
||||
publish.shouldRunAfter shadowJar
|
||||
shadowJar.shouldRunAfter build
|
||||
build.shouldRunAfter subprojects.build
|
||||
build.shouldRunAfter subprojects.build
|
||||
clean.shouldRunAfter copyAPI
|
||||
|
||||
shadowJar.dependsOn subprojects.build
|
||||
compileJava.dependsOn childProjects.values().shadowJar
|
|
@ -1,7 +1,3 @@
|
|||
# Maven related settings
|
||||
# Used to access to the private-repository
|
||||
mavenUsername=''
|
||||
mavenPassword=''
|
||||
# Compiling settings
|
||||
# You can turn-off compiling of specific modules here by setting them to `false`
|
||||
nms.compile_v1_7=true
|
||||
|
@ -11,6 +7,7 @@ nms.compile_v1_16=true
|
|||
nms.compile_v1_17=true
|
||||
nms.compile_v1_18=true
|
||||
nms.compile_v1_19=true
|
||||
nms.compile_v1_20=true
|
||||
hook.compile_epicspawners6=true
|
||||
hook.compile_epicspawners7=true
|
||||
hook.compile_factionsuuid=true
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -1,19 +1,32 @@
|
|||
rootProject.name = 'WildLoaders'
|
||||
include 'API'
|
||||
include 'Hook_EpicSpawners6'
|
||||
include 'Hook_EpicSpawners7'
|
||||
include 'Hook_FactionsUUID'
|
||||
include 'Hook_FactionsX'
|
||||
include 'Hook_MassiveFactions'
|
||||
include 'Hook_SuperiorSkyblock'
|
||||
include 'v1_7_R4'
|
||||
include 'v1_8_R3'
|
||||
include 'v1_12_R1'
|
||||
include 'v1_16_R3'
|
||||
include 'v1_17_R1'
|
||||
include 'v1_18_R1'
|
||||
include 'Hook_EpicSpawners7'
|
||||
include 'v1_18_R2'
|
||||
include 'Hook_Lands'
|
||||
include 'v1_19_R1'
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven { url "https://repo.papermc.io/repository/maven-public/" }
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'WildLoaders'
|
||||
|
||||
include 'API'
|
||||
include 'Hooks'
|
||||
include 'Hooks:EpicSpawners6'
|
||||
include 'Hooks:EpicSpawners7'
|
||||
include 'Hooks:EpicSpawners8'
|
||||
include 'Hooks:FactionsUUID'
|
||||
include 'Hooks:FactionsX'
|
||||
include 'Hooks:Lands'
|
||||
include 'Hooks:MassiveFactions'
|
||||
include 'Hooks:SuperiorSkyblock'
|
||||
include 'NMS'
|
||||
include 'NMS:v1_7_R4'
|
||||
include 'NMS:v1_8_R3'
|
||||
include 'NMS:v1_12_R1'
|
||||
include 'NMS:v1_16_R3'
|
||||
include 'NMS:v1_17'
|
||||
include 'NMS:v1_18'
|
||||
include 'NMS:v1_19'
|
||||
include 'NMS:v1_20_1'
|
||||
include 'NMS:v1_20_2'
|
||||
include 'NMS:v1_20_3'
|
||||
include 'NMS:v1_20_4'
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
package com.bgsoftware.wildloaders;
|
||||
|
||||
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;
|
||||
|
@ -11,9 +16,9 @@ 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.database.Database;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
|
@ -21,6 +26,8 @@ import java.lang.reflect.Field;
|
|||
|
||||
public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders {
|
||||
|
||||
private final Updater updater = new Updater(this, "wildloaders");
|
||||
|
||||
private static WildLoadersPlugin plugin;
|
||||
|
||||
private SettingsHandler settingsHandler;
|
||||
|
@ -36,9 +43,12 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders {
|
|||
@Override
|
||||
public void onLoad() {
|
||||
plugin = this;
|
||||
new Metrics(this);
|
||||
|
||||
loadNMSAdapter();
|
||||
DependenciesManager.inject(this);
|
||||
|
||||
new Metrics(this, 21732);
|
||||
|
||||
shouldEnable = loadNMSAdapter();
|
||||
loadAPI();
|
||||
|
||||
if (!shouldEnable)
|
||||
|
@ -70,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("");
|
||||
}
|
||||
|
||||
|
@ -89,18 +99,18 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders {
|
|||
}
|
||||
}
|
||||
|
||||
private void loadNMSAdapter() {
|
||||
String version = getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
private boolean loadNMSAdapter() {
|
||||
try {
|
||||
nmsAdapter = (NMSAdapter) Class.forName(String.format("com.bgsoftware.wildloaders.nms.%s.NMSAdapter", version)).newInstance();
|
||||
if (!nmsAdapter.isMappingsSupported()) {
|
||||
log("WildLoaders does not support your version mappings... Please contact @Ome_R");
|
||||
shouldEnable = false;
|
||||
}
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
|
||||
shouldEnable = false;
|
||||
log("Couldn't load up with an adapter " + version + ". Please contact @Ome_R");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
INMSLoader nmsLoader = NMSHandlersFactory.createNMSLoader(this);
|
||||
this.nmsAdapter = nmsLoader.loadNMSHandler(NMSAdapter.class);
|
||||
|
||||
return true;
|
||||
} catch (NMSLoadException error) {
|
||||
log("&cThe plugin doesn't support your minecraft version.");
|
||||
log("&cPlease try a different version.");
|
||||
error.printStackTrace();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,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);
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public final class CmdGive implements ICommand {
|
|||
|
||||
int amount = 1;
|
||||
|
||||
if(args.length == 4){
|
||||
if(args.length >= 4){
|
||||
try{
|
||||
amount = Integer.parseInt(args[3]);
|
||||
} catch (IllegalArgumentException e){
|
||||
|
|
|
@ -2,15 +2,18 @@ package com.bgsoftware.wildloaders.handlers;
|
|||
|
||||
import com.bgsoftware.wildloaders.WildLoadersPlugin;
|
||||
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
|
||||
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
|
||||
import com.bgsoftware.wildloaders.utils.ServerVersion;
|
||||
import com.bgsoftware.wildloaders.utils.database.Database;
|
||||
import com.bgsoftware.wildloaders.utils.locations.LocationUtils;
|
||||
import com.bgsoftware.wildloaders.utils.threads.Executor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -18,20 +21,20 @@ public final class DataHandler {
|
|||
|
||||
private final WildLoadersPlugin plugin;
|
||||
|
||||
public DataHandler(WildLoadersPlugin plugin){
|
||||
public DataHandler(WildLoadersPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
Executor.sync(() -> {
|
||||
try {
|
||||
Database.start(new File(plugin.getDataFolder(), "database.db"));
|
||||
loadDatabase();
|
||||
}catch (Exception ex){
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
||||
}
|
||||
}, 2L);
|
||||
}
|
||||
|
||||
public void loadDatabase(){
|
||||
public void loadDatabase() {
|
||||
Database.executeUpdate("CREATE TABLE IF NOT EXISTS npc_identifiers (location TEXT NOT NULL PRIMARY KEY, uuid TEXT NOT NULL);");
|
||||
Database.executeQuery("SELECT * FROM npc_identifiers;", resultSet -> {
|
||||
while (resultSet.next()) {
|
||||
|
@ -43,27 +46,30 @@ public final class DataHandler {
|
|||
|
||||
Database.executeUpdate("CREATE TABLE IF NOT EXISTS chunk_loaders (location TEXT NOT NULL PRIMARY KEY, placer TEXT NOT NULL, loader_data TEXT NOT NULL, timeLeft BIGINT NOT NULL);");
|
||||
Database.executeQuery("SELECT * FROM chunk_loaders;", resultSet -> {
|
||||
while(resultSet.next()){
|
||||
while (resultSet.next()) {
|
||||
Location location = LocationUtils.getLocation(resultSet.getString("location"));
|
||||
UUID placer = UUID.fromString(resultSet.getString("placer"));
|
||||
Optional<LoaderData> loaderData = plugin.getLoaders().getLoaderData(resultSet.getString("loader_data"));
|
||||
long timeLeft = resultSet.getLong("timeLeft");
|
||||
|
||||
if(!loaderData.isPresent())
|
||||
if (!loaderData.isPresent())
|
||||
continue;
|
||||
|
||||
Material blockType = location.getBlock().getType();
|
||||
|
||||
if(ServerVersion.isLegacy() && blockType == Material.CAULDRON){
|
||||
if (ServerVersion.isLegacy() && blockType == Material.CAULDRON) {
|
||||
blockType = Material.CAULDRON_ITEM;
|
||||
}
|
||||
|
||||
if(blockType != loaderData.get().getLoaderItem().getType()){
|
||||
if (blockType != loaderData.get().getLoaderItem().getType()) {
|
||||
WildLoadersPlugin.log("The chunk-loader at " + LocationUtils.getLocation(location) + " is invalid.");
|
||||
continue;
|
||||
}
|
||||
|
||||
plugin.getLoaders().addChunkLoader(loaderData.get(), placer, location, timeLeft);
|
||||
List<Chunk> chunksToLoad = ChunkLoaderChunks.calculateChunks(loaderData.get(), placer, location);
|
||||
chunksToLoad.removeIf(chunk -> plugin.getLoaders().getChunkLoader(chunk).isPresent());
|
||||
|
||||
plugin.getLoaders().addChunkLoaderWithoutDBSave(loaderData.get(), placer, location, timeLeft, chunksToLoad);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package com.bgsoftware.wildloaders.handlers;
|
||||
|
||||
import com.bgsoftware.wildloaders.WildLoadersPlugin;
|
||||
import com.bgsoftware.wildloaders.api.managers.LoadersManager;
|
||||
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
|
||||
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
|
||||
import com.bgsoftware.wildloaders.api.managers.LoadersManager;
|
||||
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
|
||||
import com.bgsoftware.wildloaders.loaders.WLoaderData;
|
||||
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
|
||||
import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition;
|
||||
import com.bgsoftware.wildloaders.utils.database.Query;
|
||||
import com.google.common.collect.Maps;
|
||||
|
@ -28,7 +29,7 @@ public final class LoadersHandler implements LoadersManager {
|
|||
private final Map<String, LoaderData> loadersData = Maps.newConcurrentMap();
|
||||
private final WildLoadersPlugin plugin;
|
||||
|
||||
public LoadersHandler(WildLoadersPlugin plugin){
|
||||
public LoadersHandler(WildLoadersPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
@ -59,7 +60,8 @@ public final class LoadersHandler implements LoadersManager {
|
|||
|
||||
@Override
|
||||
public ChunkLoader addChunkLoader(LoaderData loaderData, Player whoPlaced, Location location, long timeLeft) {
|
||||
WChunkLoader chunkLoader = addChunkLoader(loaderData, whoPlaced.getUniqueId(), location, timeLeft);
|
||||
WChunkLoader chunkLoader = addChunkLoaderWithoutDBSave(loaderData, whoPlaced.getUniqueId(), location, timeLeft,
|
||||
ChunkLoaderChunks.calculateChunks(loaderData, whoPlaced.getUniqueId(), location));
|
||||
|
||||
Query.INSERT_CHUNK_LOADER.insertParameters()
|
||||
.setLocation(location)
|
||||
|
@ -71,8 +73,8 @@ public final class LoadersHandler implements LoadersManager {
|
|||
return chunkLoader;
|
||||
}
|
||||
|
||||
public WChunkLoader addChunkLoader(LoaderData loaderData, UUID placer, Location location, long timeLeft){
|
||||
WChunkLoader chunkLoader = new WChunkLoader(loaderData, placer, location, timeLeft);
|
||||
public WChunkLoader addChunkLoaderWithoutDBSave(LoaderData loaderData, UUID placer, Location location, long timeLeft, List<Chunk> loadedChunks) {
|
||||
WChunkLoader chunkLoader = new WChunkLoader(loaderData, placer, location, loadedChunks.toArray(new Chunk[0]), timeLeft);
|
||||
chunkLoaders.put(location, chunkLoader);
|
||||
for (Chunk loadedChunk : chunkLoader.getLoadedChunks()) {
|
||||
chunkLoadersByChunks.put(ChunkPosition.of(loadedChunk), chunkLoader);
|
||||
|
|
|
@ -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> tickableProvider = createInstance("TickableProvider_EpicSpawners6");
|
||||
tickableProvider.ifPresent(this::addTickableProvider);
|
||||
} else {
|
||||
} else if(version.startsWith("7")) {
|
||||
Optional<TickableProvider> tickableProvider = createInstance("TickableProvider_EpicSpawners7");
|
||||
tickableProvider.ifPresent(this::addTickableProvider);
|
||||
} else {
|
||||
Optional<TickableProvider> tickableProvider = createInstance("TickableProvider_EpicSpawners8");
|
||||
tickableProvider.ifPresent(this::addTickableProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@ import com.bgsoftware.wildloaders.Locale;
|
|||
import com.bgsoftware.wildloaders.WildLoadersPlugin;
|
||||
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
|
||||
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
|
||||
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
|
||||
import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition;
|
||||
import com.bgsoftware.wildloaders.utils.legacy.Materials;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
|
@ -27,32 +29,34 @@ public final class BlocksListener implements Listener {
|
|||
|
||||
private final WildLoadersPlugin plugin;
|
||||
|
||||
public BlocksListener(WildLoadersPlugin plugin){
|
||||
public BlocksListener(WildLoadersPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onLoaderPlace(BlockPlaceEvent e){
|
||||
public void onLoaderPlace(BlockPlaceEvent e) {
|
||||
String loaderName = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-name", "");
|
||||
Optional<LoaderData> optionalLoaderData = plugin.getLoaders().getLoaderData(loaderName);
|
||||
|
||||
if(!optionalLoaderData.isPresent())
|
||||
if (!optionalLoaderData.isPresent())
|
||||
return;
|
||||
|
||||
if(!e.getPlayer().hasPermission("wildloaders.use")) {
|
||||
if (!e.getPlayer().hasPermission("wildloaders.use")) {
|
||||
e.setCancelled(true);
|
||||
Locale.NO_PLACE_PERMISSION.send(e.getPlayer());
|
||||
return;
|
||||
}
|
||||
|
||||
if(plugin.getLoaders().getChunkLoader(e.getBlock().getLocation().getChunk()).isPresent()){
|
||||
e.setCancelled(true);
|
||||
Locale.ALREADY_LOADED.send(e.getPlayer());
|
||||
return;
|
||||
}
|
||||
|
||||
LoaderData loaderData = optionalLoaderData.get();
|
||||
|
||||
for (Chunk chunk : ChunkLoaderChunks.calculateChunks(loaderData, e.getPlayer().getUniqueId(), e.getBlock().getLocation())) {
|
||||
if (plugin.getLoaders().getChunkLoader(chunk).isPresent()) {
|
||||
e.setCancelled(true);
|
||||
Locale.ALREADY_LOADED.send(e.getPlayer());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long timeLeft = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-time", loaderData.getTimeLeft());
|
||||
|
||||
plugin.getLoaders().addChunkLoader(loaderData, e.getPlayer(), e.getBlock().getLocation(), timeLeft);
|
||||
|
@ -61,33 +65,33 @@ public final class BlocksListener implements Listener {
|
|||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onLoaderBreak(BlockBreakEvent e){
|
||||
if(handleLoaderBreak(e.getBlock(), e.getPlayer().getGameMode() != GameMode.CREATIVE))
|
||||
public void onLoaderBreak(BlockBreakEvent e) {
|
||||
if (handleLoaderBreak(e.getBlock(), e.getPlayer().getGameMode() != GameMode.CREATIVE))
|
||||
Locale.BROKE_LOADER.send(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onLoaderExplode(EntityExplodeEvent e){
|
||||
public void onLoaderExplode(EntityExplodeEvent e) {
|
||||
e.blockList().removeIf(block -> handleLoaderBreak(block, true));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onSpawnerPlace(BlockPlaceEvent e){
|
||||
if(e.getBlock().getType() != Materials.SPAWNER.toBukkitType())
|
||||
public void onSpawnerPlace(BlockPlaceEvent e) {
|
||||
if (e.getBlock().getType() != Materials.SPAWNER.toBukkitType())
|
||||
return;
|
||||
|
||||
if(!plugin.getLoaders().getChunkLoader(e.getBlock().getChunk()).isPresent())
|
||||
if (!plugin.getLoaders().getChunkLoader(e.getBlock().getChunk()).isPresent())
|
||||
return;
|
||||
|
||||
plugin.getNMSAdapter().updateSpawner(e.getBlock().getLocation(), false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onLoaderInteract(PlayerInteractEvent e){
|
||||
if(e.getAction() != Action.RIGHT_CLICK_BLOCK)
|
||||
public void onLoaderInteract(PlayerInteractEvent e) {
|
||||
if (e.getAction() != Action.RIGHT_CLICK_BLOCK)
|
||||
return;
|
||||
|
||||
if(plugin.getLoaders().getChunkLoader(e.getClickedBlock().getLocation()).isPresent())
|
||||
if (plugin.getLoaders().getChunkLoader(e.getClickedBlock().getLocation()).isPresent())
|
||||
e.setCancelled(true);
|
||||
}
|
||||
|
||||
|
@ -95,37 +99,39 @@ public final class BlocksListener implements Listener {
|
|||
public void onLoaderPistonRetract(BlockPistonRetractEvent e) {
|
||||
try {
|
||||
for (Block block : e.getBlocks()) {
|
||||
if(plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) {
|
||||
if (plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onLoaderPistonExtend(BlockPistonExtendEvent e) {
|
||||
try {
|
||||
for (Block block : e.getBlocks()) {
|
||||
if(plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) {
|
||||
if (plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleLoaderBreak(Block block, boolean dropItem){
|
||||
private boolean handleLoaderBreak(Block block, boolean dropItem) {
|
||||
Location blockLoc = block.getLocation();
|
||||
Optional<ChunkLoader> optionalChunkLoader = plugin.getLoaders().getChunkLoader(blockLoc);
|
||||
|
||||
if(!optionalChunkLoader.isPresent())
|
||||
if (!optionalChunkLoader.isPresent())
|
||||
return false;
|
||||
|
||||
ChunkLoader chunkLoader = optionalChunkLoader.get();
|
||||
chunkLoader.remove();
|
||||
|
||||
if(dropItem)
|
||||
if (dropItem)
|
||||
blockLoc.getWorld().dropItemNaturally(blockLoc, chunkLoader.getLoaderItem());
|
||||
|
||||
return true;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.bgsoftware.wildloaders.api.holograms.Hologram;
|
|||
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
|
||||
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
|
||||
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
|
||||
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
|
||||
import com.bgsoftware.wildloaders.utils.database.Query;
|
||||
import com.bgsoftware.wildloaders.utils.threads.Executor;
|
||||
import org.bukkit.Bukkit;
|
||||
|
@ -14,7 +15,6 @@ import org.bukkit.Material;
|
|||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -33,11 +33,11 @@ public final class WChunkLoader implements ChunkLoader {
|
|||
private boolean active = true;
|
||||
private long timeLeft;
|
||||
|
||||
public WChunkLoader(LoaderData loaderData, UUID whoPlaced, Location location, long timeLeft) {
|
||||
public WChunkLoader(LoaderData loaderData, UUID whoPlaced, Location location, Chunk[] loadedChunks, long timeLeft) {
|
||||
this.loaderName = loaderData.getName();
|
||||
this.whoPlaced = whoPlaced;
|
||||
this.location = location.clone();
|
||||
this.loadedChunks = calculateChunks(loaderData, whoPlaced, this.location);
|
||||
this.loadedChunks = loadedChunks;
|
||||
this.timeLeft = timeLeft;
|
||||
this.tileEntityChunkLoader = plugin.getNMSAdapter().createLoader(this);
|
||||
}
|
||||
|
@ -125,39 +125,5 @@ public final class WChunkLoader implements ChunkLoader {
|
|||
return isInfinite() ? plugin.getSettings().infiniteHologramLines : plugin.getSettings().hologramLines;
|
||||
}
|
||||
|
||||
private static Chunk[] calculateChunks(LoaderData loaderData, UUID whoPlaced, Location original) {
|
||||
List<Chunk> chunkList = new ArrayList<>();
|
||||
|
||||
if (loaderData.isChunksSpread()) {
|
||||
calculateClaimChunks(original.getChunk(), whoPlaced, chunkList);
|
||||
}
|
||||
|
||||
if (chunkList.isEmpty()) {
|
||||
int chunkX = original.getBlockX() >> 4, chunkZ = original.getBlockZ() >> 4;
|
||||
|
||||
for (int x = -loaderData.getChunksRadius(); x <= loaderData.getChunksRadius(); x++)
|
||||
for (int z = -loaderData.getChunksRadius(); z <= loaderData.getChunksRadius(); z++)
|
||||
chunkList.add(original.getWorld().getChunkAt(chunkX + x, chunkZ + z));
|
||||
}
|
||||
|
||||
return chunkList.toArray(new Chunk[0]);
|
||||
}
|
||||
|
||||
private static void calculateClaimChunks(Chunk originalChunk, UUID whoPlaced, List<Chunk> chunkList) {
|
||||
if (!plugin.getProviders().hasChunkAccess(whoPlaced, originalChunk))
|
||||
return;
|
||||
|
||||
chunkList.add(originalChunk);
|
||||
|
||||
int chunkX = originalChunk.getX(), chunkZ = originalChunk.getZ();
|
||||
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
if (x != 0 || z != 0) // We don't want to add the originalChunk again.
|
||||
calculateClaimChunks(originalChunk.getWorld().getChunkAt(chunkX + x, chunkZ + z), whoPlaced, chunkList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* 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<CustomChart> 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<String> 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<String> 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<Map<String, Integer>> 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<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSONObject getChartData() throws Exception {
|
||||
JSONObject data = new JSONObject();
|
||||
JSONObject values = new JSONObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> 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<Map<String, Map<String, Integer>>> 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<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getChartData() throws Exception {
|
||||
JSONObject data = new JSONObject();
|
||||
JSONObject values = new JSONObject();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JSONObject value = new JSONObject();
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> 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<Integer> 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<Integer> 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<Map<String, Integer>> 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<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSONObject getChartData() throws Exception {
|
||||
JSONObject data = new JSONObject();
|
||||
JSONObject values = new JSONObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> 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<Map<String, Integer>> 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<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSONObject getChartData() throws Exception {
|
||||
JSONObject data = new JSONObject();
|
||||
JSONObject values = new JSONObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> 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<Map<String, int[]>> 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<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSONObject getChartData() throws Exception {
|
||||
JSONObject data = new JSONObject();
|
||||
JSONObject values = new JSONObject();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -10,8 +10,6 @@ import java.util.UUID;
|
|||
|
||||
public interface NMSAdapter {
|
||||
|
||||
boolean isMappingsSupported();
|
||||
|
||||
String getTag(ItemStack itemStack, String key, String def);
|
||||
|
||||
ItemStack setTag(ItemStack itemStack, String key, String value);
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
package com.bgsoftware.wildloaders.nms.mapping;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MappingParser {
|
||||
|
||||
private static final Pattern NEW_CLASS_REMAP_PATTERN = Pattern.compile("^([^ ]+) -> [^ ]+:$");
|
||||
private static final Pattern FIELD_REMAP_PATTERN = Pattern.compile("^[ ]{4}[^ ]+ ([^ (]+)+ -> ([^ ]+)$");
|
||||
private static final Pattern METHOD_REMAP_PATTERN = Pattern.compile("^[ ]{4}[^ ]+ ([^ ]+)\\(.*\\) -> ([^ ]+)$");
|
||||
|
||||
private MappingParser() {
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Remapped> parseRemappedMap(File mappingsFile) throws IOException {
|
||||
Map<String, Remapped> remappedMap = new HashMap<>();
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(mappingsFile))) {
|
||||
Remapped currentRemapped = null;
|
||||
String currentLine;
|
||||
|
||||
while ((currentLine = reader.readLine()) != null) {
|
||||
if (currentLine.startsWith("#")) // Comment
|
||||
continue;
|
||||
|
||||
Matcher matcher;
|
||||
|
||||
if ((matcher = NEW_CLASS_REMAP_PATTERN.matcher(currentLine)).matches()) {
|
||||
currentRemapped = new Remapped();
|
||||
remappedMap.put(matcher.group(1), currentRemapped);
|
||||
} else if (currentRemapped != null) {
|
||||
if ((matcher = FIELD_REMAP_PATTERN.matcher(currentLine)).matches()) {
|
||||
String fieldName = matcher.group(1);
|
||||
String obfuscatedName = matcher.group(2);
|
||||
currentRemapped.put(Remap.Type.FIELD, fieldName, obfuscatedName);
|
||||
} else if ((matcher = METHOD_REMAP_PATTERN.matcher(currentLine)).matches()) {
|
||||
String methodName = matcher.group(1);
|
||||
String obfuscatedName = matcher.group(2);
|
||||
currentRemapped.put(Remap.Type.METHOD, methodName, obfuscatedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return remappedMap;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package com.bgsoftware.wildloaders.nms.mapping;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Remaps.class)
|
||||
public @interface Remap {
|
||||
|
||||
String classPath();
|
||||
|
||||
String name();
|
||||
|
||||
Type type();
|
||||
|
||||
String remappedName() default "";
|
||||
|
||||
enum Type {
|
||||
|
||||
FIELD,
|
||||
METHOD
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package com.bgsoftware.wildloaders.nms.mapping;
|
||||
|
||||
public class RemapFailure extends RuntimeException {
|
||||
|
||||
public RemapFailure(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue