Initial Commit

This commit is contained in:
OmerBenGera 2020-08-15 01:39:18 +03:00
commit 9cae8e9d5a
67 changed files with 9768 additions and 0 deletions

View File

@ -0,0 +1,18 @@
package com.bgsoftware.wildloaders.api;
import com.bgsoftware.wildloaders.api.managers.LoadersManager;
import com.bgsoftware.wildloaders.api.managers.NPCManager;
public interface WildLoaders {
/**
* Get the chunk loaders manager.
*/
LoadersManager getLoaders();
/**
* Get the npcs manager.
*/
NPCManager getNPCs();
}

View File

@ -0,0 +1,7 @@
package com.bgsoftware.wildloaders.api;
public final class WildLoadersAPI {
}

View File

@ -0,0 +1,47 @@
package com.bgsoftware.wildloaders.api.loaders;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
public interface ChunkLoader {
/**
* Get the loader data from of chunk loader.
*/
LoaderData getLoaderData();
/**
* Get the player who placed the chunk loader.
*/
OfflinePlayer getWhoPlaced();
/**
* Get the amount of time that is left until the chunk loader finishes, in ticks.
*/
long getTimeLeft();
/**
* Get the location of the chunk loader.
*/
Location getLocation();
/**
* Get the NPC of this chunk loader.
*/
Optional<ChunkLoaderNPC> getNPC();
/**
* Remove this chunk loader.
*/
void remove();
/**
* Get the drop item of this chunk loader.
*/
ItemStack getLoaderItem();
}

View File

@ -0,0 +1,22 @@
package com.bgsoftware.wildloaders.api.loaders;
import org.bukkit.inventory.ItemStack;
public interface LoaderData {
/**
* Get the name of the data.
*/
String getName();
/**
* Get the default amount of time the chunk loader will run for.
*/
long getTimeLeft();
/**
* Get the drop item of the chunk loader, with default time.
*/
ItemStack getLoaderItem();
}

View File

@ -0,0 +1,77 @@
package com.bgsoftware.wildloaders.api.managers;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Optional;
public interface LoadersManager {
/**
* Get an active chunk loader from a chunk.
* @param chunk The chunk to check.
*/
Optional<ChunkLoader> getChunkLoader(Chunk chunk);
/**
* Get a chunk loader by it's location.
* @param location The location of the chunk loader.
*/
Optional<ChunkLoader> getChunkLoader(Location location);
/**
* Get all the chunk loaders on the server.
*/
List<ChunkLoader> getChunkLoaders();
/**
* Get chunk-loader data by it's name.
* @param name The name of the data.
*/
Optional<LoaderData> getLoaderData(String name);
/**
* Get all the available chunk-loaders data.
*/
List<LoaderData> getLoaderDatas();
/**
* Create a new chunk loader at a specific location.
* @param loaderData The data of the chunk loader.
* @param whoPlaced The player who placed the chunk loader.
* @param location The location of the chunk loader.
* @param timeLeft The amount of time left for the chunk loader to run.
* @return The new chunk loader object.
*/
ChunkLoader addChunkLoader(LoaderData loaderData, Player whoPlaced, Location location, long timeLeft);
/**
* Remove a chunk loader from the database.
* It's recommended to use ChunkLoader#remove instead!
*/
void removeChunkLoader(ChunkLoader chunkLoader);
/**
* Create a new chunk-loader data.
* @param name The name of the data.
* @param timeLeft The default amount of time to run.
* @param itemStack The item stack to drop upon break.
*/
void createLoaderData(String name, long timeLeft, ItemStack itemStack);
/**
* Remove all the chunk loaders data from cache.
*/
void removeLoadersData();
/**
* Remove all chunk loaders from cache.
*/
void removeChunkLoaders();
}

View File

@ -0,0 +1,40 @@
package com.bgsoftware.wildloaders.api.managers;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import java.util.Optional;
public interface NPCManager {
/**
* Get a NPC by it's location.
* @param location The location of the npc.
*/
Optional<ChunkLoaderNPC> getNPC(Location location);
/**
* Create a NPC in a specific location.
* @param location The location of the npc.
*/
ChunkLoaderNPC createNPC(Location location);
/**
* Check whether or not an entity is an NPC.
* @param livingEntity The entity to check.
*/
boolean isNPC(LivingEntity livingEntity);
/**
* Kill a NPC.
* @param npc The NPC to kill.
*/
void killNPC(ChunkLoaderNPC npc);
/**
* Kill all the npcs on the server.
*/
void killAllNPCs();
}

View File

@ -0,0 +1,28 @@
package com.bgsoftware.wildloaders.api.npc;
import org.bukkit.Location;
import java.util.UUID;
/**
* NPCs are used to make spawners work in active chunks even without nearby players, and make crops to grow in newer versions.
*/
public interface ChunkLoaderNPC {
/**
* Get the unique id of the npc.
*/
UUID getUniqueId();
/**
* Kill the npc.
* It's recommended to use NPCManager#killNPC instead!
*/
void die();
/**
* Get the location of the NPC.
*/
Location getLocation();
}

Binary file not shown.

View File

@ -0,0 +1,86 @@
package com.bgsoftware.wildloaders;
import com.bgsoftware.wildloaders.utils.config.CommentedConfiguration;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("WeakerAccess")
public final class Locale {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
private static final Map<String, Locale> localeMap = new HashMap<>();
public static Locale ALREADY_LOADED = new Locale("ALREADY_LOADED");
public static Locale BROKE_LOADER = new Locale("BROKE_LOADER");
public static Locale COMMAND_USAGE = new Locale("COMMAND_USAGE");
public static Locale GIVE_SUCCESS = new Locale("GIVE_SUCCESS");
public static Locale HELP_COMMAND_HEADER = new Locale("HELP_COMMAND_HEADER");
public static Locale HELP_COMMAND_LINE = new Locale("HELP_COMMAND_LINE");
public static Locale HELP_COMMAND_FOOTER = new Locale("HELP_COMMAND_FOOTER");
public static Locale INVALID_AMOUNT = new Locale("INVALID_AMOUNT");
public static Locale INVALID_LOADER = new Locale("INVALID_LOADER");
public static Locale INVALID_PLAYER = new Locale("INVALID_PLAYER");
public static Locale NO_PERMISSION = new Locale("NO_PERMISSION");
public static Locale NO_PLACE_PERMISSION = new Locale("NO_PLACE_PERMISSION");
public static Locale PLACED_LOADER = new Locale("PLACED_LOADER");
public static Locale RECEIVE_SUCCESS = new Locale("RECEIVE_SUCCESS");
private Locale(String identifier){
localeMap.put(identifier, this);
}
private String message;
public String getMessage(Object... objects){
if(message != null && !message.equals("")) {
String msg = message;
for (int i = 0; i < objects.length; i++)
msg = msg.replace("{" + i + "}", objects[i].toString());
return msg;
}
return null;
}
public void send(CommandSender sender, Object... objects){
String message = getMessage(objects);
if(message != null && sender != null)
sender.sendMessage(message);
}
private void setMessage(String message){
this.message = message;
}
public static void reload(){
WildLoadersPlugin.log("Loading messages started...");
long startTime = System.currentTimeMillis();
int messagesAmount = 0;
File file = new File(plugin.getDataFolder(), "lang.yml");
if(!file.exists())
plugin.saveResource("lang.yml", false);
CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file);
cfg.syncWithConfig(file, plugin.getResource("lang.yml"));
for(String identifier : localeMap.keySet()){
localeMap.get(identifier).setMessage(ChatColor.translateAlternateColorCodes('&', cfg.getString(identifier, "")));
messagesAmount++;
}
WildLoadersPlugin.log(" - Found " + messagesAmount + " messages in lang.yml.");
WildLoadersPlugin.log("Loading messages done (Took " + (System.currentTimeMillis() - startTime) + "ms)");
}
public static void sendMessage(CommandSender sender, String message){
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', message));
}
}

View File

@ -0,0 +1,97 @@
package com.bgsoftware.wildloaders;
import com.bgsoftware.wildloaders.api.WildLoaders;
import com.bgsoftware.wildloaders.command.CommandsHandler;
import com.bgsoftware.wildloaders.handlers.LoadersHandler;
import com.bgsoftware.wildloaders.handlers.NPCHandler;
import com.bgsoftware.wildloaders.handlers.SettingsHandler;
import com.bgsoftware.wildloaders.listeners.BlocksListener;
import com.bgsoftware.wildloaders.listeners.ChunksListener;
import com.bgsoftware.wildloaders.metrics.Metrics;
import com.bgsoftware.wildloaders.nms.NMSAdapter;
import org.bukkit.plugin.java.JavaPlugin;
public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders {
private static WildLoadersPlugin plugin;
private SettingsHandler settingsHandler;
private LoadersHandler loadersHandler;
private NPCHandler npcHandler;
private NMSAdapter nmsAdapter;
@Override
public void onEnable() {
plugin = this;
new Metrics(this);
log("******** ENABLE START ********");
loadNMSAdapter();
loadersHandler = new LoadersHandler(this);
npcHandler = new NPCHandler(this);
settingsHandler = new SettingsHandler(this);
getServer().getPluginManager().registerEvents(new BlocksListener(this), this);
getServer().getPluginManager().registerEvents(new ChunksListener(this), this);
CommandsHandler commandsHandler = new CommandsHandler(this);
getCommand("loader").setExecutor(commandsHandler);
getCommand("loader").setTabCompleter(commandsHandler);
Locale.reload();
// if(Updater.isOutdated()) {
// log("");
// log("A new version is available (v" + Updater.getLatestVersion() + ")!");
// log("Version's description: \"" + Updater.getVersionDescription() + "\"");
// log("");
// }
log("******** ENABLE DONE ********");
}
@Override
public void onDisable() {
loadersHandler.removeChunkLoaders();
npcHandler.killAllNPCs();
}
private void loadNMSAdapter(){
String version = getServer().getClass().getPackage().getName().split("\\.")[3];
try{
nmsAdapter = (NMSAdapter) Class.forName("com.bgsoftware.wildloaders.nms.NMSAdapter_" + version).newInstance();
} catch(ClassNotFoundException | InstantiationException | IllegalAccessException ex){
log("Couldn't load up with an adapter " + version + ". Please contact @Ome_R");
getServer().getPluginManager().disablePlugin(this);
}
}
public SettingsHandler getSettings() {
return settingsHandler;
}
@Override
public LoadersHandler getLoaders() {
return loadersHandler;
}
public NPCHandler getNPCs() {
return npcHandler;
}
public NMSAdapter getNMSAdapter() {
return nmsAdapter;
}
public static void log(String message){
plugin.getLogger().info(message);
}
public static WildLoadersPlugin getPlugin(){
return plugin;
}
}

View File

@ -0,0 +1,74 @@
package com.bgsoftware.wildloaders.command;
import com.bgsoftware.wildloaders.Locale;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.command.commands.CmdGive;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import java.util.ArrayList;
import java.util.List;
public final class CommandsHandler implements CommandExecutor, TabCompleter {
private final List<ICommand> subCommands = new ArrayList<>();
private final WildLoadersPlugin plugin;
public CommandsHandler(WildLoadersPlugin plugin){
this.plugin = plugin;
subCommands.add(new CmdGive());
}
@Override
public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) {
if(args.length > 0){
for(ICommand subCommand : subCommands) {
if (subCommand.getLabel().equalsIgnoreCase(args[0])){
if(subCommand.getPermission() != null && !sender.hasPermission(subCommand.getPermission())){
Locale.NO_PERMISSION.send(sender);
return false;
}
if(args.length < subCommand.getMinArgs() || args.length > subCommand.getMaxArgs()){
Locale.COMMAND_USAGE.send(sender, subCommand.getUsage());
return false;
}
subCommand.perform(plugin, sender, args);
return true;
}
}
}
Locale.HELP_COMMAND_HEADER.send(sender);
for(ICommand subCommand : subCommands)
if(subCommand.getPermission() == null || sender.hasPermission(subCommand.getPermission()))
Locale.HELP_COMMAND_LINE.send(sender, subCommand.getUsage(), subCommand.getDescription());
Locale.HELP_COMMAND_FOOTER.send(sender);
return false;
}
@Override
public List<String> onTabComplete(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) {
if(args.length > 0){
for(ICommand subCommand : subCommands) {
if (subCommand.getLabel().equalsIgnoreCase(args[0])){
if(subCommand.getPermission() != null && !sender.hasPermission(subCommand.getPermission())){
return new ArrayList<>();
}
return subCommand.tabComplete(plugin, sender, args);
}
}
}
List<String> list = new ArrayList<>();
for(ICommand subCommand : subCommands)
if(subCommand.getPermission() == null || sender.hasPermission(subCommand.getPermission()))
if(subCommand.getLabel().startsWith(args[0]))
list.add(subCommand.getLabel());
return list;
}
}

View File

