Beta 1.15 Support (Waiting on Paper)

This commit is contained in:
Brianna 2019-12-11 14:22:01 -05:00
parent 163f4cd950
commit bceb1c9063
15 changed files with 720 additions and 338 deletions

View File

@ -114,10 +114,9 @@
</build> </build>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.destroystokyo.papermc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>paper</artifactId> <artifactId>spigot</artifactId>
<version>1.14.4</version> <version>1.15</version>
<scope>provided</scope>
</dependency> </dependency>
<!--dependency> <!--dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
@ -210,6 +209,13 @@
<type>jar</type> <type>jar</type>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>SongodaCore-NMS-v1_15_R1</artifactId>
<version>${project.version}</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!-- End NMS --> <!-- End NMS -->
<!-- Start Plugin Hooks --> <!-- Start Plugin Hooks -->
<dependency> <dependency>

View File

@ -315,7 +315,7 @@ public class CommandManager implements CommandExecutor, TabCompleter {
// If we're on Paper 1.8, we need to register timings (spigot creates timings on init, paper creates it on register) // If we're on Paper 1.8, we need to register timings (spigot creates timings on init, paper creates it on register)
// later versions of paper create timings if needed when the command is executed // later versions of paper create timings if needed when the command is executed
if (ServerProject.isServer(ServerProject.PAPER, ServerProject.TACO) && ServerVersion.isServerVersionBelow(ServerVersion.V1_9)) { if (ServerProject.isServer(ServerProject.PAPER, ServerProject.TACO) && ServerVersion.isServerVersionBelow(ServerVersion.V1_9)) {
commandObject.timings = co.aikar.timings.TimingsManager.getCommandTiming(plugin.getName().toLowerCase(), commandObject); // commandObject.timings = co.aikar.timings.TimingsManager.getCommandTiming(plugin.getName().toLowerCase(), commandObject);
} }
// Set command action // Set command action

View File

@ -30,6 +30,16 @@ public enum CompatibleMaterial {
DARK_OAK_DOOR_ITEM(431), DARK_OAK_DOOR_ITEM(431),
*/ */
/* 1.15 */
BEE_SPAWN_EGG(),
BEE_NEST(),
BEEHIVE(),
HONEY_BLOCK(),
HONEY_BOTTLE(),
HONEYCOMB(),
HONEYCOMB_BLOCK(),
ACACIA_BOAT("BOAT_ACACIA"), ACACIA_BOAT("BOAT_ACACIA"),
ACACIA_BUTTON(), ACACIA_BUTTON(),
ACACIA_DOOR("ACACIA_DOOR_ITEM"), ACACIA_DOOR("ACACIA_DOOR_ITEM"),

View File

@ -1,17 +1,24 @@
package com.songoda.core.compatibility; package com.songoda.core.compatibility;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class CompatibleParticleHandler { public class CompatibleParticleHandler {
public static enum ParticleType { public static enum ParticleType {
/* 1.15 */
DRIPPING_HONEY,
FALLING_HONEY,
FALLING_NECTAR,
LANDING_HONEY,
EXPLOSION_NORMAL(), EXPLOSION_NORMAL(),
EXPLOSION_LARGE, EXPLOSION_LARGE,
EXPLOSION_HUGE, EXPLOSION_HUGE,
@ -214,17 +221,17 @@ public class CompatibleParticleHandler {
public static void redstoneParticles(Location location, int red, int green, int blue) { public static void redstoneParticles(Location location, int red, int green, int blue) {
redstoneParticles(location, red, green, blue, 1F, 1, 0); redstoneParticles(location, red, green, blue, 1F, 1, 0);
} }
/** /**
* Spawn colored redstone particles * Spawn colored redstone particles
* *
* @param location area to spawn the particle in * @param location area to spawn the particle in
* @param red red value 0-255 * @param red red value 0-255
* @param green green value 0-255 * @param green green value 0-255
* @param blue blue value 0-255 * @param blue blue value 0-255
* @param size (1.13+) size of the particles * @param size (1.13+) size of the particles
* @param count how many particles to spawn * @param count how many particles to spawn
* @param radius how far to spread out the particles from location * @param radius how far to spread out the particles from location
*/ */
public static void redstoneParticles(Location location, int red, int green, int blue, float size, int count, float radius) { public static void redstoneParticles(Location location, int red, int green, int blue, float size, int count, float radius) {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) { if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
@ -247,23 +254,23 @@ public class CompatibleParticleHandler {
float yy = (float) (radius * (Math.random() - Math.random())); float yy = (float) (radius * (Math.random() - Math.random()));
float zz = (float) (radius * (Math.random() - Math.random())); float zz = (float) (radius * (Math.random() - Math.random()));
Location at = location.clone().add(xx, yy, zz); Location at = location.clone().add(xx, yy, zz);
LegacyParticleEffects.createParticle(at, LegacyParticleEffects.Type.REDSTONE, LegacyParticleEffects.createParticle(at, LegacyParticleEffects.Type.REDSTONE,
red / 255F, green / 255F, blue / 255F, 1F, 0, null); red / 255F, green / 255F, blue / 255F, 1F, 0, null);
} }
} }
} }
public static void bonemealSmoke(Location l) { public static void bonemealSmoke(Location l) {
final org.bukkit.World w = l.getWorld(); final org.bukkit.World w = l.getWorld();
w.playEffect(l, Effect.SMOKE, BlockFace.SOUTH_EAST); w.playEffect(l, Effect.SMOKE, BlockFace.SOUTH_EAST);
w.playEffect(l, Effect.SMOKE, BlockFace.SOUTH); w.playEffect(l, Effect.SMOKE, BlockFace.SOUTH);
w.playEffect(l, Effect.SMOKE, BlockFace.SOUTH_WEST); w.playEffect(l, Effect.SMOKE, BlockFace.SOUTH_WEST);
w.playEffect(l, Effect.SMOKE, BlockFace.EAST); w.playEffect(l, Effect.SMOKE, BlockFace.EAST);
w.playEffect(l, Effect.SMOKE, BlockFace.SELF); w.playEffect(l, Effect.SMOKE, BlockFace.SELF);
w.playEffect(l, Effect.SMOKE, BlockFace.WEST); w.playEffect(l, Effect.SMOKE, BlockFace.WEST);
w.playEffect(l, Effect.SMOKE, BlockFace.NORTH_EAST); w.playEffect(l, Effect.SMOKE, BlockFace.NORTH_EAST);
w.playEffect(l, Effect.SMOKE, BlockFace.NORTH); w.playEffect(l, Effect.SMOKE, BlockFace.NORTH);
w.playEffect(l, Effect.SMOKE, BlockFace.NORTH_WEST); w.playEffect(l, Effect.SMOKE, BlockFace.NORTH_WEST);
} }
} }

View File

@ -23,6 +23,29 @@ public enum CompatibleSound {
// would using the raw strings be better? // would using the raw strings be better?
// 1.8 list: // 1.8 list:
// https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2213619-1-8-all-playsound-sound-arguments // https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2213619-1-8-all-playsound-sound-arguments
/* 1.15 */
BLOCK_BEEHIVE_DRIP,
BLOCK_BEEHIVE_ENTER,
BLOCK_BEEHIVE_EXIT,
BLOCK_BEEHIVE_SHEAR,
BLOCK_BEEHIVE_WORK,
BLOCK_HONEY_BLOCK_BREAK,
BLOCK_HONEY_BLOCK_FALL,
BLOCK_HONEY_BLOCK_HIT,
BLOCK_HONEY_BLOCK_PLACE,
BLOCK_HONEY_BLOCK_SLIDE,
BLOCK_HONEY_BLOCK_STEP,
ENTITY_BEE_DEATH,
ENTITY_BEE_HURT,
ENTITY_BEE_LOOP,
ENTITY_BEE_LOOP_AGGRESSIVE,
ENTITY_BEE_POLLINATE,
ENTITY_BEE_STING,
ENTITY_IRON_GOLEM_DAMAGE,
ENTITY_IRON_GOLEM_REPAIR,
ITEM_HONEY_BOTTLE_DRINK,
AMBIENT_CAVE(ServerVersion.V1_9, v("AMBIENCE_CAVE")), AMBIENT_CAVE(ServerVersion.V1_9, v("AMBIENCE_CAVE")),
AMBIENT_UNDERWATER_ENTER, AMBIENT_UNDERWATER_ENTER,
AMBIENT_UNDERWATER_EXIT, AMBIENT_UNDERWATER_EXIT,

View File

@ -40,6 +40,8 @@ public class NmsManager {
return new com.songoda.core.nms.v1_13_R2.NMS(); return new com.songoda.core.nms.v1_13_R2.NMS();
case "v1_14_R1": case "v1_14_R1":
return new com.songoda.core.nms.v1_14_R1.NMS(); return new com.songoda.core.nms.v1_14_R1.NMS();
case "v1_15_R1":
return new com.songoda.core.nms.v1_15_R1.NMS();
} }
Logger.getLogger(NmsManager.class.getName()).log(Level.SEVERE, "Failed to load NMS for this server version: version {0} not found", serverPackageVersion); Logger.getLogger(NmsManager.class.getName()).log(Level.SEVERE, "Failed to load NMS for this server version: version {0} not found", serverPackageVersion);
return null; return null;

View File

@ -46,8 +46,6 @@ public class ItemUtils {
public static String getItemName(ItemStack it) { public static String getItemName(ItemStack it) {
if (it == null) { if (it == null) {
return null; return null;
} else if (can_getI18NDisplayName) {
return it.getI18NDisplayName();
} else { } else {
return itemName(it.getType()); return itemName(it.getType());
} }

View File

@ -1,22 +1,22 @@
package com.songoda.core.nms.v1_14_R1; package com.songoda.core.nms.v1_14_R1;
import net.minecraft.server.v1_14_R1.ContainerAnvil; import net.minecraft.server.v1_14_R1.ContainerAnvil;
import net.minecraft.server.v1_14_R1.IInventory; import net.minecraft.server.v1_14_R1.IInventory;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventoryAnvil; import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventoryAnvil;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
public class AnvilInventoryCustom extends CraftInventoryAnvil { public class AnvilInventoryCustom extends CraftInventoryAnvil {
final InventoryHolder holder; final InventoryHolder holder;
public AnvilInventoryCustom(InventoryHolder holder, Location location, IInventory inventory, IInventory resultInventory, ContainerAnvil container) { public AnvilInventoryCustom(InventoryHolder holder, Location location, IInventory inventory, IInventory resultInventory, ContainerAnvil container) {
super(location, inventory, resultInventory, container); super(location, inventory, resultInventory, container);
this.holder = holder; this.holder = holder;
} }
@Override @Override
public InventoryHolder getHolder() { public InventoryHolder getHolder() {
return holder; return holder;
} }
} }

View File

@ -1,261 +1,261 @@
package com.songoda.core.nms.v1_14_R1; package com.songoda.core.nms.v1_14_R1;
import com.songoda.core.nms.CustomAnvil; import com.songoda.core.nms.CustomAnvil;
import com.songoda.core.nms.methods.AnvilTextChange; import com.songoda.core.nms.methods.AnvilTextChange;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import net.minecraft.server.v1_14_R1.BlockPosition; import net.minecraft.server.v1_14_R1.BlockPosition;
import net.minecraft.server.v1_14_R1.ChatMessage; import net.minecraft.server.v1_14_R1.ChatMessage;
import net.minecraft.server.v1_14_R1.Container; import net.minecraft.server.v1_14_R1.Container;
import net.minecraft.server.v1_14_R1.ContainerAccess; import net.minecraft.server.v1_14_R1.ContainerAccess;
import net.minecraft.server.v1_14_R1.ContainerAnvil; import net.minecraft.server.v1_14_R1.ContainerAnvil;
import net.minecraft.server.v1_14_R1.ContainerProperty; import net.minecraft.server.v1_14_R1.ContainerProperty;
import net.minecraft.server.v1_14_R1.Containers; import net.minecraft.server.v1_14_R1.Containers;
import net.minecraft.server.v1_14_R1.EntityHuman; import net.minecraft.server.v1_14_R1.EntityHuman;
import net.minecraft.server.v1_14_R1.EntityPlayer; import net.minecraft.server.v1_14_R1.EntityPlayer;
import net.minecraft.server.v1_14_R1.IInventory; import net.minecraft.server.v1_14_R1.IInventory;
import net.minecraft.server.v1_14_R1.PacketPlayOutOpenWindow; import net.minecraft.server.v1_14_R1.PacketPlayOutOpenWindow;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventoryView; import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventoryView;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class AnvilView extends ContainerAnvil implements CustomAnvil { public class AnvilView extends ContainerAnvil implements CustomAnvil {
private final EntityPlayer entity; private final EntityPlayer entity;
private final Inventory inventory; private final Inventory inventory;
private String customTitle = "Repairing"; private String customTitle = "Repairing";
private int cost = -1; private int cost = -1;
private boolean canUse = true; private boolean canUse = true;
private AnvilTextChange textChange = null; private AnvilTextChange textChange = null;
// used for setting custom inventory // used for setting custom inventory
static Field mc_ContainerAnvil_repairInventory; // subcontainer with only the result static Field mc_ContainerAnvil_repairInventory; // subcontainer with only the result
static Field mc_ContainerAnvil_resultInventory; // full inventory static Field mc_ContainerAnvil_resultInventory; // full inventory
static Field mc_ContainerAnvil_bukkitEntity; static Field mc_ContainerAnvil_bukkitEntity;
static { static {
try { try {
mc_ContainerAnvil_repairInventory = ContainerAnvil.class.getDeclaredField("repairInventory"); mc_ContainerAnvil_repairInventory = ContainerAnvil.class.getDeclaredField("repairInventory");
mc_ContainerAnvil_repairInventory.setAccessible(true); mc_ContainerAnvil_repairInventory.setAccessible(true);
mc_ContainerAnvil_resultInventory = ContainerAnvil.class.getDeclaredField("resultInventory"); mc_ContainerAnvil_resultInventory = ContainerAnvil.class.getDeclaredField("resultInventory");
mc_ContainerAnvil_resultInventory.setAccessible(true); mc_ContainerAnvil_resultInventory.setAccessible(true);
mc_ContainerAnvil_bukkitEntity = ContainerAnvil.class.getDeclaredField("bukkitEntity"); mc_ContainerAnvil_bukkitEntity = ContainerAnvil.class.getDeclaredField("bukkitEntity");
mc_ContainerAnvil_bukkitEntity.setAccessible(true); mc_ContainerAnvil_bukkitEntity.setAccessible(true);
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
} }
} }
// 1.14.3 and 1.14.4 have different fields for levelCost // 1.14.3 and 1.14.4 have different fields for levelCost
static boolean compat_mode = true; static boolean compat_mode = true;
static Method mc_ContainerProperty_set; static Method mc_ContainerProperty_set;
static Method mc_ContainerProperty_get; static Method mc_ContainerProperty_get;
// 1.14 also made this field private. Fun. // 1.14 also made this field private. Fun.
static Field mc_Container_windowId; static Field mc_Container_windowId;
// 1.14 also introduced a title field, also private, which can only be set once and can't be checked // 1.14 also introduced a title field, also private, which can only be set once and can't be checked
static Field mc_Container_title; static Field mc_Container_title;
static { static {
try { try {
mc_Container_windowId = Container.class.getDeclaredField("windowId"); mc_Container_windowId = Container.class.getDeclaredField("windowId");
mc_Container_windowId.setAccessible(true); mc_Container_windowId.setAccessible(true);
mc_Container_title = Container.class.getDeclaredField("title"); mc_Container_title = Container.class.getDeclaredField("title");
mc_Container_title.setAccessible(true); mc_Container_title.setAccessible(true);
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
} }
for (Method m : ContainerProperty.class.getMethods()) { for (Method m : ContainerProperty.class.getMethods()) {
if (m.getName().equals("set")) { if (m.getName().equals("set")) {
compat_mode = false; compat_mode = false;
break; break;
} }
} }
if (compat_mode) { if (compat_mode) {
try { try {
mc_ContainerProperty_set = ContainerProperty.class.getDeclaredMethod("a", int.class); mc_ContainerProperty_set = ContainerProperty.class.getDeclaredMethod("a", int.class);
mc_ContainerProperty_get = ContainerProperty.class.getDeclaredMethod("b"); mc_ContainerProperty_get = ContainerProperty.class.getDeclaredMethod("b");
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
} }
} }
} }
public AnvilView(int id, EntityPlayer entity, InventoryHolder holder) { public AnvilView(int id, EntityPlayer entity, InventoryHolder holder) {
super(id, entity.inventory, ContainerAccess.at(entity.world, new BlockPosition(0, 0, 0))); super(id, entity.inventory, ContainerAccess.at(entity.world, new BlockPosition(0, 0, 0)));
this.setTitle(new ChatMessage(customTitle != null ? customTitle : "")); this.setTitle(new ChatMessage(customTitle != null ? customTitle : ""));
this.checkReachable = false; this.checkReachable = false;
this.entity = entity; this.entity = entity;
if(holder != null) { if(holder != null) {
this.inventory = getBukkitView(entity, holder).getTopInventory(); this.inventory = getBukkitView(entity, holder).getTopInventory();
} else { } else {
this.inventory = getBukkitView().getTopInventory(); this.inventory = getBukkitView().getTopInventory();
} }
} }
public CraftInventoryView getBukkitView(EntityHuman player, InventoryHolder holder) { public CraftInventoryView getBukkitView(EntityHuman player, InventoryHolder holder) {
try { try {
AnvilInventoryCustom craftInventory = new AnvilInventoryCustom(holder, AnvilInventoryCustom craftInventory = new AnvilInventoryCustom(holder,
new Location(entity.world.getWorld(), 0, 0, 0), new Location(entity.world.getWorld(), 0, 0, 0),
(IInventory) mc_ContainerAnvil_repairInventory.get(this), (IInventory) mc_ContainerAnvil_repairInventory.get(this),
(IInventory) mc_ContainerAnvil_resultInventory.get(this), this); (IInventory) mc_ContainerAnvil_resultInventory.get(this), this);
CraftInventoryView view = new CraftInventoryView(player.getBukkitEntity(), craftInventory, this); CraftInventoryView view = new CraftInventoryView(player.getBukkitEntity(), craftInventory, this);
mc_ContainerAnvil_bukkitEntity.set(this, view); mc_ContainerAnvil_bukkitEntity.set(this, view);
return view; return view;
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
} }
return getBukkitView(); return getBukkitView();
} }
@Override @Override
public boolean canUse(EntityHuman entityhuman) { public boolean canUse(EntityHuman entityhuman) {
return canUse; return canUse;
} }
@Override @Override
public void e() { public void e() {
super.e(); super.e();
if (cost >= 0) { if (cost >= 0) {
if (compat_mode) { if (compat_mode) {
if (mc_ContainerProperty_set != null) { if (mc_ContainerProperty_set != null) {
try { try {
mc_ContainerProperty_set.invoke(this.levelCost, 0); mc_ContainerProperty_set.invoke(this.levelCost, 0);
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex);
mc_ContainerProperty_set = null; mc_ContainerProperty_set = null;
} }
} }
} else { } else {
this.levelCost.set(cost); this.levelCost.set(cost);
} }
} }
textChange.onChange(); textChange.onChange();
} }
@Override @Override
public void update() { public void update() {
e(); e();
} }
@Override @Override
public String getRenameText() { public String getRenameText() {
return this.renameText; return this.renameText;
} }
@Override @Override
public void setRenameText(String text) { public void setRenameText(String text) {
this.a(text); this.a(text);
} }
@Override @Override
public void setOnChange(AnvilTextChange handler) { public void setOnChange(AnvilTextChange handler) {
textChange = handler; textChange = handler;
} }
@Override @Override
public String getCustomTitle() { public String getCustomTitle() {
return customTitle; return customTitle;
} }
@Override @Override
public void setCustomTitle(String title) { public void setCustomTitle(String title) {
this.customTitle = title; this.customTitle = title;
try { try {
mc_Container_title.set(this, new ChatMessage(customTitle != null ? customTitle : "")); mc_Container_title.set(this, new ChatMessage(customTitle != null ? customTitle : ""));
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex);
} }
} }
@Override @Override
public void setLevelCost(int cost) { public void setLevelCost(int cost) {
this.cost = cost; this.cost = cost;
} }
@Override @Override
public int getLevelCost() { public int getLevelCost() {
if (cost >= 0) { if (cost >= 0) {
return cost; return cost;
} else if (compat_mode) { } else if (compat_mode) {
if (mc_ContainerProperty_get != null) { if (mc_ContainerProperty_get != null) {
try { try {
return (int) mc_ContainerProperty_get.invoke(this.levelCost); return (int) mc_ContainerProperty_get.invoke(this.levelCost);
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex);
mc_ContainerProperty_get = null; mc_ContainerProperty_get = null;
} }
} }
} else { } else {
return this.levelCost.get(); return this.levelCost.get();
} }
return -1; return -1;
} }
@Override @Override
public void setCanUse(boolean bool) { public void setCanUse(boolean bool) {
this.canUse = bool; this.canUse = bool;
} }
@Override @Override
public ItemStack getLeftInput() { public ItemStack getLeftInput() {
return inventory.getItem(0); return inventory.getItem(0);
} }
@Override @Override
public ItemStack getRightInput() { public ItemStack getRightInput() {
return inventory.getItem(1); return inventory.getItem(1);
} }
@Override @Override
public ItemStack getOutput() { public ItemStack getOutput() {
return inventory.getItem(2); return inventory.getItem(2);
} }
@Override @Override
public void setLeftInput(ItemStack item) { public void setLeftInput(ItemStack item) {
inventory.setItem(0, item); inventory.setItem(0, item);
} }
@Override @Override
public void setRightInput(ItemStack item) { public void setRightInput(ItemStack item) {
inventory.setItem(1, item); inventory.setItem(1, item);
} }
@Override @Override
public void setOutput(ItemStack item) { public void setOutput(ItemStack item) {
inventory.setItem(2, item); inventory.setItem(2, item);
} }
@Override @Override
public Inventory getInventory() { public Inventory getInventory() {
return inventory; return inventory;
} }
@Override @Override
public void open() { public void open() {
// Counter stuff that the game uses to keep track of inventories // Counter stuff that the game uses to keep track of inventories
int id = entity.nextContainerCounter(); int id = entity.nextContainerCounter();
// Send the packet // Send the packet
entity.playerConnection.sendPacket(new PacketPlayOutOpenWindow(id, Containers.ANVIL, new ChatMessage(customTitle != null ? customTitle : ""))); entity.playerConnection.sendPacket(new PacketPlayOutOpenWindow(id, Containers.ANVIL, new ChatMessage(customTitle != null ? customTitle : "")));
// Set their active container to this anvil // Set their active container to this anvil
entity.activeContainer = this; entity.activeContainer = this;
try { try {
// Set their active container window id to that counter stuff // Set their active container window id to that counter stuff
mc_Container_windowId.set(this, id); mc_Container_windowId.set(this, id);
} catch (Exception ex) { } catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Create Error", ex); Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Create Error", ex);
} }
// Add the slot listener // Add the slot listener
entity.activeContainer.addSlotListener(entity); entity.activeContainer.addSlotListener(entity);
} }
} }

