mirror of
https://github.com/BG-Software-LLC/WildLoaders.git
synced 2024-11-24 12:15:28 +01:00
Initial Commit
This commit is contained in:
commit
9cae8e9d5a
@ -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();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.bgsoftware.wildloaders.api;
|
||||||
|
|
||||||
|
public final class WildLoadersAPI {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
BIN
libs/HolographicDisplays.jar
Normal file
BIN
libs/HolographicDisplays.jar
Normal file
Binary file not shown.
86
src/main/java/com/bgsoftware/wildloaders/Locale.java
Normal file
86
src/main/java/com/bgsoftware/wildloaders/Locale.java
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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){}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
707
src/main/java/com/bgsoftware/wildloaders/metrics/Metrics.java
Normal file
707
src/main/java/com/bgsoftware/wildloaders/metrics/Metrics.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
src/main/java/com/bgsoftware/wildloaders/nms/NMSAdapter.java
Normal file
31
src/main/java/com/bgsoftware/wildloaders/nms/NMSAdapter.java
Normal 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);
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
101
src/main/java/com/bgsoftware/wildloaders/utils/TimeUtils.java
Normal file
101
src/main/java/com/bgsoftware/wildloaders/utils/TimeUtils.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
src/main/resources/config.yml
Normal file
22
src/main/resources/config.yml
Normal 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!'
|
21
src/main/resources/lang.yml
Normal file
21
src/main/resources/lang.yml
Normal 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}.'
|
18
src/main/resources/plugin.yml
Normal file
18
src/main/resources/plugin.yml
Normal 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.
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user