@ -0,0 +1,26 @@
package com.bgsoftware.wildloaders.command;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import org.bukkit.command.CommandSender;
import java.util.List;
public interface ICommand {
String getLabel();
String getUsage();
String getPermission();
String getDescription();
int getMinArgs();
int getMaxArgs();
void perform(WildLoadersPlugin plugin, CommandSender sender, String[] args);
List<String> tabComplete(WildLoadersPlugin plugin, CommandSender sender, String[] args);
}

View File

@ -0,0 +1,122 @@
package com.bgsoftware.wildloaders.command.commands;
import com.bgsoftware.wildloaders.Locale;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.command.ICommand;
import com.bgsoftware.wildloaders.utils.TimeUtils;
import com.bgsoftware.wildloaders.utils.items.ItemUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public final class CmdGive implements ICommand {
@Override
public String getLabel() {
return "give";
}
@Override
public String getUsage() {
return "loader give <player-name> <loader-name> [amount] [time]";
}
@Override
public String getPermission() {
return "wildloaders.give";
}
@Override
public String getDescription() {
return "Give a chunk-loader item to a specific player.";
}
@Override
public int getMinArgs() {
return 3;
}
@Override
public int getMaxArgs() {
return 5;
}
@Override
public void perform(WildLoadersPlugin plugin, CommandSender sender, String[] args) {
Player target = Bukkit.getPlayer(args[1]);
if(target == null){
Locale.INVALID_PLAYER.send(sender, args[1]);
return;
}
Optional<LoaderData> optionalLoaderData = plugin.getLoaders().getLoaderData(args[2]);
if(!optionalLoaderData.isPresent()){
Locale.INVALID_LOADER.send(sender, args[2]);
return;
}
if(!target.equals(sender) && !sender.hasPermission(getPermission() + ".other")){
Locale.NO_PERMISSION.send(sender);
return;
}
if(target.equals(sender) && !(sender instanceof Player)){
sender.sendMessage(ChatColor.RED + "You must give a chunk-loader item to a valid player.");
return;
}
int amount = 1;
if(args.length == 4){
try{
amount = Integer.parseInt(args[3]);
} catch (IllegalArgumentException e){
Locale.INVALID_AMOUNT.send(sender, args[3]);
return;
}
}
LoaderData loaderData = optionalLoaderData.get();
ItemStack itemStack = loaderData.getLoaderItem();
itemStack.setAmount(amount);
if(args.length == 5){
itemStack = plugin.getNMSAdapter().setTag(itemStack, "loader-time", TimeUtils.fromString(args[4]));
}
ItemUtils.addItems(target.getInventory(), target.getLocation(), itemStack);
Locale.GIVE_SUCCESS.send(sender, amount, loaderData.getName(), target.getName());
Locale.RECEIVE_SUCCESS.send(target, amount, loaderData.getName(), sender.getName());
}
@Override
public List<String> tabComplete(WildLoadersPlugin plugin, CommandSender sender, String[] args) {
if(!sender.hasPermission(getPermission()))
return new ArrayList<>();
if (args.length == 3) {
List<String> list = new ArrayList<>();
for(LoaderData loaderData : plugin.getLoaders().getLoaderDatas())
if(loaderData.getName().startsWith(args[2]))
list.add(loaderData.getName());
return list;
}
if (args.length >= 4) {
return new ArrayList<>();
}
return null;
}
}

View File

@ -0,0 +1,91 @@
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.loaders.WChunkLoader;
import com.bgsoftware.wildloaders.loaders.WLoaderData;
import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition;
import com.google.common.collect.Maps;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public final class LoadersHandler implements LoadersManager {
private final Map<Location, ChunkLoader> chunkLoaders = Maps.newConcurrentMap();
private final Map<ChunkPosition, ChunkLoader> chunkLoadersByChunks = Maps.newConcurrentMap();
private final Map<String, LoaderData> loadersData = Maps.newConcurrentMap();
private final WildLoadersPlugin plugin;
public LoadersHandler(WildLoadersPlugin plugin){
this.plugin = plugin;
}
@Override
public Optional<ChunkLoader> getChunkLoader(Chunk chunk) {
return Optional.ofNullable(chunkLoadersByChunks.get(ChunkPosition.of(chunk)));
}
@Override
public Optional<ChunkLoader> getChunkLoader(Location location) {
return Optional.ofNullable(chunkLoaders.get(location));
}
@Override
public List<ChunkLoader> getChunkLoaders() {
return Collections.unmodifiableList(new ArrayList<>(chunkLoaders.values()));
}
@Override
public Optional<LoaderData> getLoaderData(String name) {
return Optional.ofNullable(loadersData.get(name));
}
@Override
public List<LoaderData> getLoaderDatas() {
return new ArrayList<>(loadersData.values());
}
@Override
public ChunkLoader addChunkLoader(LoaderData loaderData, Player whoPlaced, Location location, long timeLeft) {
ChunkLoader chunkLoader = new WChunkLoader(loaderData.getName(), whoPlaced, location, timeLeft);
chunkLoaders.put(location, chunkLoader);
chunkLoadersByChunks.put(ChunkPosition.of(location), chunkLoader);
plugin.getNPCs().createNPC(location);
return chunkLoader;
}
@Override
public void removeChunkLoader(ChunkLoader chunkLoader) {
Location location = chunkLoader.getLocation();
chunkLoaders.remove(location);
chunkLoadersByChunks.remove(ChunkPosition.of(location));
chunkLoader.getNPC().ifPresent(npc -> plugin.getNPCs().killNPC(npc));
}
@Override
public void createLoaderData(String name, long timeLeft, ItemStack itemStack) {
LoaderData loaderData = new WLoaderData(name, timeLeft, itemStack);
loadersData.put(name, loaderData);
}
@Override
public void removeLoadersData() {
loadersData.clear();
}
@Override
public void removeChunkLoaders() {
chunkLoaders.clear();
chunkLoadersByChunks.clear();
}
}

View File