View File

@ -1,24 +1,24 @@
package com.songoda.core.nms.v1_14_R1; package com.songoda.core.nms.v1_14_R1;
import com.songoda.core.nms.CoreNMS; import com.songoda.core.nms.CoreNMS;
import com.songoda.core.nms.CustomAnvil; import com.songoda.core.nms.CustomAnvil;
import net.minecraft.server.v1_14_R1.EntityPlayer; import net.minecraft.server.v1_14_R1.EntityPlayer;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
public class NMS implements CoreNMS { public class NMS implements CoreNMS {
@Override @Override
public CustomAnvil createAnvil(Player player) { public CustomAnvil createAnvil(Player player) {
EntityPlayer p = ((CraftPlayer) player).getHandle(); EntityPlayer p = ((CraftPlayer) player).getHandle();
return new AnvilView(p.nextContainerCounter(), p, null); return new AnvilView(p.nextContainerCounter(), p, null);
} }
@Override @Override
public CustomAnvil createAnvil(Player player, InventoryHolder holder) { public CustomAnvil createAnvil(Player player, InventoryHolder holder) {
EntityPlayer p = ((CraftPlayer) player).getHandle(); EntityPlayer p = ((CraftPlayer) player).getHandle();
return new AnvilView(p.nextContainerCounter(), p, holder); return new AnvilView(p.nextContainerCounter(), p, holder);
} }
} }