@ -0,0 +1,163 @@
package com.bgsoftware.wildloaders.handlers;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.managers.NPCManager;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.utils.ServerVersion;
import com.bgsoftware.wildloaders.utils.locations.LocationUtils;
import com.google.common.collect.Maps;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.LivingEntity;
import java.io.File;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
public final class NPCHandler implements NPCManager {
private static final boolean PER_WORLD_NPCS = ServerVersion.isLessThan(ServerVersion.v1_14);
private final WildLoadersPlugin plugin;
private final Map<NPCIdentifier, ChunkLoaderNPC> npcs = Maps.newConcurrentMap();
private final Map<NPCIdentifier, UUID> npcUUIDs = Maps.newConcurrentMap();
public NPCHandler(WildLoadersPlugin plugin){
this.plugin = plugin;
loadUUIDs();
}
@Override
public Optional<ChunkLoaderNPC> getNPC(Location location) {
return Optional.ofNullable(npcs.get(new NPCIdentifier(location)));
}
@Override
public ChunkLoaderNPC createNPC(Location location) {
return npcs.computeIfAbsent(new NPCIdentifier(location), i -> plugin.getNMSAdapter().createNPC(i.getSpawnLocation(), getUUID(i)));
}
@Override
public boolean isNPC(LivingEntity livingEntity) {
ChunkLoaderNPC npc = getNPC(livingEntity.getLocation()).orElse(null);
return npc != null && npc.getUniqueId().equals(livingEntity.getUniqueId());
}
@Override
public void killNPC(ChunkLoaderNPC npc) {
if(!PER_WORLD_NPCS){
NPCIdentifier identifier = new NPCIdentifier(npc.getLocation());
npcs.remove(identifier);
npcUUIDs.remove(identifier);
saveUUIDs();
npc.die();
}
}
@Override
public void killAllNPCs() {
for(ChunkLoaderNPC npc : npcs.values()){
npc.die();
}
npcs.clear();
}
private void loadUUIDs(){
File file = new File(plugin.getDataFolder(), "uuids.yml");
if(!file.exists())
return;
YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
for(String location : cfg.getConfigurationSection("").getKeys(false)){
try{
Location _location = LocationUtils.getLocation(location);
npcUUIDs.put(new NPCIdentifier(_location), UUID.fromString(cfg.getString(location)));
}catch(Exception ignored){}
}
}
private UUID getUUID(NPCIdentifier identifier){
if(npcUUIDs.containsKey(identifier))
return npcUUIDs.get(identifier);
UUID uuid;
do{
uuid = UUID.randomUUID();
}while(npcUUIDs.containsValue(uuid));
npcUUIDs.put(identifier, uuid);
saveUUIDs();
return uuid;
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private void saveUUIDs(){
if(Bukkit.isPrimaryThread()){
Bukkit.getScheduler().runTaskAsynchronously(plugin, this::saveUUIDs);
return;
}
File file = new File(plugin.getDataFolder(), "uuids.yml");
if(!file.exists())
file.delete();
YamlConfiguration cfg = new YamlConfiguration();
for(Map.Entry<NPCIdentifier, UUID> entry : npcUUIDs.entrySet())
cfg.set(LocationUtils.getLocation(entry.getKey().getSpawnLocation()), entry.getValue() + "");
try{
file.getParentFile().mkdirs();
file.createNewFile();
cfg.save(file);
}catch(Exception ex){
ex.printStackTrace();
}
}
private static final class NPCIdentifier{
private final Object identifier;
NPCIdentifier(Location location){
this.identifier = PER_WORLD_NPCS ? location.getWorld() : location;
}
Location getSpawnLocation(){
return PER_WORLD_NPCS ? ((World) identifier).getSpawnLocation() : (Location) identifier;
}
@Override
public String toString() {
return PER_WORLD_NPCS ? ((World) identifier).getName() : identifier.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NPCIdentifier that = (NPCIdentifier) o;
return Objects.equals(identifier, that.identifier);
}
@Override
public int hashCode() {
return Objects.hash(identifier);
}
}
}

View File

@ -0,0 +1,97 @@
package com.bgsoftware.wildloaders.handlers;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.utils.items.ItemBuilder;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public final class SettingsHandler {
public List<String> hologramLines;
public SettingsHandler(WildLoadersPlugin plugin){
WildLoadersPlugin.log("Loading configuration started...");
long startTime = System.currentTimeMillis();
int loadersAmount = 0;
File file = new File(plugin.getDataFolder(), "config.yml");
if(!file.exists())
plugin.saveResource("config.yml", false);
YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
hologramLines = cfg.getStringList("hologram-lines").stream()
.map(line -> ChatColor.translateAlternateColorCodes('&', line)).collect(Collectors.toList());
plugin.getLoaders().removeLoadersData();
for (String name : cfg.getConfigurationSection("chunkloaders").getKeys(false)) {
long timeLeft = cfg.getLong("chunkloaders." + name + ".time", 0);
ItemBuilder itemBuilder = null;
try{
Material type = Material.valueOf(cfg.getString("chunkloaders." + name + ".type", ""));
short data = (short) cfg.getInt("chunkloaders." + name + ".data", 0);
itemBuilder = new ItemBuilder(type, data);
if(cfg.contains("chunkloaders." + name + ".name"))
itemBuilder.setDisplayName(ChatColor.translateAlternateColorCodes('&',
cfg.getString("chunkloaders." + name + ".name")));
if(cfg.contains("chunkloaders." + name + ".lore")) {
List<String> lore = new ArrayList<>();
cfg.getStringList("chunkloaders." + name + ".lore")
.forEach(line -> lore.add(ChatColor.translateAlternateColorCodes('&', line)));
itemBuilder.setLore(lore);
}
if(cfg.contains("chunkloaders." + name + ".enchants")) {
for(String line : cfg.getStringList("chunkloaders." + name + ".enchants")){
Enchantment enchantment = Enchantment.getByName(line.split(":")[0]);
int level = Integer.parseInt(line.split(":")[1]);
itemBuilder.addEnchant(enchantment, level);
}
}
if(cfg.contains("chunkloaders." + name + ".skull")) {
itemBuilder.setTexture(cfg.getString("chunkloaders." + name + ".skull"));
}
} catch(Exception ignored){}
if (timeLeft <= 0 || itemBuilder == null) {
WildLoadersPlugin.log("Something went wrong while loading chunk-loader '" + name + "'.");
continue;
}
plugin.getLoaders().createLoaderData(name, timeLeft, itemBuilder.build());
loadersAmount++;
}
WildLoadersPlugin.log(" - Found " + loadersAmount + " chunk-loaders in config.yml.");
WildLoadersPlugin.log("Loading configuration done (Took " + (System.currentTimeMillis() - startTime) + "ms)");
}
public static void reload(){
try{
WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
Field settings = WildLoadersPlugin.class.getDeclaredField("settingsHandler");
settings.setAccessible(true);
settings.set(plugin, new SettingsHandler(plugin));
} catch(NoSuchFieldException | IllegalAccessException ex){
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,84 @@
package com.bgsoftware.wildloaders.listeners;
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.chunks.ChunkPosition;
import com.bgsoftware.wildloaders.utils.legacy.Materials;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import java.util.Optional;
@SuppressWarnings("unused")
public final class BlocksListener implements Listener {
private final WildLoadersPlugin plugin;
public BlocksListener(WildLoadersPlugin plugin){
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onLoaderPlace(BlockPlaceEvent e){
String loaderName = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-name", "");
Optional<LoaderData> optionalLoaderData = plugin.getLoaders().getLoaderData(loaderName);
if(!optionalLoaderData.isPresent())
return;
if(!e.getPlayer().hasPermission("wildloaders.use")) {
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();
long timeLeft = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-time", loaderData.getTimeLeft());
plugin.getLoaders().addChunkLoader(loaderData, e.getPlayer(), e.getBlock().getLocation(), timeLeft);
Locale.PLACED_LOADER.send(e.getPlayer(), ChunkPosition.of(e.getBlock().getLocation()));
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onLoaderBreak(BlockBreakEvent e){
Location blockLoc = e.getBlock().getLocation();
Optional<ChunkLoader> optionalChunkLoader = plugin.getLoaders().getChunkLoader(blockLoc);
if(!optionalChunkLoader.isPresent())
return;
ChunkLoader chunkLoader = optionalChunkLoader.get();
chunkLoader.remove();
if(e.getPlayer().getGameMode() != GameMode.CREATIVE)
blockLoc.getWorld().dropItemNaturally(blockLoc, chunkLoader.getLoaderItem());
Locale.BROKE_LOADER.send(e.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpawnerPlace(BlockPlaceEvent e){
if(e.getBlock().getType() != Materials.SPAWNER.toBukkitType())
return;
if(!plugin.getLoaders().getChunkLoader(e.getBlock().getChunk()).isPresent())
return;
plugin.getNMSAdapter().updateSpawner(e.getBlock().getLocation(), false);
}
}

View File

@ -0,0 +1,26 @@
package com.bgsoftware.wildloaders.listeners;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkUnloadEvent;
@SuppressWarnings("unused")
public final class ChunksListener implements Listener {
private final WildLoadersPlugin plugin;
public ChunksListener(WildLoadersPlugin plugin){
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onChunkUnload(ChunkUnloadEvent e){
try {
if (plugin.getLoaders().getChunkLoader(e.getChunk()).isPresent())
e.setCancelled(true);
}catch (Throwable ignored){}
}
}

View File

@ -0,0 +1,35 @@
package com.bgsoftware.wildloaders.listeners;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
public final class PlayersListener implements Listener {
private WildLoadersPlugin plugin;
public PlayersListener(WildLoadersPlugin plugin){
this.plugin = plugin;
}
/**
* In some versions, the loaders can die even if they are in creative.
* This should fix the issue.
*/
@EventHandler(priority = EventPriority.LOWEST)
public void onLoaderDamage(EntityDamageEvent e){
if(!(e.getEntity() instanceof LivingEntity))
return;
if(plugin.getNPCs().isNPC((LivingEntity) e.getEntity())) {
e.setCancelled(true);
e.setDamage(0D);
}
}
}

View File

@ -0,0 +1,93 @@
package com.bgsoftware.wildloaders.loaders;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
import java.util.UUID;
public final class WChunkLoader implements ChunkLoader {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
private final UUID whoPlaced;
private final Location location;
private final String loaderName;
private boolean active = true;
private long timeLeft;
public WChunkLoader(String loaderName, Player whoPlaced, Location location, long timeLeft){
this.loaderName = loaderName;
this.whoPlaced = whoPlaced.getUniqueId();
this.location = location.clone();
this.timeLeft = timeLeft;
plugin.getNMSAdapter().createLoader(this);
}
@Override
public LoaderData getLoaderData() {
return plugin.getLoaders().getLoaderData(loaderName).orElse(null);
}
@Override
public OfflinePlayer getWhoPlaced() {
return Bukkit.getOfflinePlayer(whoPlaced);
}
public boolean isNotActive(){
if(active)
active = plugin.getLoaders().getChunkLoader(getLocation()).orElse(null) == this;
return !active;
}
@Override
public long getTimeLeft() {
return timeLeft;
}
public void tick(){
timeLeft--;
if(timeLeft < 0) {
remove();
}
}
@Override
public Location getLocation() {
return location.clone();
}
@Override
public Optional<ChunkLoaderNPC> getNPC() {
return plugin.getNPCs().getNPC(location);
}
@Override
public void remove() {
if(!Bukkit.isPrimaryThread()){
Bukkit.getScheduler().runTask(plugin, this::remove);
return;
}
plugin.getNMSAdapter().removeLoader(this, timeLeft <= 0 || isNotActive());
plugin.getLoaders().removeChunkLoader(this);
getLocation().getBlock().setType(Material.AIR);
}
@Override
public ItemStack getLoaderItem() {
ItemStack itemStack = getLoaderData().getLoaderItem();
return plugin.getNMSAdapter().setTag(itemStack, "loader-time", getTimeLeft());
}
}

View File

@ -0,0 +1,35 @@
package com.bgsoftware.wildloaders.loaders;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import org.bukkit.inventory.ItemStack;
public final class WLoaderData implements LoaderData {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
private final String name;
private final long timeLeft;
private final ItemStack loaderItem;
public WLoaderData(String name, long timeLeft, ItemStack loaderItem){
this.name = name;
this.timeLeft = timeLeft;
this.loaderItem = plugin.getNMSAdapter().setTag(loaderItem, "loader-name", name);
}
@Override
public String getName() {
return name;
}
@Override
public long getTimeLeft() {
return timeLeft;
}
@Override
public ItemStack getLoaderItem() {
return loaderItem.clone();
}
}

View File

@ -0,0 +1,707 @@
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().length; // 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;
}
}
}

View File

@ -0,0 +1,31 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import java.util.UUID;
public interface NMSAdapter {
String getTag(ItemStack itemStack, String key, String def);
ItemStack setTag(ItemStack itemStack, String key, String value);
long getTag(ItemStack itemStack, String key, long def);
ItemStack setTag(ItemStack itemStack, String key, long value);
ItemStack getPlayerSkull(ItemStack itemStack, String texture);
ChunkLoaderNPC createNPC(Location location, UUID uuid);
void createLoader(ChunkLoader chunkLoader);
void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle);
void updateSpawner(Location location, boolean reset);
}

View File

@ -0,0 +1,81 @@
package com.bgsoftware.wildloaders.npc;
import io.netty.channel.AbstractChannel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.EventLoop;
import java.net.SocketAddress;
public final class DummyChannel extends AbstractChannel {
public DummyChannel(){
super(null);
}
@Override
protected AbstractUnsafe newUnsafe() {
return null;
}
@Override
protected boolean isCompatible(EventLoop eventLoop) {
return false;
}
@Override
protected SocketAddress localAddress0() {
return null;
}
@Override
protected SocketAddress remoteAddress0() {
return null;
}
@Override
protected void doBind(SocketAddress socketAddress){
}
@Override
protected void doDisconnect(){
}
@Override
protected void doClose(){
}
@Override
protected void doBeginRead(){
}
@Override
protected void doWrite(ChannelOutboundBuffer channelOutboundBuffer){
}
@Override
public ChannelConfig config() {
return null;
}
@Override
public boolean isOpen() {
return false;
}
@Override
public boolean isActive() {
return false;
}
@Override
public ChannelMetadata metadata() {
return null;
}
}

View File

@ -0,0 +1,56 @@
package com.bgsoftware.wildloaders.utils;
import org.bukkit.Bukkit;
public enum ServerVersion {
v1_7(17),
v1_8(18),
v1_9(19),
v1_10(110),
v1_11(111),
v1_12(112),
v1_13(113),
v1_14(114),
v1_15(115),
v1_16(116);
private static final ServerVersion currentVersion;
private static final String bukkitVersion;
private static final boolean legacy;
static {
bukkitVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
String[] sections = bukkitVersion.split("_");
currentVersion = ServerVersion.valueOf(sections[0] + "_" + sections[1]);
legacy = isLessThan(ServerVersion.v1_13);
}
private final int code;
ServerVersion(int code){
this.code = code;
}
public static boolean isAtLeast(ServerVersion serverVersion){
return currentVersion.code >= serverVersion.code;
}
public static boolean isLessThan(ServerVersion serverVersion){
return currentVersion.code < serverVersion.code;
}
public static boolean isEquals(ServerVersion serverVersion){
return currentVersion.code == serverVersion.code;
}
public static boolean isLegacy(){
return legacy;
}
public static String getBukkitVersion(){
return bukkitVersion;
}
}

View File

@ -0,0 +1,101 @@
package com.bgsoftware.wildloaders.utils;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public final class TimeUtils {
private static final int MINUTES = 60, HOURS = 3600, DAYS = 86400;
public static long fromString(String time){
Map<TimeUnit, Integer> timeUnits = parseString(time);
long timeValue = 0;
for(Map.Entry<TimeUnit, Integer> entry : timeUnits.entrySet()){
switch (entry.getKey()){
case SECONDS:
timeValue += entry.getValue();
break;
case MINUTES:
timeValue += entry.getValue() * MINUTES;
break;
case HOURS:
timeValue += entry.getValue() * HOURS;
break;
case DAYS:
timeValue += entry.getValue() * DAYS;
break;
}
}
return timeValue;
}
private static Map<TimeUnit, Integer> parseString(String str){
Map<TimeUnit, Integer> timeUnits = Maps.newHashMap();
TimeUnit timeUnit;
StringBuilder value = new StringBuilder();
for(int i = 0; i < str.length(); i++){
char ch = str.charAt(i);
if(Character.isDigit(ch)){
value.append(ch);
}
if(!Character.isDigit(ch) || i == str.length() - 1){
int timeValue = -1;
try {
timeValue = Integer.parseInt(value.toString());
}catch(Exception ignored){}
switch (ch){
case 'm':
case 'M':
timeUnit = TimeUnit.MINUTES;
break;
case 'h':
case 'H':
timeUnit = TimeUnit.HOURS;
break;
case 'd':
case 'D':
timeUnit = TimeUnit.DAYS;
break;
default:
timeUnit = TimeUnit.SECONDS;
break;
}
if(timeValue != -1 && !timeUnits.containsKey(timeUnit)){
timeUnits.put(timeUnit, timeValue);
}
value = new StringBuilder();
}
}
return timeUnits;
}
public static String[] formatTime(long time){
String[] result = new String[4];
result[0] = String.valueOf(time / DAYS);
time = time % DAYS;
result[1] = String.valueOf(time / HOURS);
time = time % HOURS;
result[2] = String.valueOf(time / MINUTES);
time = time % MINUTES;
result[3] = String.valueOf(time);
return result;
}
}

View File

@ -0,0 +1,59 @@
package com.bgsoftware.wildloaders.utils.chunks;
import org.bukkit.Chunk;
import org.bukkit.Location;
import java.util.Objects;
public final class ChunkPosition {
private final String world;
private final int x, z;
private ChunkPosition(String world, int x, int z){
this.world = world;
this.x = x;
this.z = z;
}
public String getWorld() {
return world;
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
@Override
public String toString() {
return world + ", " + x + ", " + z;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChunkPosition that = (ChunkPosition) o;
return x == that.x &&
z == that.z &&
world.equals(that.world);
}
@Override
public int hashCode() {
return Objects.hash(world, x, z);
}
public static ChunkPosition of(Location location){
return new ChunkPosition(location.getWorld().getName(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
public static ChunkPosition of(Chunk chunk){
return new ChunkPosition(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
}
}

View File

@ -0,0 +1,462 @@
/*******************************************************************************
*
* CommentedConfiguration
* Developed by Ome_R
*
* You may use the resource and/or modify it - but not
* claiming it as your own work. You are not allowed
* to remove this message, unless being permitted by
* the developer of the resource.
*
* Spigot: https://www.spigotmc.org/resources/authors/ome_r.25629/
* MC-Market: https://www.mc-market.org/resources/authors/40228/
* Github: https://github.com/OmerBenGera?tab=repositories
* Website: https://bg-software.com/
*
*******************************************************************************/
package com.bgsoftware.wildloaders.utils.config;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class CommentedConfiguration extends YamlConfiguration {
/**
* Holds all comments for the config.
* Can be accessed by using the methods that are provided
* by the class.
*/
private final Map<String, String> configComments = new HashMap<>();
/**
* Sync the config with another resource.
* This method can be used as an auto updater for your config files.
* @param file The file to save changes into if there are any.
* @param resource The resource to sync with. Can be provided by JavaPlugin#getResource
* @param ignoredSections An array of sections that will be ignored, and won't get updated
* if they are already exist in the config. If they are not in the
* config, they will be synced with the resource's config.
*/
public void syncWithConfig(File file, InputStream resource, String... ignoredSections){
CommentedConfiguration cfg = loadConfiguration(resource);
if(syncConfigurationSection(cfg, cfg.getConfigurationSection(""), Arrays.asList(ignoredSections)) && file != null) {
try {
save(file);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* Set a new comment to a path.
* You can remove comments by providing a null as a comment argument.
* @param path The path to set the comment to.
* @param comment The comment to set. Supports multiple lines (use \n as a spacer).
*/
public void setComment(String path, String comment){
if(comment == null)
configComments.remove(path);
else
configComments.put(path, comment);
}
/**
* Get a comment of a path.
* @param path The path to get the comment of.
* @return Returns a string that contains the comment. If no comment exists, null will be returned.
*/
public String getComment(String path){
return getComment(path, null);
}
/**
* Get a comment of a path with a default value if no comment exists.
* @param path The path to get the comment of.
* @param def A default comment that will be returned if no comment exists for the path.
* @return Returns a string that contains the comment. If no comment exists, the def value will be returned.
*/
public String getComment(String path, String def){
return configComments.getOrDefault(path, def);
}
/**
* Checks whether or not a path has a comment.
* @param path The path to check.
* @return Returns true if there's an existing comment, otherwise false.
*/
public boolean containsComment(String path){
return getComment(path) != null;
}
/**
* Load all data related to the config file - keys, values and comments.
* @param contents The contents of the file.
* @throws InvalidConfigurationException if the contents are invalid.
*/
@Override
public void loadFromString(String contents) throws InvalidConfigurationException {
//Load data of the base yaml (keys and values).
super.loadFromString(contents);
//Parse the contents into lines.
String[] lines = contents.split("\n");
int currentIndex = 0;
//Variables that are used to track progress.
StringBuilder comments = new StringBuilder();
String currentSection = "";
while(currentIndex < lines.length){
//Checking if the current line is a comment.
if(isComment(lines[currentIndex])){
//Adding the comment to the builder with an enter at the end.
comments.append(lines[currentIndex]).append("\n");
}
//Checking if the current line is a valid new section.
else if(isNewSection(lines[currentIndex])){
//Parsing the line into a full-path.
currentSection = getSectionPath(this, lines[currentIndex], currentSection);
//If there is a valid comment for the section.
if(comments.length() > 0)
//Adding the comment.
setComment(currentSection, comments.toString().substring(0, comments.length() - 1));
//Reseting the comment variable for further usage.
comments = new StringBuilder();
}
//Skipping to the next line.
currentIndex++;
}
}
@Override
public void save(File file){
try {
super.save(file);
}catch(Exception ex){
ex.printStackTrace();
}
}
/**
* Parsing all the data (keys, values and comments) into a valid string, that will be written into a file later.
* @return A string that contains all the data, ready to be written into a file.
*/
@Override
public String saveToString() {
//First, we set headers to null - as we will handle all comments, including headers, in this method.
this.options().header(null);
//Get the string of the data (keys and values) and parse it into an array of lines.
List<String> lines = new ArrayList<>(Arrays.asList(super.saveToString().split("\n")));
//Variables that are used to track progress.
int currentIndex = 0;
String currentSection = "";
while(currentIndex < lines.size()){
String line = lines.get(currentIndex);
//Checking if the line is a new section.
if(isNewSection(line)){
//Parsing the line into a full-path.
currentSection = getSectionPath(this, line, currentSection);
//Checking if that path contains a comment
if(containsComment(currentSection)) {
//Adding the comment to the lines array at that index (adding it one line before the actual line)
lines.add(currentIndex, getComment(currentSection));
//Skipping one line so the pointer will point to the line we checked again.
currentIndex++;
}
}
//Skipping to the next line.
currentIndex++;
}
//Parsing the array of lines into a one single string.
StringBuilder contents = new StringBuilder();
for(String line : lines)
contents.append("\n").append(line);
return contents.length() == 0 ? "" : contents.substring(1);
}
/**
* Sync a specific configuration section with another one, recursively.
* @param commentedConfig The config that contains the data we need to sync with.
* @param section The current section that we sync.
* @param ignoredSections A list of ignored sections that won't be synced (unless not found in the file).
* @return Returns true if there were any changes, otherwise false.
*/
private boolean syncConfigurationSection(CommentedConfiguration commentedConfig, ConfigurationSection section, List<String> ignoredSections){
//Variables that are used to track progress.
boolean changed = false;
//Going through all the keys of the section.
for (String key : section.getKeys(false)) {
//Parsing the key into a full-path.
String path = section.getCurrentPath().isEmpty() ? key : section.getCurrentPath() + "." + key;
//Checking if the key is also a section.
if (section.isConfigurationSection(key)) {
//Checking if the section is ignored.
boolean isIgnored = ignoredSections.stream().anyMatch(path::contains);
//Checking if the config contains the section.
boolean containsSection = contains(path);
//If the config doesn't contain the section, or it's not ignored - we will sync data.
if(!containsSection || !isIgnored) {
//Syncing data and updating the changed variable.
changed = syncConfigurationSection(commentedConfig, section.getConfigurationSection(key), ignoredSections) || changed;
}
}
//Checking if the config contains the path (not a section).
else if (!contains(path)) {
//Saving the value of the key into the config.
set(path, section.get(key));
//Updating variables.
changed = true;
}
//Checking if there is a valid comment for the path, and also making sure the comments are not the same.
if (commentedConfig.containsComment(path) && !commentedConfig.getComment(path).equals(getComment(path))) {
//Saving the comment of the key into the config.
setComment(path, commentedConfig.getComment(path));
//Updating variable.
changed = true;
}
}
/*Keys cannot be ordered easily, so we need to do some tricks to make sure
all of the keys are ordered correctly (and the new config will look the same
as the resource that was provided).*/
//Checking if there was a value that had been added into the config
if(changed)
correctIndexes(section, getConfigurationSection(section.getCurrentPath()));
return changed;
}
/**
* Load a config from a file.
* @param file The file to load the config from.
* @return A new instance of CommentedConfiguration contains all the data (keys, values and comments).
*/
public static CommentedConfiguration loadConfiguration(File file) {
try {
FileInputStream stream = new FileInputStream(file);
return loadConfiguration(new InputStreamReader(stream, StandardCharsets.UTF_8));
}catch(FileNotFoundException ex){
Bukkit.getLogger().warning("File " + file.getName() + " doesn't exist.");
return new CommentedConfiguration();
}
}
/**
* Load a config from an input-stream, which is used for resources that are obtained using JavaPlugin#getResource.
* @param inputStream The input-stream to load the config from.
* @return A new instance of CommentedConfiguration contains all the data (keys, values and comments).
*/
public static CommentedConfiguration loadConfiguration(InputStream inputStream) {
return loadConfiguration(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
}
/**
* Load a config from a reader (used for files and streams together).
* @param reader The reader to load the config from.
* @return A new instance of CommentedConfiguration contains all the data (keys, values and comments).
*/
public static CommentedConfiguration loadConfiguration(Reader reader) {
//Creating a blank instance of the config.
CommentedConfiguration config = new CommentedConfiguration();
//Parsing the reader into a BufferedReader for an easy reading of it.
try(BufferedReader bufferedReader = reader instanceof BufferedReader ? (BufferedReader)reader : new BufferedReader(reader)){
StringBuilder contents = new StringBuilder();
String line;
while((line = bufferedReader.readLine()) != null) {
contents.append(line).append('\n');
}
config.loadFromString(contents.toString());
} catch (IOException | InvalidConfigurationException ex) {
ex.printStackTrace();
}
return config;
}
/**
* Checks if a line is a new section or not.
* Sadly, that's not possible to use ":" as a spacer between key and value, and ": " must be used.
* @param line The line to check.
* @return True if the line is a new section, otherwise false.
*/
private static boolean isNewSection(String line){
String trimLine = line.trim();
return trimLine.contains(": ") || trimLine.endsWith(":");
}
/**
* Creates a full path of a line.
* @param commentedConfig The config to get the path from.
* @param line The line to get the path of.
* @param currentSection The last known section.
* @return The full path of the line.
*/
private static String getSectionPath(CommentedConfiguration commentedConfig, String line, String currentSection){
//Removing all spaces and getting the name of the section.
String newSection = line.trim().split(": ")[0];
//Parsing some formats to make sure having a plain name.
if(newSection.endsWith(":"))
newSection = newSection.substring(0, newSection.length() - 1);
if(newSection.startsWith("."))
newSection = newSection.substring(1);
if(newSection.startsWith("'") && newSection.endsWith("'"))
newSection = newSection.substring(1, newSection.length() - 1);
//Checking if the new section is a child-section of the currentSection.
if(!currentSection.isEmpty() && commentedConfig.contains(currentSection + "." + newSection)){
newSection = currentSection + "." + newSection;
}
//Looking for the parent of the the new section.
else{
String parentSection = currentSection;
/*Getting the parent of the new section. The loop will stop in one of the following situations:
1) The parent is empty - which means we have no where to go, as that's the root section.
2) The config contains a valid path that was built with <parent-section>.<new-section>.*/
while(!parentSection.isEmpty() &&
!commentedConfig.contains((parentSection = getParentPath(parentSection)) + "." + newSection));
//Parsing and building the new full path.
newSection = parentSection.trim().isEmpty() ? newSection : parentSection + "." + newSection;
}
return newSection;
}
/**
* Checks if a line represents a comment or not.
* @param line The line to check.
* @return True if the line is a comment (stars with # or it's empty), otherwise false.
*/
private static boolean isComment(String line){
String trimLine = line.trim();
return trimLine.startsWith("#") || trimLine.isEmpty();
}
/**
* Get the parent path of the provided path, by removing the last '.' from the path.
* @param path The path to check.
* @return The parent path of the provided path.
*/
private static String getParentPath(String path){
return path.contains(".") ? path.substring(0, path.lastIndexOf('.')) : "";
}
/**
* Convert key-indexes of a section into the same key-indexes that another section has.
* @param section The section that will be used as a way to get the correct indexes.
* @param target The target section that will be ordered again.
*/
private static void correctIndexes(ConfigurationSection section, ConfigurationSection target){
//Parsing the sections into ArrayLists with their keys and values.
List<Pair<String, Object>> sectionMap = getSectionMap(section), correctOrder = new ArrayList<>();
//Going through the sectionMap, which is in the correct order.
for (Pair<String, Object> entry : sectionMap) {
//Adding the entry into a new list with the correct value from the target section.
correctOrder.add(new Pair<>(entry.key, target.get(entry.key)));
}
/*The only way to change key-indexes is to add them one-by-one again, in the correct order.
In order to do so, the section needs to be cleared so the indexes will be reset.*/
//Clearing the configuration.
clearConfiguration(target);
//Adding the entries again in the correct order.
for(Pair<String, Object> entry : correctOrder)
target.set(entry.key, entry.value);
}
/**
* Parsing a section into a list that contains all of it's keys and their values without changing their order.
* @param section The section to convert.
* @return A list that contains all the keys and their values.
*/
private static List<Pair<String, Object>> getSectionMap(ConfigurationSection section){
//Creating an empty ArrayList.
List<Pair<String, Object>> list = new ArrayList<>();
//Going through all the keys and adding them in the same order.
for(String key : section.getKeys(false)) {
list.add(new Pair<>(key, section.get(key)));
}
return list;
}
/**
* Clear a configuration section from all of it's keys.
* This can be done by setting all the keys' values to null.
* @param section The section to clear.
*/
private static void clearConfiguration(ConfigurationSection section){
for(String key : section.getKeys(false))
section.set(key, null);
}
/**
* A class that is used as a way of representing a map's entry (which is not implemented).
*/
private static class Pair<K, V>{
private final K key;
private final V value;
Pair(K key, V value){
this.key = key;
this.value = value;
}
@Override
public boolean equals(Object obj) {
return obj instanceof Pair && key.equals(((Pair) obj).key) && value.equals(((Pair) obj).value);
}
@Override
public int hashCode() {
return key.hashCode();
}
}
}

View File

@ -0,0 +1,79 @@
package com.bgsoftware.wildloaders.utils.items;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.Arrays;
import java.util.List;
@SuppressWarnings("WeakerAccess")
public final class ItemBuilder {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
private final ItemStack itemStack;
private final ItemMeta itemMeta;
private String texture = "";
public ItemBuilder(Material type){
this(type, 1);
}
public ItemBuilder(Material type, int amount){
this(type, amount, (short) 0);
}
public ItemBuilder(Material type, short damage){
this(type, 1, damage);
}
public ItemBuilder(Material type, int amount, short damage){
this(new ItemStack(type, amount, damage));
}
public ItemBuilder(ItemStack itemStack){
this.itemStack = itemStack;
this.itemMeta = itemStack.getItemMeta();
}
public ItemBuilder setDisplayName(String name){
itemMeta.setDisplayName(name);
return this;
}
public ItemBuilder setLore(String... lore){
return setLore(Arrays.asList(lore));
}
public ItemBuilder setLore(List<String> lore){
itemMeta.setLore(lore);
return this;
}
public ItemBuilder setOwner(String playerName){
if(itemMeta instanceof SkullMeta){
((SkullMeta) itemMeta).setOwner(playerName);
}
return this;
}
public ItemBuilder setTexture(String texture){
this.texture = texture;
return this;
}
public ItemBuilder addEnchant(Enchantment ench, int level){
itemMeta.addEnchant(ench, level, true);
return this;
}
public ItemStack build(){
itemStack.setItemMeta(itemMeta);
return texture.isEmpty() ? itemStack : plugin.getNMSAdapter().getPlayerSkull(itemStack, texture);
}
}

View File

@ -0,0 +1,21 @@
package com.bgsoftware.wildloaders.utils.items;
import org.bukkit.Location;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
public final class ItemUtils {
private ItemUtils(){
}
public static void addItems(Inventory inventory, Location location, ItemStack... itemStacks){
HashMap<Integer, ItemStack> leftOvers = inventory.addItem(itemStacks);
if(!leftOvers.isEmpty() && location != null)
leftOvers.values().forEach(itemStack -> location.getWorld().dropItemNaturally(location, itemStack));
}
}

View File

@ -0,0 +1,42 @@
package com.bgsoftware.wildloaders.utils.legacy;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
public enum Materials {
SPAWNER("MOB_SPAWNER");
Materials(String bukkitType){
this(bukkitType, 0);
}
Materials(String bukkitType, int bukkitData){
this.bukkitType = bukkitType;
this.bukkitData = (short) bukkitData;
}
private final String bukkitType;
private final short bukkitData;
public Material toBukkitType(){
try {
try {
return Material.valueOf(bukkitType);
} catch (IllegalArgumentException ex) {
return Material.valueOf(name());
}
}catch(Exception ex){
throw new IllegalArgumentException("Couldn't cast " + name() + " into a bukkit enum. Contact Ome_R!");
}
}
public ItemStack toBukkitItem(){
return toBukkitItem(1);
}
public ItemStack toBukkitItem(int amount){
return bukkitData == 0 ? new ItemStack(toBukkitType(), amount) : new ItemStack(toBukkitType(), amount, bukkitData);
}
}

View File

@ -0,0 +1,36 @@
package com.bgsoftware.wildloaders.utils.locations;
import org.bukkit.Bukkit;
import org.bukkit.Location;
public final class LocationUtils {
private LocationUtils(){}
public static String getLocation(Location location){
return location.getWorld().getName() + "," + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ();
}
public static Location getLocation(String location){
String[] locationSections = location.split(",");
if(locationSections.length != 4)
throw new IllegalArgumentException("Cannot parse location " + location);
String worldName = locationSections[0];
double x = parseDouble(locationSections[1]);
double y = parseDouble(locationSections[2]);
double z = parseDouble(locationSections[3]);
return new Location(Bukkit.getWorld(worldName), x, y, z);
}
private static double parseDouble(String str){
try{
return Double.parseDouble(str);
}catch (Exception ex){
throw new IllegalArgumentException("Cannot parse double " + str);
}
}
}

View File

@ -0,0 +1,22 @@
#######################################################
## ##
## WildLoaders Configuration ##
## Developed by Ome_R ##
## ##
#######################################################
hologram-lines:
- '&b{0}''s Loader'
- '&bTime Left: &f{1} days, {2} hours, {3} minutes, {4} seconds'
# List of all the chunk-loaders
# Do not name 2 chunk-loaders the same
chunkloaders:
normal_loader:
time: 1 #1 stands for 1x1 chunks, 3 for 3x3 and so on.
type: SPONGE
data: 1
name: '&6Chunk Buster &7(Place to bust)'
lore:
- '&7Place this chunk buster'
- '&7to bust the chunk!'

View File

@ -0,0 +1,21 @@
#######################################################
## ##
## WildLoaders Configuration ##
## Developed by Ome_R ##
## ##
#######################################################
ALREADY_LOADED: '&a&lWildLoaders &7This chunk is already loaded.'
BROKE_LOADER: '&a&lWildLoaders &7Successfully broken this chunk-loader.'
COMMAND_USAGE: '&cUsage: /{0}'
GIVE_SUCCESS: '&a&lWildLoaders &7Successfully gave x{0} {1} to {2}.'
HELP_COMMAND_HEADER: '&a&lWildLoaders &7Plugin Commands:'
HELP_COMMAND_LINE: '&a/{0} &7- {1}'
HELP_COMMAND_FOOTER: ''
INVALID_AMOUNT: '&a&lWildLoaders &7Invalid amount {0}.'
INVALID_LOADER: '&a&lWildLoaders &7Couldn''t find a valid chunk-loader with the name {0}.'
INVALID_PLAYER: '&a&lWildLoaders &7Couldn''t find a player with the name {0}.'
NO_PERMISSION: '&fUnknown command. Type "/help" for help.'
NO_PLACE_PERMISSION: '&a&lWildLoaders &7You are lacking the permission to place chunk loaders.'
PLACED_LOADER: '&a&lWildLoaders &7Successfully placed a new chunk-loader at {0}.'
RECEIVE_SUCCESS: '&a&lWildLoaders &7You received x{0} {1} from {2}.'

View File

@ -0,0 +1,18 @@
name: WildLoaders
version: 0.0.1
api-version: 1.13
main: com.bgsoftware.wildloaders.WildLoadersPlugin
description: Highly configurable and optimized chunk-loaders plugin.
website: https://bg-software.com/
authors: [Ome_R]
commands:
loader:
description: Main command for wild loaders.
permissions:
wildloaders.*:
description: Gives access to all the commands.
default: op
children:
wildloaders.use: true
wildloaders.use:
description: Gives access to place a chunkloader.

View File

@ -0,0 +1,145 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_10_R1.DamageSource;
import net.minecraft.server.v1_10_R1.EntityPlayer;
import net.minecraft.server.v1_10_R1.EnumGamemode;
import net.minecraft.server.v1_10_R1.EnumProtocolDirection;
import net.minecraft.server.v1_10_R1.MinecraftServer;
import net.minecraft.server.v1_10_R1.NetworkManager;
import net.minecraft.server.v1_10_R1.Packet;
import net.minecraft.server.v1_10_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_10_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_10_R1.PacketPlayInChat;
import net.minecraft.server.v1_10_R1.PacketPlayInFlying;
import net.minecraft.server.v1_10_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_10_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_10_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_10_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_10_R1.PlayerConnection;
import net.minecraft.server.v1_10_R1.PlayerInteractManager;
import net.minecraft.server.v1_10_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_10_R1.CraftServer;
import org.bukkit.craftbukkit.v1_10_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_10_R1 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_10_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
protected boolean damageEntity0(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,282 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_10_R1.AxisAlignedBB;
import net.minecraft.server.v1_10_R1.Block;
import net.minecraft.server.v1_10_R1.BlockPosition;
import net.minecraft.server.v1_10_R1.Chunk;
import net.minecraft.server.v1_10_R1.Entity;
import net.minecraft.server.v1_10_R1.EntityArmorStand;
import net.minecraft.server.v1_10_R1.ITickable;
import net.minecraft.server.v1_10_R1.ItemStack;
import net.minecraft.server.v1_10_R1.NBTTagCompound;
import net.minecraft.server.v1_10_R1.NBTTagList;
import net.minecraft.server.v1_10_R1.NBTTagLong;
import net.minecraft.server.v1_10_R1.NBTTagString;
import net.minecraft.server.v1_10_R1.TileEntity;
import net.minecraft.server.v1_10_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_10_R1.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_10_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_10_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_10_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_10_R1.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings({"ConstantConditions", "unused"})
public final class NMSAdapter_v1_10_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_10_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
setPosition(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void E_() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,145 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_11_R1.DamageSource;
import net.minecraft.server.v1_11_R1.EntityPlayer;
import net.minecraft.server.v1_11_R1.EnumGamemode;
import net.minecraft.server.v1_11_R1.EnumProtocolDirection;
import net.minecraft.server.v1_11_R1.MinecraftServer;
import net.minecraft.server.v1_11_R1.NetworkManager;
import net.minecraft.server.v1_11_R1.Packet;
import net.minecraft.server.v1_11_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_11_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_11_R1.PacketPlayInChat;
import net.minecraft.server.v1_11_R1.PacketPlayInFlying;
import net.minecraft.server.v1_11_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_11_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_11_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_11_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_11_R1.PlayerConnection;
import net.minecraft.server.v1_11_R1.PlayerInteractManager;
import net.minecraft.server.v1_11_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_11_R1.CraftServer;
import org.bukkit.craftbukkit.v1_11_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_11_R1 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_11_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
protected boolean damageEntity0(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,282 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_11_R1.AxisAlignedBB;
import net.minecraft.server.v1_11_R1.Block;
import net.minecraft.server.v1_11_R1.BlockPosition;
import net.minecraft.server.v1_11_R1.Chunk;
import net.minecraft.server.v1_11_R1.Entity;
import net.minecraft.server.v1_11_R1.EntityArmorStand;
import net.minecraft.server.v1_11_R1.ITickable;
import net.minecraft.server.v1_11_R1.ItemStack;
import net.minecraft.server.v1_11_R1.NBTTagCompound;
import net.minecraft.server.v1_11_R1.NBTTagList;
import net.minecraft.server.v1_11_R1.NBTTagLong;
import net.minecraft.server.v1_11_R1.NBTTagString;
import net.minecraft.server.v1_11_R1.TileEntity;
import net.minecraft.server.v1_11_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_11_R1.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_11_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_11_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_11_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_11_R1.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings({"ConstantConditions", "unused"})
public final class NMSAdapter_v1_11_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_11_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
setPosition(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void F_() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,143 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_12_R1.DamageSource;
import net.minecraft.server.v1_12_R1.EntityPlayer;
import net.minecraft.server.v1_12_R1.EnumGamemode;
import net.minecraft.server.v1_12_R1.EnumProtocolDirection;
import net.minecraft.server.v1_12_R1.MinecraftServer;
import net.minecraft.server.v1_12_R1.NetworkManager;
import net.minecraft.server.v1_12_R1.Packet;
import net.minecraft.server.v1_12_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_12_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_12_R1.PacketPlayInChat;
import net.minecraft.server.v1_12_R1.PacketPlayInFlying;
import net.minecraft.server.v1_12_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_12_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_12_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_12_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_12_R1.PlayerConnection;
import net.minecraft.server.v1_12_R1.PlayerInteractManager;
import net.minecraft.server.v1_12_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_12_R1 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_12_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
a(EnumGamemode.CREATIVE);
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
protected boolean damageEntity0(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,305 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_12_R1.AxisAlignedBB;
import net.minecraft.server.v1_12_R1.Block;
import net.minecraft.server.v1_12_R1.BlockPosition;
import net.minecraft.server.v1_12_R1.Chunk;
import net.minecraft.server.v1_12_R1.Entity;
import net.minecraft.server.v1_12_R1.EntityArmorStand;
import net.minecraft.server.v1_12_R1.ITickable;
import net.minecraft.server.v1_12_R1.ItemStack;
import net.minecraft.server.v1_12_R1.NBTTagCompound;
import net.minecraft.server.v1_12_R1.NBTTagList;
import net.minecraft.server.v1_12_R1.NBTTagLong;
import net.minecraft.server.v1_12_R1.NBTTagString;
import net.minecraft.server.v1_12_R1.TileEntity;
import net.minecraft.server.v1_12_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_12_R1.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_12_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_12_R1.util.LongHash;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings({"ConstantConditions", "unused"})
public final class NMSAdapter_v1_12_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
private static Method compoundLoadMethod = null;
static {
try{
//noinspection JavaReflectionMemberAccess
compoundLoadMethod = TileEntity.class.getMethod("load", NBTTagCompound.class);
}catch (Exception ignored){}
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_12_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
try {
compoundLoadMethod.invoke(tileEntity, nbtTagCompound);
}catch (Throwable ex){
tileEntity.a(nbtTagCompound);
}
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
try {
compoundLoadMethod.invoke(tileEntity, nbtTagCompound);
}catch (Throwable ex){
tileEntity.a(nbtTagCompound);
}
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
try {
compoundLoadMethod.invoke(mobSpawner, nbtTagCompound);
}catch (Throwable ex){
mobSpawner.a(nbtTagCompound);
}
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
setPosition(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void e() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand{
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,146 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_13_R1.DamageSource;
import net.minecraft.server.v1_13_R1.EntityPlayer;
import net.minecraft.server.v1_13_R1.EnumGamemode;
import net.minecraft.server.v1_13_R1.EnumProtocolDirection;
import net.minecraft.server.v1_13_R1.MinecraftServer;
import net.minecraft.server.v1_13_R1.NetworkManager;
import net.minecraft.server.v1_13_R1.Packet;
import net.minecraft.server.v1_13_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_13_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_13_R1.PacketPlayInChat;
import net.minecraft.server.v1_13_R1.PacketPlayInFlying;
import net.minecraft.server.v1_13_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_13_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_13_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_13_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_13_R1.PlayerConnection;
import net.minecraft.server.v1_13_R1.PlayerInteractManager;
import net.minecraft.server.v1_13_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R1.CraftServer;
import org.bukkit.craftbukkit.v1_13_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_13_R1 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_13_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
MinecraftServer minecraftServer = ((CraftServer) Bukkit.getServer()).getServer();
WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle();
playerConnection = new DummyPlayerConnection(minecraftServer, this);
a(EnumGamemode.CREATIVE);
fauxSleeping = true;
spawnIn(worldServer);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
worldServer.players.add(this);
worldServer.getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
protected boolean damageEntity0(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,278 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_13_R1.AxisAlignedBB;
import net.minecraft.server.v1_13_R1.Block;
import net.minecraft.server.v1_13_R1.BlockPosition;
import net.minecraft.server.v1_13_R1.Chunk;
import net.minecraft.server.v1_13_R1.Entity;
import net.minecraft.server.v1_13_R1.EntityArmorStand;
import net.minecraft.server.v1_13_R1.ITickable;
import net.minecraft.server.v1_13_R1.ItemStack;
import net.minecraft.server.v1_13_R1.NBTTagCompound;
import net.minecraft.server.v1_13_R1.NBTTagList;
import net.minecraft.server.v1_13_R1.NBTTagLong;
import net.minecraft.server.v1_13_R1.NBTTagString;
import net.minecraft.server.v1_13_R1.TileEntity;
import net.minecraft.server.v1_13_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_13_R1.TileEntityTypes;
import net.minecraft.server.v1_13_R1.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_13_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_13_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_13_R1.util.CraftChatMessage;
import org.bukkit.craftbukkit.v1_13_R1.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_13_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@Override
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 8))
return def;
return tagCompound.getString(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 4))
return def;
return tagCompound.getLong(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.getOrCreateTag();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_13_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = -1);
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = 16);
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
if(mobSpawner == null)
return;
mobSpawner.getSpawner().requiredPlayerRange = reset ? 16 : -1;
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
super(TileEntityTypes.w);
this.chunkLoader = chunkLoader;
setPosition(blockPosition);
setWorld(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void Y_() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(CraftChatMessage.fromStringOrNull(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + ""))
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,148 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_13_R2.DamageSource;
import net.minecraft.server.v1_13_R2.EntityPlayer;
import net.minecraft.server.v1_13_R2.EnumGamemode;
import net.minecraft.server.v1_13_R2.EnumProtocolDirection;
import net.minecraft.server.v1_13_R2.MinecraftServer;
import net.minecraft.server.v1_13_R2.NetworkManager;
import net.minecraft.server.v1_13_R2.Packet;
import net.minecraft.server.v1_13_R2.PacketPlayInBlockDig;
import net.minecraft.server.v1_13_R2.PacketPlayInBlockPlace;
import net.minecraft.server.v1_13_R2.PacketPlayInChat;
import net.minecraft.server.v1_13_R2.PacketPlayInFlying;
import net.minecraft.server.v1_13_R2.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_13_R2.PacketPlayInTransaction;
import net.minecraft.server.v1_13_R2.PacketPlayInUpdateSign;
import net.minecraft.server.v1_13_R2.PacketPlayInWindowClick;
import net.minecraft.server.v1_13_R2.PlayerConnection;
import net.minecraft.server.v1_13_R2.PlayerInteractManager;
import net.minecraft.server.v1_13_R2.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R2.CraftServer;
import org.bukkit.craftbukkit.v1_13_R2.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_13_R2 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_13_R2(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
a(EnumGamemode.CREATIVE);
clientViewDistance = 1;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
WorldServer worldServer = getWorldServer();
worldServer.players.remove(this);
worldServer.getPlayerChunkMap().removePlayer(this);
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
protected boolean damageEntity0(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("socketAddress");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,278 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_13_R2.AxisAlignedBB;
import net.minecraft.server.v1_13_R2.Block;
import net.minecraft.server.v1_13_R2.BlockPosition;
import net.minecraft.server.v1_13_R2.Chunk;
import net.minecraft.server.v1_13_R2.Entity;
import net.minecraft.server.v1_13_R2.EntityArmorStand;
import net.minecraft.server.v1_13_R2.ITickable;
import net.minecraft.server.v1_13_R2.ItemStack;
import net.minecraft.server.v1_13_R2.NBTTagCompound;
import net.minecraft.server.v1_13_R2.NBTTagList;
import net.minecraft.server.v1_13_R2.NBTTagLong;
import net.minecraft.server.v1_13_R2.NBTTagString;
import net.minecraft.server.v1_13_R2.TileEntity;
import net.minecraft.server.v1_13_R2.TileEntityMobSpawner;
import net.minecraft.server.v1_13_R2.TileEntityTypes;
import net.minecraft.server.v1_13_R2.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_13_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_13_R2.util.CraftChatMessage;
import org.bukkit.craftbukkit.v1_13_R2.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_13_R2 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@Override
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 8))
return def;
return tagCompound.getString(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 4))
return def;
return tagCompound.getLong(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.getOrCreateTag();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_13_R2(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = -1);
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = 16);
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
if(mobSpawner == null)
return;
mobSpawner.getSpawner().requiredPlayerRange = reset ? 16 : -1;
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
super(TileEntityTypes.COMMAND_BLOCK);
this.chunkLoader = chunkLoader;
setPosition(blockPosition);
setWorld(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void tick() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(CraftChatMessage.fromStringOrNull(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + ""))
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,147 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_14_R1.EntityPlayer;
import net.minecraft.server.v1_14_R1.EnumGamemode;
import net.minecraft.server.v1_14_R1.EnumProtocolDirection;
import net.minecraft.server.v1_14_R1.MinecraftServer;
import net.minecraft.server.v1_14_R1.NetworkManager;
import net.minecraft.server.v1_14_R1.Packet;
import net.minecraft.server.v1_14_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_14_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_14_R1.PacketPlayInChat;
import net.minecraft.server.v1_14_R1.PacketPlayInFlying;
import net.minecraft.server.v1_14_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_14_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_14_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_14_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_14_R1.PlayerConnection;
import net.minecraft.server.v1_14_R1.PlayerInteractManager;
import net.minecraft.server.v1_14_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_14_R1 extends EntityPlayer implements ChunkLoaderNPC {
private boolean dieCall = false;
public ChunkLoaderNPC_v1_14_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
a(EnumGamemode.CREATIVE);
clientViewDistance = 1;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
((WorldServer) world).addPlayerJoin(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
if(!dieCall) {
dieCall = true;
getWorldServer().removePlayer(this);
dieCall = false;
}
else {
super.die();
}
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("socketAddress");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,293 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_14_R1.AxisAlignedBB;
import net.minecraft.server.v1_14_R1.Block;
import net.minecraft.server.v1_14_R1.BlockPosition;
import net.minecraft.server.v1_14_R1.Chunk;
import net.minecraft.server.v1_14_R1.ChunkCoordIntPair;
import net.minecraft.server.v1_14_R1.Entity;
import net.minecraft.server.v1_14_R1.EntityArmorStand;
import net.minecraft.server.v1_14_R1.EntityTypes;
import net.minecraft.server.v1_14_R1.ITickable;
import net.minecraft.server.v1_14_R1.ItemStack;
import net.minecraft.server.v1_14_R1.NBTTagCompound;
import net.minecraft.server.v1_14_R1.NBTTagList;
import net.minecraft.server.v1_14_R1.NBTTagLong;
import net.minecraft.server.v1_14_R1.NBTTagString;
import net.minecraft.server.v1_14_R1.TileEntity;
import net.minecraft.server.v1_14_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_14_R1.TileEntityTypes;
import net.minecraft.server.v1_14_R1.World;
import net.minecraft.server.v1_14_R1.WorldServer;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_14_R1.util.CraftChatMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_14_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@Override
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 8))
return def;
return tagCompound.getString(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 4))
return def;
return tagCompound.getLong(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.getOrCreateTag();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_14_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = -1);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = 16);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
@Override
public void updateSpawner(Location location, boolean reset) {
assert location.getWorld() != null;
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
if(mobSpawner == null)
return;
mobSpawner.getSpawner().requiredPlayerRange = reset ? 16 : -1;
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
super(TileEntityTypes.COMMAND_BLOCK);
this.chunkLoader = chunkLoader;
setPosition(blockPosition);
setWorld(world);
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;
tileEntityChunkLoaderMap.put(ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void r() {
tick();
}
@Override
public void tick() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
assert chunkLoader.getWhoPlaced().getName() != null;
hologram.setCustomName(CraftChatMessage.fromStringOrNull(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + ""))
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(EntityTypes.ARMOR_STAND, world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,147 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_15_R1.EntityPlayer;
import net.minecraft.server.v1_15_R1.EnumGamemode;
import net.minecraft.server.v1_15_R1.EnumProtocolDirection;
import net.minecraft.server.v1_15_R1.MinecraftServer;
import net.minecraft.server.v1_15_R1.NetworkManager;
import net.minecraft.server.v1_15_R1.Packet;
import net.minecraft.server.v1_15_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_15_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_15_R1.PacketPlayInChat;
import net.minecraft.server.v1_15_R1.PacketPlayInFlying;
import net.minecraft.server.v1_15_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_15_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_15_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_15_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_15_R1.PlayerConnection;
import net.minecraft.server.v1_15_R1.PlayerInteractManager;
import net.minecraft.server.v1_15_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_15_R1.CraftServer;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_15_R1 extends EntityPlayer implements ChunkLoaderNPC {
private boolean dieCall = false;
public ChunkLoaderNPC_v1_15_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
a(EnumGamemode.CREATIVE);
clientViewDistance = 1;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
((WorldServer) world).addPlayerJoin(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
if(!dieCall) {
dieCall = true;
getWorldServer().removePlayer(this);
dieCall = false;
}
else {
super.die();
}
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("socketAddress");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,302 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_15_R1.AxisAlignedBB;
import net.minecraft.server.v1_15_R1.Block;
import net.minecraft.server.v1_15_R1.BlockPosition;
import net.minecraft.server.v1_15_R1.Chunk;
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair;
import net.minecraft.server.v1_15_R1.Entity;
import net.minecraft.server.v1_15_R1.EntityArmorStand;
import net.minecraft.server.v1_15_R1.EntityTypes;
import net.minecraft.server.v1_15_R1.ITickable;
import net.minecraft.server.v1_15_R1.ItemStack;
import net.minecraft.server.v1_15_R1.NBTTagCompound;
import net.minecraft.server.v1_15_R1.NBTTagList;
import net.minecraft.server.v1_15_R1.NBTTagLong;
import net.minecraft.server.v1_15_R1.NBTTagString;
import net.minecraft.server.v1_15_R1.TileEntity;
import net.minecraft.server.v1_15_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_15_R1.TileEntityTypes;
import net.minecraft.server.v1_15_R1.World;
import net.minecraft.server.v1_15_R1.WorldServer;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_15_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_15_R1.util.CraftChatMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_15_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@Override
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 8))
return def;
return tagCompound.getString(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagString.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 4))
return def;
return tagCompound.getLong(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagLong.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.getOrCreateTag();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_15_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = -1);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = 16);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, false);
}
@Override
public void updateSpawner(Location location, boolean reset) {
assert location.getWorld() != null;
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
if(mobSpawner == null)
return;
mobSpawner.getSpawner().requiredPlayerRange = reset ? 16 : -1;
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
super(TileEntityTypes.COMMAND_BLOCK);
this.chunkLoader = chunkLoader;
setLocation(world, blockPosition);
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;
tileEntityChunkLoaderMap.put(ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void v() {
tick();
}
@Override
public void tick() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
assert chunkLoader.getWhoPlaced().getName() != null;
hologram.setCustomName(CraftChatMessage.fromStringOrNull(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + ""))
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(EntityTypes.ARMOR_STAND, world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
@Override
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
return new NBTTagCompound();
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
return false;
}
}
}

View File

@ -0,0 +1,147 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_16_R1.EntityPlayer;
import net.minecraft.server.v1_16_R1.EnumGamemode;
import net.minecraft.server.v1_16_R1.EnumProtocolDirection;
import net.minecraft.server.v1_16_R1.MinecraftServer;
import net.minecraft.server.v1_16_R1.NetworkManager;
import net.minecraft.server.v1_16_R1.Packet;
import net.minecraft.server.v1_16_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_16_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_16_R1.PacketPlayInChat;
import net.minecraft.server.v1_16_R1.PacketPlayInFlying;
import net.minecraft.server.v1_16_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_16_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_16_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_16_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_16_R1.PlayerConnection;
import net.minecraft.server.v1_16_R1.PlayerInteractManager;
import net.minecraft.server.v1_16_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R1.CraftServer;
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_16_R1 extends EntityPlayer implements ChunkLoaderNPC {
private boolean dieCall = false;
public ChunkLoaderNPC_v1_16_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
a(EnumGamemode.CREATIVE);
clientViewDistance = 1;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
((WorldServer) world).addPlayerJoin(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
if(!dieCall) {
dieCall = true;
getWorldServer().removePlayer(this);
dieCall = false;
}
else {
super.die();
}
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("socketAddress");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,294 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_16_R1.AxisAlignedBB;
import net.minecraft.server.v1_16_R1.Block;
import net.minecraft.server.v1_16_R1.BlockPosition;
import net.minecraft.server.v1_16_R1.Chunk;
import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
import net.minecraft.server.v1_16_R1.Entity;
import net.minecraft.server.v1_16_R1.EntityArmorStand;
import net.minecraft.server.v1_16_R1.EntityTypes;
import net.minecraft.server.v1_16_R1.IBlockData;
import net.minecraft.server.v1_16_R1.ITickable;
import net.minecraft.server.v1_16_R1.ItemStack;
import net.minecraft.server.v1_16_R1.NBTTagCompound;
import net.minecraft.server.v1_16_R1.NBTTagList;
import net.minecraft.server.v1_16_R1.NBTTagLong;
import net.minecraft.server.v1_16_R1.NBTTagString;
import net.minecraft.server.v1_16_R1.TileEntity;
import net.minecraft.server.v1_16_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_16_R1.TileEntityTypes;
import net.minecraft.server.v1_16_R1.World;
import net.minecraft.server.v1_16_R1.WorldServer;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_16_R1.util.CraftChatMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_16_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@Override
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 8))
return def;
return tagCompound.getString(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagString.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 4))
return def;
return tagCompound.getLong(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagLong.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.getOrCreateTag();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_16_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = -1);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = 16);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, false);
}
@Override
public void updateSpawner(Location location, boolean reset) {
assert location.getWorld() != null;
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
IBlockData blockData = world.getType(blockPosition);
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
if(mobSpawner == null)
return;
mobSpawner.getSpawner().requiredPlayerRange = reset ? 16 : -1;
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
super(TileEntityTypes.COMMAND_BLOCK);
this.chunkLoader = chunkLoader;
setLocation(world, blockPosition);
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;
tileEntityChunkLoaderMap.put(ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void w() {
tick();
}
@Override
public void tick() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
assert chunkLoader.getWhoPlaced().getName() != null;
hologram.setCustomName(CraftChatMessage.fromStringOrNull(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + ""))
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(EntityTypes.ARMOR_STAND, world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,147 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_16_R2.EntityPlayer;
import net.minecraft.server.v1_16_R2.EnumGamemode;
import net.minecraft.server.v1_16_R2.EnumProtocolDirection;
import net.minecraft.server.v1_16_R2.MinecraftServer;
import net.minecraft.server.v1_16_R2.NetworkManager;
import net.minecraft.server.v1_16_R2.Packet;
import net.minecraft.server.v1_16_R2.PacketPlayInBlockDig;
import net.minecraft.server.v1_16_R2.PacketPlayInBlockPlace;
import net.minecraft.server.v1_16_R2.PacketPlayInChat;
import net.minecraft.server.v1_16_R2.PacketPlayInFlying;
import net.minecraft.server.v1_16_R2.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_16_R2.PacketPlayInTransaction;
import net.minecraft.server.v1_16_R2.PacketPlayInUpdateSign;
import net.minecraft.server.v1_16_R2.PacketPlayInWindowClick;
import net.minecraft.server.v1_16_R2.PlayerConnection;
import net.minecraft.server.v1_16_R2.PlayerInteractManager;
import net.minecraft.server.v1_16_R2.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R2.CraftServer;
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_16_R2 extends EntityPlayer implements ChunkLoaderNPC {
private boolean dieCall = false;
public ChunkLoaderNPC_v1_16_R2(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
a(EnumGamemode.CREATIVE);
clientViewDistance = 1;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
((WorldServer) world).addPlayerJoin(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
if(!dieCall) {
dieCall = true;
getWorldServer().removePlayer(this);
dieCall = false;
}
else {
super.die();
}
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("socketAddress");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,294 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_16_R2.AxisAlignedBB;
import net.minecraft.server.v1_16_R2.Block;
import net.minecraft.server.v1_16_R2.BlockPosition;
import net.minecraft.server.v1_16_R2.Chunk;
import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
import net.minecraft.server.v1_16_R2.Entity;
import net.minecraft.server.v1_16_R2.EntityArmorStand;
import net.minecraft.server.v1_16_R2.EntityTypes;
import net.minecraft.server.v1_16_R2.IBlockData;
import net.minecraft.server.v1_16_R2.ITickable;
import net.minecraft.server.v1_16_R2.ItemStack;
import net.minecraft.server.v1_16_R2.NBTTagCompound;
import net.minecraft.server.v1_16_R2.NBTTagList;
import net.minecraft.server.v1_16_R2.NBTTagLong;
import net.minecraft.server.v1_16_R2.NBTTagString;
import net.minecraft.server.v1_16_R2.TileEntity;
import net.minecraft.server.v1_16_R2.TileEntityMobSpawner;
import net.minecraft.server.v1_16_R2.TileEntityTypes;
import net.minecraft.server.v1_16_R2.World;
import net.minecraft.server.v1_16_R2.WorldServer;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_16_R2.util.CraftChatMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_16_R2 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@Override
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 8))
return def;
return tagCompound.getString(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagString.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 4))
return def;
return tagCompound.getLong(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagLong.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.getOrCreateTag();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_16_R2(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = -1);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = 16);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
@Override
public void updateSpawner(Location location, boolean reset) {
assert location.getWorld() != null;
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
IBlockData blockData = world.getType(blockPosition);
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
if(mobSpawner == null)
return;
mobSpawner.getSpawner().requiredPlayerRange = reset ? 16 : -1;
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
super(TileEntityTypes.COMMAND_BLOCK);
this.chunkLoader = chunkLoader;
setLocation(world, blockPosition);
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;
tileEntityChunkLoaderMap.put(ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void w() {
tick();
}
@Override
public void tick() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
assert chunkLoader.getWhoPlaced().getName() != null;
hologram.setCustomName(CraftChatMessage.fromStringOrNull(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + ""))
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(EntityTypes.ARMOR_STAND, world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,146 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import net.minecraft.server.v1_7_R3.DamageSource;
import net.minecraft.server.v1_7_R3.EntityPlayer;
import net.minecraft.server.v1_7_R3.EnumGamemode;
import net.minecraft.server.v1_7_R3.MinecraftServer;
import net.minecraft.server.v1_7_R3.NetworkManager;
import net.minecraft.server.v1_7_R3.Packet;
import net.minecraft.server.v1_7_R3.PacketPlayInBlockDig;
import net.minecraft.server.v1_7_R3.PacketPlayInBlockPlace;
import net.minecraft.server.v1_7_R3.PacketPlayInChat;
import net.minecraft.server.v1_7_R3.PacketPlayInFlying;
import net.minecraft.server.v1_7_R3.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_7_R3.PacketPlayInTransaction;
import net.minecraft.server.v1_7_R3.PacketPlayInUpdateSign;
import net.minecraft.server.v1_7_R3.PacketPlayInWindowClick;
import net.minecraft.server.v1_7_R3.PlayerConnection;
import net.minecraft.server.v1_7_R3.PlayerInteractManager;
import net.minecraft.server.v1_7_R3.WorldServer;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_7_R3 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_7_R3(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
//noinspection unchecked
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
public boolean damageEntity(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(false);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("m");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("n");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,207 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_7_R3.Block;
import net.minecraft.server.v1_7_R3.Chunk;
import net.minecraft.server.v1_7_R3.IUpdatePlayerListBox;
import net.minecraft.server.v1_7_R3.ItemStack;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.NBTTagList;
import net.minecraft.server.v1_7_R3.NBTTagLong;
import net.minecraft.server.v1_7_R3.NBTTagString;
import net.minecraft.server.v1_7_R3.TileEntity;
import net.minecraft.server.v1_7_R3.TileEntityMobSpawner;
import net.minecraft.server.v1_7_R3.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_7_R3.util.LongHash;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_7_R3 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_7_R3(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
int x = loaderLoc.getBlockX(), y = loaderLoc.getBlockY(), z = loaderLoc.getBlockZ();
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, x, y, z);
//noinspection unchecked
world.tileEntityList.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
//noinspection unchecked
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
((TileEntity) tileEntity).b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
((TileEntity) tileEntity).a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
int x = loaderLoc.getBlockX(), y = loaderLoc.getBlockY(), z = loaderLoc.getBlockZ();
long tileEntityLong = LongHash.toLong(x >> 4, z >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.removed = true;
world.tileEntityList.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, x, y, z, Block.b(world.getType(x, y, z)) + (world.getData(x, y, z) << 12));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
//noinspection unchecked
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
((TileEntity) tileEntity).b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
((TileEntity) tileEntity).a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner)
world.getTileEntity(location.getBlockX(), location.getBlockY(), location.getBlockZ());
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements IUpdatePlayerListBox {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, int x, int y, int z){
this.chunkLoader = chunkLoader;
this.x = x;
this.y = y;
this.z = z;
a(world);
tileEntityChunkLoaderMap.put(LongHash.toLong(x >> 4, z >> 4), this);
}
@Override
public void a() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
((WChunkLoader) chunkLoader).tick();
}
}
}

View File

@ -0,0 +1,145 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import net.minecraft.server.v1_7_R4.DamageSource;
import net.minecraft.server.v1_7_R4.EntityPlayer;
import net.minecraft.server.v1_7_R4.EnumGamemode;
import net.minecraft.server.v1_7_R4.MinecraftServer;
import net.minecraft.server.v1_7_R4.NetworkManager;
import net.minecraft.server.v1_7_R4.Packet;
import net.minecraft.server.v1_7_R4.PacketPlayInBlockDig;
import net.minecraft.server.v1_7_R4.PacketPlayInBlockPlace;
import net.minecraft.server.v1_7_R4.PacketPlayInChat;
import net.minecraft.server.v1_7_R4.PacketPlayInFlying;
import net.minecraft.server.v1_7_R4.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_7_R4.PacketPlayInTransaction;
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.WorldServer;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R4.CraftServer;
import org.bukkit.craftbukkit.v1_7_R4.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_7_R4 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_7_R4(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
//noinspection unchecked
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
public boolean damageEntity(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager {
DummyNetworkManager(){
super(false);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("m");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("n");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,207 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_7_R4.Block;
import net.minecraft.server.v1_7_R4.Chunk;
import net.minecraft.server.v1_7_R4.IUpdatePlayerListBox;
import net.minecraft.server.v1_7_R4.ItemStack;
import net.minecraft.server.v1_7_R4.NBTTagCompound;
import net.minecraft.server.v1_7_R4.NBTTagList;
import net.minecraft.server.v1_7_R4.NBTTagLong;
import net.minecraft.server.v1_7_R4.NBTTagString;
import net.minecraft.server.v1_7_R4.TileEntity;
import net.minecraft.server.v1_7_R4.TileEntityMobSpawner;
import net.minecraft.server.v1_7_R4.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R4.CraftChunk;
import org.bukkit.craftbukkit.v1_7_R4.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_7_R4.util.LongHash;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_7_R4 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_7_R4(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
int x = loaderLoc.getBlockX(), y = loaderLoc.getBlockY(), z = loaderLoc.getBlockZ();
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, x, y, z);
//noinspection unchecked
world.tileEntityList.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
//noinspection unchecked
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
((TileEntity) tileEntity).b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
((TileEntity) tileEntity).a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
int x = loaderLoc.getBlockX(), y = loaderLoc.getBlockY(), z = loaderLoc.getBlockZ();
long tileEntityLong = LongHash.toLong(x >> 4, z >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.removed = true;
world.tileEntityList.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, x, y, z, Block.getId(world.getType(x, y, z)) + (world.getData(x, y, z) << 12));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
//noinspection unchecked
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
((TileEntity) tileEntity).b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
((TileEntity) tileEntity).a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner)
world.getTileEntity(location.getBlockX(), location.getBlockY(), location.getBlockZ());
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements IUpdatePlayerListBox {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, int x, int y, int z){
this.chunkLoader = chunkLoader;
this.x = x;
this.y = y;
this.z = z;
a(world);
tileEntityChunkLoaderMap.put(LongHash.toLong(x >> 4, z >> 4), this);
}
@Override
public void a() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
((WChunkLoader) chunkLoader).tick();
}
}
}

View File

@ -0,0 +1,146 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_8_R1.DamageSource;
import net.minecraft.server.v1_8_R1.EntityPlayer;
import net.minecraft.server.v1_8_R1.EnumGamemode;
import net.minecraft.server.v1_8_R1.EnumProtocolDirection;
import net.minecraft.server.v1_8_R1.MinecraftServer;
import net.minecraft.server.v1_8_R1.NetworkManager;
import net.minecraft.server.v1_8_R1.Packet;
import net.minecraft.server.v1_8_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_8_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_8_R1.PacketPlayInChat;
import net.minecraft.server.v1_8_R1.PacketPlayInFlying;
import net.minecraft.server.v1_8_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_8_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_8_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_8_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_8_R1.PlayerConnection;
import net.minecraft.server.v1_8_R1.PlayerInteractManager;
import net.minecraft.server.v1_8_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R1.CraftServer;
import org.bukkit.craftbukkit.v1_8_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_8_R1 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_8_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
//noinspection unchecked
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
public boolean damageEntity(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("i");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("j");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,284 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_8_R1.AxisAlignedBB;
import net.minecraft.server.v1_8_R1.Block;
import net.minecraft.server.v1_8_R1.BlockPosition;
import net.minecraft.server.v1_8_R1.Chunk;
import net.minecraft.server.v1_8_R1.Entity;
import net.minecraft.server.v1_8_R1.EntityArmorStand;
import net.minecraft.server.v1_8_R1.IUpdatePlayerListBox;
import net.minecraft.server.v1_8_R1.ItemStack;
import net.minecraft.server.v1_8_R1.NBTTagCompound;
import net.minecraft.server.v1_8_R1.NBTTagList;
import net.minecraft.server.v1_8_R1.NBTTagLong;
import net.minecraft.server.v1_8_R1.NBTTagString;
import net.minecraft.server.v1_8_R1.TileEntity;
import net.minecraft.server.v1_8_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_8_R1.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_8_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_8_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_8_R1.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_8_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_8_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
//noinspection unchecked
world.tileEntityList.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
//noinspection unchecked
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
((TileEntity) tileEntity).b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
((TileEntity) tileEntity).a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityList.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
//noinspection unchecked
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
((TileEntity) tileEntity).b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
((TileEntity) tileEntity).a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements IUpdatePlayerListBox {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
a(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void c() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setGravity(false);
setBasePlate(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,145 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_8_R2.DamageSource;
import net.minecraft.server.v1_8_R2.EntityPlayer;
import net.minecraft.server.v1_8_R2.EnumProtocolDirection;
import net.minecraft.server.v1_8_R2.MinecraftServer;
import net.minecraft.server.v1_8_R2.NetworkManager;
import net.minecraft.server.v1_8_R2.Packet;
import net.minecraft.server.v1_8_R2.PacketPlayInBlockDig;
import net.minecraft.server.v1_8_R2.PacketPlayInBlockPlace;
import net.minecraft.server.v1_8_R2.PacketPlayInChat;
import net.minecraft.server.v1_8_R2.PacketPlayInFlying;
import net.minecraft.server.v1_8_R2.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_8_R2.PacketPlayInTransaction;
import net.minecraft.server.v1_8_R2.PacketPlayInUpdateSign;
import net.minecraft.server.v1_8_R2.PacketPlayInWindowClick;
import net.minecraft.server.v1_8_R2.PlayerConnection;
import net.minecraft.server.v1_8_R2.PlayerInteractManager;
import net.minecraft.server.v1_8_R2.WorldServer;
import net.minecraft.server.v1_8_R2.WorldSettings;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R2.CraftServer;
import org.bukkit.craftbukkit.v1_8_R2.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_8_R2 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_8_R2(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(WorldSettings.EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
public boolean damageEntity(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("k");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,281 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_8_R2.AxisAlignedBB;
import net.minecraft.server.v1_8_R2.Block;
import net.minecraft.server.v1_8_R2.BlockPosition;
import net.minecraft.server.v1_8_R2.Chunk;
import net.minecraft.server.v1_8_R2.Entity;
import net.minecraft.server.v1_8_R2.EntityArmorStand;
import net.minecraft.server.v1_8_R2.IUpdatePlayerListBox;
import net.minecraft.server.v1_8_R2.ItemStack;
import net.minecraft.server.v1_8_R2.NBTTagCompound;
import net.minecraft.server.v1_8_R2.NBTTagList;
import net.minecraft.server.v1_8_R2.NBTTagLong;
import net.minecraft.server.v1_8_R2.NBTTagString;
import net.minecraft.server.v1_8_R2.TileEntity;
import net.minecraft.server.v1_8_R2.TileEntityMobSpawner;
import net.minecraft.server.v1_8_R2.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_8_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_8_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_8_R2.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_8_R2 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_8_R2(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityList.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityList.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements IUpdatePlayerListBox {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
a(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void c() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setGravity(false);
setBasePlate(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,145 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_8_R3.DamageSource;
import net.minecraft.server.v1_8_R3.EntityPlayer;
import net.minecraft.server.v1_8_R3.EnumProtocolDirection;
import net.minecraft.server.v1_8_R3.MinecraftServer;
import net.minecraft.server.v1_8_R3.NetworkManager;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
import net.minecraft.server.v1_8_R3.PacketPlayInChat;
import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
import net.minecraft.server.v1_8_R3.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_8_R3.PacketPlayInTransaction;
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.WorldServer;
import net.minecraft.server.v1_8_R3.WorldSettings;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_8_R3 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_8_R3(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(WorldSettings.EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
public boolean damageEntity(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,281 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_8_R3.AxisAlignedBB;
import net.minecraft.server.v1_8_R3.Block;
import net.minecraft.server.v1_8_R3.BlockPosition;
import net.minecraft.server.v1_8_R3.Chunk;
import net.minecraft.server.v1_8_R3.Entity;
import net.minecraft.server.v1_8_R3.EntityArmorStand;
import net.minecraft.server.v1_8_R3.IUpdatePlayerListBox;
import net.minecraft.server.v1_8_R3.ItemStack;
import net.minecraft.server.v1_8_R3.NBTTagCompound;
import net.minecraft.server.v1_8_R3.NBTTagList;
import net.minecraft.server.v1_8_R3.NBTTagLong;
import net.minecraft.server.v1_8_R3.NBTTagString;
import net.minecraft.server.v1_8_R3.TileEntity;
import net.minecraft.server.v1_8_R3.TileEntityMobSpawner;
import net.minecraft.server.v1_8_R3.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_8_R3.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_8_R3 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_8_R3(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityList.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityList.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.b(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements IUpdatePlayerListBox {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
a(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void c() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setGravity(false);
setBasePlate(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,145 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_9_R1.DamageSource;
import net.minecraft.server.v1_9_R1.EntityPlayer;
import net.minecraft.server.v1_9_R1.EnumProtocolDirection;
import net.minecraft.server.v1_9_R1.MinecraftServer;
import net.minecraft.server.v1_9_R1.NetworkManager;
import net.minecraft.server.v1_9_R1.Packet;
import net.minecraft.server.v1_9_R1.PacketPlayInBlockDig;
import net.minecraft.server.v1_9_R1.PacketPlayInBlockPlace;
import net.minecraft.server.v1_9_R1.PacketPlayInChat;
import net.minecraft.server.v1_9_R1.PacketPlayInFlying;
import net.minecraft.server.v1_9_R1.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_9_R1.PacketPlayInTransaction;
import net.minecraft.server.v1_9_R1.PacketPlayInUpdateSign;
import net.minecraft.server.v1_9_R1.PacketPlayInWindowClick;
import net.minecraft.server.v1_9_R1.PlayerConnection;
import net.minecraft.server.v1_9_R1.PlayerInteractManager;
import net.minecraft.server.v1_9_R1.WorldServer;
import net.minecraft.server.v1_9_R1.WorldSettings;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R1.CraftServer;
import org.bukkit.craftbukkit.v1_9_R1.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_9_R1 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_9_R1(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(WorldSettings.EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
protected boolean damageEntity0(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,282 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_9_R1.AxisAlignedBB;
import net.minecraft.server.v1_9_R1.Block;
import net.minecraft.server.v1_9_R1.BlockPosition;
import net.minecraft.server.v1_9_R1.Chunk;
import net.minecraft.server.v1_9_R1.Entity;
import net.minecraft.server.v1_9_R1.EntityArmorStand;
import net.minecraft.server.v1_9_R1.ITickable;
import net.minecraft.server.v1_9_R1.ItemStack;
import net.minecraft.server.v1_9_R1.NBTTagCompound;
import net.minecraft.server.v1_9_R1.NBTTagList;
import net.minecraft.server.v1_9_R1.NBTTagLong;
import net.minecraft.server.v1_9_R1.NBTTagString;
import net.minecraft.server.v1_9_R1.TileEntity;
import net.minecraft.server.v1_9_R1.TileEntityMobSpawner;
import net.minecraft.server.v1_9_R1.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_9_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_9_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_9_R1.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_9_R1 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_9_R1(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
a(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void c() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setGravity(false);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}

View File

@ -0,0 +1,145 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_9_R2.DamageSource;
import net.minecraft.server.v1_9_R2.EntityPlayer;
import net.minecraft.server.v1_9_R2.EnumProtocolDirection;
import net.minecraft.server.v1_9_R2.MinecraftServer;
import net.minecraft.server.v1_9_R2.NetworkManager;
import net.minecraft.server.v1_9_R2.Packet;
import net.minecraft.server.v1_9_R2.PacketPlayInBlockDig;
import net.minecraft.server.v1_9_R2.PacketPlayInBlockPlace;
import net.minecraft.server.v1_9_R2.PacketPlayInChat;
import net.minecraft.server.v1_9_R2.PacketPlayInFlying;
import net.minecraft.server.v1_9_R2.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_9_R2.PacketPlayInTransaction;
import net.minecraft.server.v1_9_R2.PacketPlayInUpdateSign;
import net.minecraft.server.v1_9_R2.PacketPlayInWindowClick;
import net.minecraft.server.v1_9_R2.PlayerConnection;
import net.minecraft.server.v1_9_R2.PlayerInteractManager;
import net.minecraft.server.v1_9_R2.WorldServer;
import net.minecraft.server.v1_9_R2.WorldSettings;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R2.CraftServer;
import org.bukkit.craftbukkit.v1_9_R2.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_9_R2 extends EntityPlayer implements ChunkLoaderNPC {
public ChunkLoaderNPC_v1_9_R2(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
playerInteractManager.setGameMode(WorldSettings.EnumGamemode.CREATIVE);
fallDistance = 0.0F;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
world.players.add(this);
((WorldServer) world).getPlayerChunkMap().addPlayer(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
super.die();
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
@Override
protected boolean damageEntity0(DamageSource damagesource, float f) {
return false;
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("l");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static class DummyPlayerConnection extends PlayerConnection {
DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) {
super(minecraftServer, new DummyNetworkManager(), entityPlayer);
}
public void a(PacketPlayInWindowClick packetPlayInWindowClick) {
}
public void a(PacketPlayInTransaction packetPlayInTransaction) {
}
public void a(PacketPlayInFlying packetPlayInFlying) {
}
public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) {
}
public void a(PacketPlayInBlockDig packetPlayInBlockDig) {
}
public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) {
}
public void disconnect(String s) {
}
public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) {
}
public void a(PacketPlayInChat packetPlayInChat) {
}
public void sendPacket(Packet packet) {
}
}
}

View File

@ -0,0 +1,282 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_9_R2.AxisAlignedBB;
import net.minecraft.server.v1_9_R2.Block;
import net.minecraft.server.v1_9_R2.BlockPosition;
import net.minecraft.server.v1_9_R2.Chunk;
import net.minecraft.server.v1_9_R2.Entity;
import net.minecraft.server.v1_9_R2.EntityArmorStand;
import net.minecraft.server.v1_9_R2.ITickable;
import net.minecraft.server.v1_9_R2.ItemStack;
import net.minecraft.server.v1_9_R2.NBTTagCompound;
import net.minecraft.server.v1_9_R2.NBTTagList;
import net.minecraft.server.v1_9_R2.NBTTagLong;
import net.minecraft.server.v1_9_R2.NBTTagString;
import net.minecraft.server.v1_9_R2.TileEntity;
import net.minecraft.server.v1_9_R2.TileEntityMobSpawner;
import net.minecraft.server.v1_9_R2.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_9_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_9_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_9_R2.util.LongHash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings({"ConstantConditions", "unused"})
public final class NMSAdapter_v1_9_R2 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagString(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@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);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
tagCompound.set(key, new NBTTagLong(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.hasTag() ? nmsItem.getTag() : new NBTTagCompound();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_9_R2(location, uuid);
}
@Override
public void createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) -1);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
World world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(Entity::die);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
Chunk chunk = ((CraftChunk) loaderLoc.getChunk()).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner).forEach(tileEntity -> {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
tileEntity.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) 16);
tileEntity.a(nbtTagCompound);
});
}
@Override
public void updateSpawner(Location location, boolean reset) {
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
mobSpawner.save(nbtTagCompound);
nbtTagCompound.setShort("RequiredPlayerRange", (short) (reset ? 16 : -1));
mobSpawner.a(nbtTagCompound);
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHologram> holograms = new ArrayList<>();
private final ChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
this.chunkLoader = chunkLoader;
a(blockPosition);
a(world);
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;
tileEntityChunkLoaderMap.put(LongHash.toLong(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
double currentY = position.getY() + 1;
for(int i = plugin.getSettings().hologramLines.size(); i > 0; i--){
EntityHologram hologram = new EntityHologram(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void c() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(((WChunkLoader) chunkLoader).isNotActive()){
chunkLoader.remove();
return;
}
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHologram hologram = holograms.get(hologramsAmount - i);
updateName(hologram, plugin.getSettings().hologramLines.get(i - 1));
}
((WChunkLoader) chunkLoader).tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
private void updateName(EntityHologram hologram, String line){
hologram.setCustomName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
private static class EntityHologram extends EntityArmorStand {
EntityHologram(World world, double x, double y, double z){
super(world);
setPosition(x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setGravity(false);
setBasePlate(true);
setMarker(true);
setCustomNameVisible(true);
a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
}
}