28
NMS/NMS-v1_15_R1/pom.xml Normal file
View File

@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>com.songoda</groupId>
<artifactId>SongodaCore-Modules</artifactId>
<version>maven-version-number</version>
<relativePath>../../</relativePath>
</parent>
<artifactId>SongodaCore-NMS-v1_15_R1</artifactId>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.songoda</groupId>
<artifactId>SongodaCore-NMS-API</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,22 @@
package com.songoda.core.nms.v1_15_R1;
import net.minecraft.server.v1_15_R1.ContainerAnvil;
import net.minecraft.server.v1_15_R1.IInventory;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftInventoryAnvil;
import org.bukkit.inventory.InventoryHolder;
public class AnvilInventoryCustom extends CraftInventoryAnvil {
final InventoryHolder holder;
public AnvilInventoryCustom(InventoryHolder holder, Location location, IInventory inventory, IInventory resultInventory, ContainerAnvil container) {
super(location, inventory, resultInventory, container);
this.holder = holder;
}
@Override
public InventoryHolder getHolder() {
return holder;
}
}

View File

@ -0,0 +1,261 @@
package com.songoda.core.nms.v1_15_R1;
import com.songoda.core.nms.CustomAnvil;
import com.songoda.core.nms.methods.AnvilTextChange;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.server.v1_15_R1.BlockPosition;
import net.minecraft.server.v1_15_R1.ChatMessage;
import net.minecraft.server.v1_15_R1.Container;
import net.minecraft.server.v1_15_R1.ContainerAccess;
import net.minecraft.server.v1_15_R1.ContainerAnvil;
import net.minecraft.server.v1_15_R1.ContainerProperty;
import net.minecraft.server.v1_15_R1.Containers;
import net.minecraft.server.v1_15_R1.EntityHuman;
import net.minecraft.server.v1_15_R1.EntityPlayer;
import net.minecraft.server.v1_15_R1.IInventory;
import net.minecraft.server.v1_15_R1.PacketPlayOutOpenWindow;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftInventoryView;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
public class AnvilView extends ContainerAnvil implements CustomAnvil {
private final EntityPlayer entity;
private final Inventory inventory;
private String customTitle = "Repairing";
private int cost = -1;
private boolean canUse = true;
private AnvilTextChange textChange = null;
// used for setting custom inventory
static Field mc_ContainerAnvil_repairInventory; // subcontainer with only the result
static Field mc_ContainerAnvil_resultInventory; // full inventory
static Field mc_ContainerAnvil_bukkitEntity;
static {
try {
mc_ContainerAnvil_repairInventory = ContainerAnvil.class.getDeclaredField("repairInventory");
mc_ContainerAnvil_repairInventory.setAccessible(true);
mc_ContainerAnvil_resultInventory = ContainerAnvil.class.getDeclaredField("resultInventory");
mc_ContainerAnvil_resultInventory.setAccessible(true);
mc_ContainerAnvil_bukkitEntity = ContainerAnvil.class.getDeclaredField("bukkitEntity");
mc_ContainerAnvil_bukkitEntity.setAccessible(true);
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
}
}
// 1.14.3 and 1.14.4 have different fields for levelCost
static boolean compat_mode = true;
static Method mc_ContainerProperty_set;
static Method mc_ContainerProperty_get;
// 1.14 also made this field private. Fun.
static Field mc_Container_windowId;
// 1.14 also introduced a title field, also private, which can only be set once and can't be checked
static Field mc_Container_title;
static {
try {
mc_Container_windowId = Container.class.getDeclaredField("windowId");
mc_Container_windowId.setAccessible(true);
mc_Container_title = Container.class.getDeclaredField("title");
mc_Container_title.setAccessible(true);
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
}
for (Method m : ContainerProperty.class.getMethods()) {
if (m.getName().equals("set")) {
compat_mode = false;
break;
}
}
if (compat_mode) {
try {
mc_ContainerProperty_set = ContainerProperty.class.getDeclaredMethod("a", int.class);
mc_ContainerProperty_get = ContainerProperty.class.getDeclaredMethod("b");
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
}
}
}
public AnvilView(int id, EntityPlayer entity, InventoryHolder holder) {
super(id, entity.inventory, ContainerAccess.at(entity.world, new BlockPosition(0, 0, 0)));
this.setTitle(new ChatMessage(customTitle != null ? customTitle : ""));
this.checkReachable = false;
this.entity = entity;
if(holder != null) {
this.inventory = getBukkitView(entity, holder).getTopInventory();
} else {
this.inventory = getBukkitView().getTopInventory();
}
}
public CraftInventoryView getBukkitView(EntityHuman player, InventoryHolder holder) {
try {
AnvilInventoryCustom craftInventory = new AnvilInventoryCustom(holder,
new Location(entity.world.getWorld(), 0, 0, 0),
(IInventory) mc_ContainerAnvil_repairInventory.get(this),
(IInventory) mc_ContainerAnvil_resultInventory.get(this), this);
CraftInventoryView view = new CraftInventoryView(player.getBukkitEntity(), craftInventory, this);
mc_ContainerAnvil_bukkitEntity.set(this, view);
return view;
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex);
}
return getBukkitView();
}
@Override
public boolean canUse(EntityHuman entityhuman) {
return canUse;
}
@Override
public void e() {
super.e();
if (cost >= 0) {
if (compat_mode) {
if (mc_ContainerProperty_set != null) {
try {
mc_ContainerProperty_set.invoke(this.levelCost, 0);
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex);
mc_ContainerProperty_set = null;
}
}
} else {
this.levelCost.set(cost);
}
}
textChange.onChange();
}
@Override
public void update() {
e();
}
@Override
public String getRenameText() {
return this.renameText;
}
@Override
public void setRenameText(String text) {
this.a(text);
}
@Override
public void setOnChange(AnvilTextChange handler) {
textChange = handler;
}
@Override
public String getCustomTitle() {
return customTitle;
}
@Override
public void setCustomTitle(String title) {
this.customTitle = title;
try {
mc_Container_title.set(this, new ChatMessage(customTitle != null ? customTitle : ""));
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex);
}
}
@Override
public void setLevelCost(int cost) {
this.cost = cost;
}
@Override
public int getLevelCost() {
if (cost >= 0) {
return cost;
} else if (compat_mode) {
if (mc_ContainerProperty_get != null) {
try {
return (int) mc_ContainerProperty_get.invoke(this.levelCost);
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex);
mc_ContainerProperty_get = null;
}
}
} else {
return this.levelCost.get();
}
return -1;
}
@Override
public void setCanUse(boolean bool) {
this.canUse = bool;
}
@Override
public ItemStack getLeftInput() {
return inventory.getItem(0);
}
@Override
public ItemStack getRightInput() {
return inventory.getItem(1);
}
@Override
public ItemStack getOutput() {
return inventory.getItem(2);
}
@Override
public void setLeftInput(ItemStack item) {
inventory.setItem(0, item);
}
@Override
public void setRightInput(ItemStack item) {
inventory.setItem(1, item);
}
@Override
public void setOutput(ItemStack item) {
inventory.setItem(2, item);
}
@Override
public Inventory getInventory() {
return inventory;
}
@Override
public void open() {
// Counter stuff that the game uses to keep track of inventories
int id = entity.nextContainerCounter();
// Send the packet
entity.playerConnection.sendPacket(new PacketPlayOutOpenWindow(id, Containers.ANVIL, new ChatMessage(customTitle != null ? customTitle : "")));
// Set their active container to this anvil
entity.activeContainer = this;
try {
// Set their active container window id to that counter stuff
mc_Container_windowId.set(this, id);
} catch (Exception ex) {
Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Create Error", ex);
}
// Add the slot listener
entity.activeContainer.addSlotListener(entity);
}
}

View File

@ -0,0 +1,24 @@
package com.songoda.core.nms.v1_15_R1;
import com.songoda.core.nms.CoreNMS;
import com.songoda.core.nms.CustomAnvil;
import net.minecraft.server.v1_15_R1.EntityPlayer;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
public class NMS implements CoreNMS {
@Override
public CustomAnvil createAnvil(Player player) {
EntityPlayer p = ((CraftPlayer) player).getHandle();
return new AnvilView(p.nextContainerCounter(), p, null);
}
@Override
public CustomAnvil createAnvil(Player player, InventoryHolder holder) {
EntityPlayer p = ((CraftPlayer) player).getHandle();
return new AnvilView(p.nextContainerCounter(), p, holder);
}
}

View File

@ -20,6 +20,7 @@
<module>NMS/NMS-v1_13_R1</module> <module>NMS/NMS-v1_13_R1</module>
<module>NMS/NMS-v1_13_R2</module> <module>NMS/NMS-v1_13_R2</module>
<module>NMS/NMS-v1_14_R1</module> <module>NMS/NMS-v1_14_R1</module>
<module>NMS/NMS-v1_15_R1</module>
</modules> </modules>
<build> <build>