OfflinePlayerReflectionTests

This commit is contained in:
James Peters 2022-01-03 16:46:17 +00:00
parent 332d6d3df1
commit ab9a31d78a
24 changed files with 538 additions and 31 deletions

View File

@ -9,5 +9,5 @@ public interface CraftingProvider {
CraftingResult craft(Player player, World world, ItemStack[] items); CraftingResult craft(Player player, World world, ItemStack[] items);
Recipe getRecipe(Player player, World world, ItemStack[] items); Recipe getRecipe(World world, ItemStack[] items);
} }

View File

@ -63,7 +63,7 @@ public class Crafting implements CraftingProvider {
} }
@Override @Override
public Recipe getRecipe(Player player, World world, ItemStack[] items) { public Recipe getRecipe(World world, ItemStack[] items) {
Container container = new Container(null, -1) { Container container = new Container(null, -1) {
@Override @Override
public InventoryView getBukkitView() { public InventoryView getBukkitView() {

View File

@ -63,7 +63,7 @@ public class Crafting implements CraftingProvider {
} }
@Override @Override
public Recipe getRecipe(Player player, World world, ItemStack[] items) { public Recipe getRecipe(World world, ItemStack[] items) {
Container container = new Container(null, -1) { Container container = new Container(null, -1) {
@Override @Override
public InventoryView getBukkitView() { public InventoryView getBukkitView() {

View File

@ -63,7 +63,7 @@ public class Crafting implements CraftingProvider {
} }
@Override @Override
public Recipe getRecipe(Player player, World world, ItemStack[] items) { public Recipe getRecipe(World world, ItemStack[] items) {
Container container = new Container(null, -1) { Container container = new Container(null, -1) {
@Override @Override
public InventoryView getBukkitView() { public InventoryView getBukkitView() {

View File

@ -22,7 +22,7 @@ public class Crafting implements CraftingProvider {
} }
@Override @Override
public Recipe getRecipe(Player player, World world, ItemStack[] items) { public Recipe getRecipe(World world, ItemStack[] items) {
return Bukkit.getCraftingRecipe(items, world); return Bukkit.getCraftingRecipe(items, world);
} }
} }

View File

@ -17,6 +17,7 @@ import com.jamesdpeters.minecraft.chests.misc.Stats;
import com.jamesdpeters.minecraft.chests.misc.Utils; import com.jamesdpeters.minecraft.chests.misc.Utils;
import com.jamesdpeters.minecraft.chests.party.PlayerParty; import com.jamesdpeters.minecraft.chests.party.PlayerParty;
import com.jamesdpeters.minecraft.chests.party.PlayerPartyStorage; import com.jamesdpeters.minecraft.chests.party.PlayerPartyStorage;
import com.jamesdpeters.minecraft.chests.players.PlayerStorage;
import com.jamesdpeters.minecraft.chests.serialize.Config; import com.jamesdpeters.minecraft.chests.serialize.Config;
import com.jamesdpeters.minecraft.chests.serialize.ConfigStorage; import com.jamesdpeters.minecraft.chests.serialize.ConfigStorage;
import com.jamesdpeters.minecraft.chests.serialize.LocationInfo; import com.jamesdpeters.minecraft.chests.serialize.LocationInfo;
@ -141,6 +142,7 @@ public class ChestsPlusPlus extends JavaPlugin {
getServer().getPluginManager().registerEvents(new InventoryListener(), this); getServer().getPluginManager().registerEvents(new InventoryListener(), this);
getServer().getPluginManager().registerEvents(new HopperListener(), this); getServer().getPluginManager().registerEvents(new HopperListener(), this);
getServer().getPluginManager().registerEvents(new WorldListener(), this); getServer().getPluginManager().registerEvents(new WorldListener(), this);
getServer().getPluginManager().registerEvents(new PlayerStorage(), this);
Config.getStorageTypes().forEach(storageType -> getServer().getPluginManager().registerEvents(storageType, this)); Config.getStorageTypes().forEach(storageType -> getServer().getPluginManager().registerEvents(storageType, this));
getLogger().info("Chests++ enabled!"); getLogger().info("Chests++ enabled!");
}, 1); }, 1);

View File

@ -32,8 +32,8 @@ public class Crafting {
}); });
} }
public static Recipe getRecipe(Player player, ItemStack[] craftingTable) { public static Recipe getRecipe(ItemStack[] craftingTable) {
return ApiSpecific.getNmsProvider().getCraftingProvider().getRecipe(player, Bukkit.getWorlds().get(0), craftingTable); return ApiSpecific.getNmsProvider().getCraftingProvider().getRecipe(Bukkit.getWorlds().get(0), craftingTable);
} }
public static CraftingResult craft(Player player, ItemStack[] recipe) { public static CraftingResult craft(Player player, ItemStack[] recipe) {

View File

@ -18,6 +18,7 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.Container; import org.bukkit.block.Container;
import org.bukkit.block.Hopper; import org.bukkit.block.Hopper;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
@ -33,6 +34,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class VirtualCraftingHolder implements InventoryHolder { public class VirtualCraftingHolder implements InventoryHolder {
@ -44,6 +46,7 @@ public class VirtualCraftingHolder implements InventoryHolder {
private ItemStack[][] recipeChoices = new ItemStack[9][]; private ItemStack[][] recipeChoices = new ItemStack[9][];
private ItemStack result; private ItemStack result;
private ItemStack[] matrixResult; // stored matrix result after a crafting event
private final int[] recipeChoiceIndex = new int[9]; private final int[] recipeChoiceIndex = new int[9];
private boolean hasCompleteRecipe = false; private boolean hasCompleteRecipe = false;
@ -71,6 +74,7 @@ public class VirtualCraftingHolder implements InventoryHolder {
public void setCrafting(ShapelessRecipe shapelessRecipe) { public void setCrafting(ShapelessRecipe shapelessRecipe) {
result = shapelessRecipe.getResult(); result = shapelessRecipe.getResult();
matrixResult = null;
List<RecipeChoice> choiceList = shapelessRecipe.getChoiceList(); List<RecipeChoice> choiceList = shapelessRecipe.getChoiceList();
for (int i = 0; i < choiceList.size(); i++) { for (int i = 0; i < choiceList.size(); i++) {
RecipeChoice recipeChoice = choiceList.get(i); RecipeChoice recipeChoice = choiceList.get(i);
@ -84,6 +88,7 @@ public class VirtualCraftingHolder implements InventoryHolder {
public void setCrafting(ShapedRecipe recipe) { public void setCrafting(ShapedRecipe recipe) {
result = recipe.getResult(); result = recipe.getResult();
matrixResult = null;
int row = 0; int row = 0;
for (String r : recipe.getShape()) { for (String r : recipe.getShape()) {
int col = 0; int col = 0;
@ -101,12 +106,13 @@ public class VirtualCraftingHolder implements InventoryHolder {
setHasCompleteRecipe(); setHasCompleteRecipe();
} }
public void setCrafting(Recipe recipe, ItemStack[] matrix) { public void setCrafting(Recipe recipe, ItemStack[] matrix, ItemStack[] matrixResult) {
if (recipe instanceof ShapedRecipe) setCrafting((ShapedRecipe) recipe); if (recipe instanceof ShapedRecipe) setCrafting((ShapedRecipe) recipe);
else if (recipe instanceof ShapelessRecipe) setCrafting((ShapelessRecipe) recipe); else if (recipe instanceof ShapelessRecipe) setCrafting((ShapelessRecipe) recipe);
else { else {
// For ComplexRecipes or other implementations just use the result and original matrix for choices. // For ComplexRecipes or other implementations just use the result and original matrix for choices.
result = ApiSpecific.getNmsProvider().getCraftingProvider().craft(storage.getOwner().getPlayer(), Bukkit.getWorlds().get(0), matrix).result(); result = recipe.getResult();
this.matrixResult = matrixResult;
for (int i = 0; i < matrix.length; i++) { for (int i = 0; i < matrix.length; i++) {
ItemStack item = matrix[i]; ItemStack item = matrix[i];
if (item != null) { if (item != null) {
@ -131,15 +137,18 @@ public class VirtualCraftingHolder implements InventoryHolder {
stopCraftingItems(); stopCraftingItems();
} }
public void updateCrafting() { public void updateCrafting(InventoryEvent event) {
var crafting = Arrays.copyOfRange(inventory.getContents(),1, inventory.getContents().length); var crafting = Arrays.copyOfRange(inventory.getContents(),1, inventory.getContents().length);
Recipe recipe = Crafting.getRecipe(storage.getOwner().getPlayer(), crafting); Player player = (Player) event.getView().getPlayer();
getStorage().setRecipe(recipe, crafting); // Only store the crafting matrix if the recipe is valid var craftingResult = ApiSpecific.getNmsProvider().getCraftingProvider().craft(player, player.getWorld(), Arrays.copyOf(crafting, crafting.length));
Recipe recipe = Crafting.getRecipe(crafting);
getStorage().setRecipe(recipe, crafting, craftingResult.matrixResult()); // Only store the crafting matrix if the recipe is valid
resetChoices(); resetChoices();
if (recipe != null) { if (recipe != null) {
setCrafting(recipe, crafting); setCrafting(recipe, crafting, craftingResult.matrixResult());
playSound(Sound.BLOCK_NOTE_BLOCK_CHIME, 0.5f, 1f); playSound(Sound.BLOCK_NOTE_BLOCK_CHIME, 0.5f, 1f);
} else { } else {
stopCraftingItems(); stopCraftingItems();
@ -426,13 +435,16 @@ public class VirtualCraftingHolder implements InventoryHolder {
Inventory tempOutput = sameInv ? sameInventory : Utils.copyInventory(output); Inventory tempOutput = sameInv ? sameInventory : Utils.copyInventory(output);
HashMap<Integer, ItemStack> map = tempOutput.addItem(craftingResult.result()); HashMap<Integer, ItemStack> map = tempOutput.addItem(craftingResult.result());
boolean isEmpty = Arrays.stream(craftingResult.matrixResult()) // Remove nulls from matrix result.
.anyMatch(itemStack -> (itemStack == null || itemStack.getType() == Material.AIR)); var matrix = Arrays.stream(craftingResult.matrixResult())
.filter(Objects::nonNull).toList();
boolean isEmpty = matrix.stream().allMatch(itemStack -> itemStack.getType() == Material.AIR);
// Add any leftover items from the recipe e.g buckets. // Add any leftover items from the recipe e.g buckets.
HashMap<Integer, ItemStack> craftingMatrixLeftOvers = HashMap<Integer, ItemStack> craftingMatrixLeftOvers =
isEmpty ? Maps.newHashMap() isEmpty ? Maps.newHashMap()
: tempOutput.addItem(craftingResult.matrixResult()); : tempOutput.addItem(matrix.toArray(ItemStack[]::new));
//If result fits into output copy over the temporary inventories. //If result fits into output copy over the temporary inventories.
if (map.isEmpty() && craftingMatrixLeftOvers.isEmpty()) { if (map.isEmpty() && craftingMatrixLeftOvers.isEmpty()) {

View File

@ -113,10 +113,9 @@ public class InventoryListener implements Listener {
} }
private void craftingUpdate(InventoryInteractEvent event) { private void craftingUpdate(InventoryInteractEvent event) {
InventoryHolder holder = event.getInventory().getHolder(); if (event.getInventory().getHolder() instanceof VirtualCraftingHolder vHolder) {
if (holder instanceof VirtualCraftingHolder) { Bukkit.getScheduler().scheduleSyncDelayedTask(ChestsPlusPlus.PLUGIN, () -> vHolder.setUpdatingRecipe(true).updateCrafting(event), 1);
Bukkit.getScheduler().scheduleSyncDelayedTask(ChestsPlusPlus.PLUGIN, (((VirtualCraftingHolder) holder).setUpdatingRecipe(true))::updateCrafting, 1); Bukkit.getScheduler().scheduleSyncDelayedTask(ChestsPlusPlus.PLUGIN, vHolder::forceUpdateInventory, 1);
Bukkit.getScheduler().scheduleSyncDelayedTask(ChestsPlusPlus.PLUGIN, (((VirtualCraftingHolder) holder))::forceUpdateInventory, 1);
} }
} }

View File

@ -0,0 +1,5 @@
package com.jamesdpeters.minecraft.chests.misc;
public class OfflinePlayerUtil {
}

View File

@ -0,0 +1,92 @@
package com.jamesdpeters.minecraft.chests.players;
import com.jamesdpeters.minecraft.chests.reflection.craftbukkit.CraftPlayer;
import com.jamesdpeters.minecraft.chests.reflection.craftbukkit.CraftServer;
import com.jamesdpeters.minecraft.chests.reflection.craftbukkit.CraftWorld;
import com.jamesdpeters.minecraft.chests.reflection.minecraft.EntityPlayer;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.world.WorldSaveEvent;
import java.util.HashMap;
import java.util.UUID;
import java.util.function.Consumer;
public class PlayerStorage implements Listener {
private static final HashMap<UUID, Player> offlinePlayers = new HashMap<>();
@EventHandler
public void onPlayerJoin(PlayerLoginEvent event) {
if (event.getResult() == PlayerLoginEvent.Result.ALLOWED) {
var player = offlinePlayers.remove(event.getPlayer().getUniqueId());
if (player != null) {
player.saveData();
event.getPlayer().loadData();
}
}
}
@EventHandler
public void onSave(WorldSaveEvent event) {
offlinePlayers.forEach((uuid, player) -> {
player.saveData();
});
}
@EventHandler
public void onCraft(PrepareItemCraftEvent event) {
Player player = (Player) event.getView().getPlayer();
player.giveExp(10);
Bukkit.broadcastMessage("Inventory type: "+player.getOpenInventory().getType());
}
public static void runMethodOnOfflinePlayer(OfflinePlayer offlinePlayer, World world, Consumer<Player> playerConsumer) {
Player player = getPlayer(offlinePlayer, world);
if (player != null) {
playerConsumer.accept(player);
}
}
private static Player getPlayer(OfflinePlayer offlinePlayer, World world) {
Player player = offlinePlayer.getPlayer();
if (player != null)
return player;
player = offlinePlayers.get(offlinePlayer.getUniqueId());
if (player != null)
return player;
try {
player = generateFakePlayer(offlinePlayer, world);
offlinePlayers.put(offlinePlayer.getUniqueId(), player);
return player;
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
private static Player generateFakePlayer(OfflinePlayer offlinePlayer, World world) throws NoSuchMethodException {
var craftServer = new CraftServer(Bukkit.getServer());
var minecraftServer = craftServer.getServer();
var craftWorld = new CraftWorld(world);
var worldServer = craftWorld.getWorldServer();
var gameProfile = minecraftServer.getGameProfile(offlinePlayer.getUniqueId(), offlinePlayer.getName());
var entityPlayer = new EntityPlayer(minecraftServer, worldServer, gameProfile);
minecraftServer.loadEntity(entityPlayer);
var craftPlayer = new CraftPlayer(craftServer, entityPlayer);
var player = craftPlayer.getOriginalObj();
player.loadData();
return player;
}
}

View File

@ -0,0 +1,40 @@
package com.jamesdpeters.minecraft.chests.reflection.craftbukkit;
import com.jamesdpeters.minecraft.chests.reflection.helpers.BaseReflection;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectMethod;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectionUtil;
import com.jamesdpeters.minecraft.chests.reflection.minecraft.EntityPlayer;
import org.bukkit.entity.Player;
import java.lang.reflect.Constructor;
import java.util.Objects;
public class CraftPlayer extends BaseReflection<Player> {
public static final Class<?> clazz = ReflectionUtil.getCraftBukkitClass("entity.CraftPlayer");
private static final Constructor<?> constructor = ReflectionUtil.getConstructor(clazz, CraftServer.clazz, EntityPlayer.clazz);
private static final ReflectMethod getHandle = ReflectionUtil.getMethod("getHandle", clazz);
static {
assert clazz != null;
assert constructor != null;
}
public CraftPlayer(CraftServer craftServer, EntityPlayer entityPlayer) throws NoSuchMethodException {
super(clazz, Objects.requireNonNull(constructor), craftServer, entityPlayer);
}
public CraftPlayer(Player player) {
super(clazz, player);
}
@Override
public Player getOriginalObj() {
return (Player) getHandle();
}
public EntityPlayer getEntityPlayer() {
return new EntityPlayer(getHandle.invoke(getHandle()));
}
}

View File

@ -0,0 +1,27 @@
package com.jamesdpeters.minecraft.chests.reflection.craftbukkit;
import com.jamesdpeters.minecraft.chests.reflection.helpers.BaseReflection;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectMethod;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectionUtil;
import com.jamesdpeters.minecraft.chests.reflection.minecraft.MinecraftServer;
import org.bukkit.Server;
public class CraftServer extends BaseReflection<Server> {
public static final Class<?> clazz = ReflectionUtil.getCraftBukkitClass("CraftServer");
private static final ReflectMethod getServer = ReflectionUtil.getMethod("getServer", clazz);
static {
assert clazz != null;
assert getServer != null;
}
public CraftServer(Server server) {
super(clazz, server);
}
public MinecraftServer getServer() {
assert getServer != null;
return new MinecraftServer(getServer.invoke(getOriginalObj()));
}
}

View File

@ -0,0 +1,27 @@
package com.jamesdpeters.minecraft.chests.reflection.craftbukkit;
import com.jamesdpeters.minecraft.chests.reflection.helpers.BaseReflection;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectMethod;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectionUtil;
import com.jamesdpeters.minecraft.chests.reflection.minecraft.WorldServer;
import org.bukkit.World;
public class CraftWorld extends BaseReflection<World> {
private static final Class<?> clazz = ReflectionUtil.getCraftBukkitClass("CraftWorld");
public static final ReflectMethod getHandle = ReflectionUtil.getMethod("getHandle", clazz);
static {
assert clazz != null;
assert getHandle != null;
}
public CraftWorld(World world) {
super(clazz, world);
}
public WorldServer getWorldServer() {
return new WorldServer(this);
}
}

View File

@ -0,0 +1,42 @@
package com.jamesdpeters.minecraft.chests.reflection.helpers;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
public class BaseReflection<T> {
protected Object handle;
private final T originalObj;
private final Class<?> clazz;
public BaseReflection(Class<?> clazz, T from) {
assert clazz.isAssignableFrom(from.getClass());
this.handle = clazz.cast(from);
this.clazz = clazz;
this.originalObj = from;
}
public BaseReflection(Class<?> clazz, Constructor<?> constructor, BaseReflection<?>... parameters) throws NoSuchMethodException {
this.clazz = clazz;
this.originalObj = null;
try {
var handles = Arrays.stream(parameters).map(BaseReflection::getHandle).toArray();
this.handle = constructor.newInstance(handles);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
public T getOriginalObj() {
return originalObj;
}
public Object getHandle() {
return handle;
}
public Class<?> getClazz() {
return clazz;
}
}

View File

@ -0,0 +1,22 @@
package com.jamesdpeters.minecraft.chests.reflection.helpers;
import java.lang.reflect.Method;
public class ReflectMethod {
private final Method method;
public ReflectMethod(Method method) {
method.setAccessible(true);
this.method = method;
}
public Object invoke(Object instance, Object... args) {
try {
return method.invoke(instance, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,86 @@
package com.jamesdpeters.minecraft.chests.reflection.helpers;
import org.bukkit.Bukkit;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
public class ReflectionUtil {
private static final String version;
static {
String packageName = Bukkit.getServer().getClass().getPackage().getName();
var tempVersion = packageName.substring(packageName.lastIndexOf(".") + 1);
if (tempVersion.equals("craftbukkit"))
version = "";
else version = tempVersion;
}
public static String getNmsPrefix() {
return "net.minecraft.server." + getVersionPrefix() ;
}
private static String getVersionPrefix() {
return version.isEmpty() ? "" : version + ".";
}
public static String getCraftBukkitPrefix() {
return "org.bukkit.craftbukkit." +getVersionPrefix();
}
public static Class<?> getNmsClass(String name) {
return getClass("net.minecraft.server." + name , false);
}
public static Class<?> getNbtClass(String name) {
return getClass("net.minecraft.nbt." + name , false);
}
public static Class<?> getNmsClassAsArray(String name) {
return getClass("net.minecraft.server." + name , true);
}
public static Class<?> getCraftBukkitClass(String name) {
return getClass("org.bukkit.craftbukkit." + getVersionPrefix() + name , false);
}
public static Class<?> getCraftBukkitClassAsArray(String name) {
return getClass("org.bukkit.craftbukkit." + getVersionPrefix() + name , true);
}
public static Class<?> getMojangAuthClass(String name) {
return getClass("com.mojang.authlib." + name , false);
}
private static Class<?> getClass(String name, boolean asArray) {
try {
if(asArray) return Array.newInstance(Class.forName(name), 0).getClass();
else return Class.forName(name);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static ReflectMethod getMethod(String name , Class<?> clazz , Class<?>... parameterClasses) {
try {
return new ReflectMethod(clazz.getDeclaredMethod(name, parameterClasses));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Constructor<?> getConstructor(Class<?> clazz, Class<?>... constructorParameters) {
try {
return clazz.getConstructor(constructorParameters);
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,37 @@
package com.jamesdpeters.minecraft.chests.reflection.minecraft;
import com.jamesdpeters.minecraft.chests.reflection.helpers.BaseReflection;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectMethod;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectionUtil;
import com.jamesdpeters.minecraft.chests.reflection.mojangauth.GameProfile;
import java.lang.reflect.Constructor;
import java.util.Objects;
public class EntityPlayer extends BaseReflection<Object> {
public static final Class<?> clazz = ReflectionUtil.getNmsClass("level.EntityPlayer");
private static final Constructor<?> constructor = ReflectionUtil.getConstructor(clazz, MinecraftServer.clazz, WorldServer.clazz, GameProfile.clazz);
private static final Class<?> nbtTagCompoundClazz = ReflectionUtil.getNbtClass("NBTTagCompound");
private static final ReflectMethod loadGameTypes = ReflectionUtil.getMethod("loadGameTypes", clazz, nbtTagCompoundClazz);
static {
assert clazz != null;
assert constructor != null;
}
public EntityPlayer(MinecraftServer minecraftServer, WorldServer worldServer, GameProfile gameProfile) throws NoSuchMethodException {
super(clazz, Objects.requireNonNull(constructor), minecraftServer, worldServer, gameProfile);
}
public EntityPlayer(Object object) {
super(clazz, object);
}
public void loadGameTypes(Object nbtTagCompound) {
Object tag = nbtTagCompoundClazz.cast(nbtTagCompound);
loadGameTypes.invoke(getHandle(), tag);
}
}

View File

@ -0,0 +1,55 @@
package com.jamesdpeters.minecraft.chests.reflection.minecraft;
import com.jamesdpeters.minecraft.chests.reflection.helpers.BaseReflection;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectMethod;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectionUtil;
import com.jamesdpeters.minecraft.chests.reflection.mojangauth.GameProfile;
import java.util.Optional;
import java.util.UUID;
public class MinecraftServer extends BaseReflection<Object> {
public static final Class<?> clazz = ReflectionUtil.getNmsClass("MinecraftServer");
private static final Class<?> userCache = ReflectionUtil.getNmsClass("players.UserCache");
private static final Class<?> playerList = ReflectionUtil.getNmsClass("players.PlayerList");
private static final ReflectMethod getProfileCache = ReflectionUtil.getMethod("getProfileCache", clazz);
private static final ReflectMethod userCache_get = ReflectionUtil.getMethod("get", userCache, UUID.class);
private static final ReflectMethod getPlayerList = ReflectionUtil.getMethod("getPlayerList", clazz);
private static final ReflectMethod playerList_loadEntity = ReflectionUtil.getMethod("load", playerList, EntityPlayer.clazz);
private static final ReflectMethod playerList_saveEntity = ReflectionUtil.getMethod("save", playerList, EntityPlayer.clazz);
static {
assert clazz != null;
assert userCache_get != null;
assert getProfileCache != null;
assert userCache_get != null;
}
public MinecraftServer(Object dediServer) {
super(clazz, dediServer);
}
public GameProfile getGameProfile(UUID uuid, String defaultName) {
assert getProfileCache != null;
var profileCache = getProfileCache.invoke(getHandle());
var opt = userCache_get.invoke(profileCache, uuid);
return GameProfile.fromOptional((Optional<?>) opt, uuid, defaultName);
}
public void loadEntity(EntityPlayer entityPlayer) {
var playerList = getPlayerList.invoke(getHandle());
var result = playerList_loadEntity.invoke(playerList, entityPlayer.getHandle());
entityPlayer.loadGameTypes(result);
}
public void saveEntity(EntityPlayer entityPlayer) {
var playerList = getPlayerList.invoke(getHandle());
playerList_saveEntity.invoke(playerList, entityPlayer.getHandle());
}
}

View File

@ -0,0 +1,21 @@
package com.jamesdpeters.minecraft.chests.reflection.minecraft;
import com.jamesdpeters.minecraft.chests.reflection.craftbukkit.CraftWorld;
import com.jamesdpeters.minecraft.chests.reflection.helpers.BaseReflection;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectionUtil;
import java.util.Objects;
public class WorldServer extends BaseReflection<Object> {
public static final Class<?> clazz = ReflectionUtil.getNmsClass("level.WorldServer");
static {
assert clazz != null;
}
public WorldServer(CraftWorld craftWorld) {
super(clazz, Objects.requireNonNull(CraftWorld.getHandle).invoke(craftWorld.getHandle()));
}
}

View File

@ -0,0 +1,31 @@
package com.jamesdpeters.minecraft.chests.reflection.mojangauth;
import com.jamesdpeters.minecraft.chests.reflection.helpers.BaseReflection;
import com.jamesdpeters.minecraft.chests.reflection.helpers.ReflectionUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import java.util.UUID;
public class GameProfile extends BaseReflection<Object> {
public static final Class<?> clazz = ReflectionUtil.getMojangAuthClass("GameProfile");
private static final Constructor<?> constructor = ReflectionUtil.getConstructor(clazz, UUID.class, String.class);
public GameProfile(Object from) {
super(clazz, from);
}
public static GameProfile fromOptional(Optional<?> from, UUID defaultUUID, String defaultName) {
return new GameProfile(from.orElseGet(() -> {
try {
constructor.newInstance(defaultName, defaultName);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
return null;
}));
}
}

View File

@ -7,14 +7,12 @@ import org.bukkit.Keyed;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe; import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.ShapelessRecipe;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
@SerializableAs("C++Recipe") @SerializableAs("C++Recipe")
@ -25,10 +23,12 @@ public class RecipeSerializable implements ConfigurationSerializable {
// Store items used for ComplexRecipes // Store items used for ComplexRecipes
private ItemStack[] items; private ItemStack[] items;
private ItemStack[] returnedItems; // Stores and items returned from the recipe. i.e Buckets/bottles etc.
public RecipeSerializable(Recipe recipe, ItemStack[] items) { public RecipeSerializable(Recipe recipe, ItemStack[] items, ItemStack[] returnedItems) {
this.recipe = recipe; this.recipe = recipe;
this.items = items; this.items = items;
this.returnedItems = returnedItems;
if (recipe instanceof Keyed){ if (recipe instanceof Keyed){
namespacedKey = ((Keyed) recipe).getKey(); namespacedKey = ((Keyed) recipe).getKey();
} }
@ -37,18 +37,22 @@ public class RecipeSerializable implements ConfigurationSerializable {
public RecipeSerializable(Map<String, Object> map) { public RecipeSerializable(Map<String, Object> map) {
Object obj = map.get("items"); Object obj = map.get("items");
if (obj != null) { if (obj != null) {
//noinspection unchecked
items = (ItemStack[]) obj; items = (ItemStack[]) obj;
} }
Object retItems = map.get("returnedItems");
if (retItems != null) {
returnedItems = (ItemStack[]) retItems;
}
//noinspection deprecation //noinspection deprecation
namespacedKey = new NamespacedKey((String) map.get("namespace"), (String) map.get("key")); namespacedKey = new NamespacedKey((String) map.get("namespace"), (String) map.get("key"));
recipe = Crafting.getRecipeByKey(namespacedKey); recipe = Crafting.getRecipeByKey(namespacedKey);
} }
public void updateRecipe(Player player) { public void updateRecipe() {
if (recipe == null) { if (recipe == null) {
recipe = ApiSpecific.getNmsProvider().getCraftingProvider().getRecipe(player, Bukkit.getWorlds().get(0), items); recipe = ApiSpecific.getNmsProvider().getCraftingProvider().getRecipe(Bukkit.getWorlds().get(0), items);
} }
} }
@ -59,6 +63,7 @@ public class RecipeSerializable implements ConfigurationSerializable {
map.put("key", namespacedKey.getKey()); map.put("key", namespacedKey.getKey());
if (!(recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe)) { if (!(recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe)) {
map.put("items", items); map.put("items", items);
map.put("returnedItems", returnedItems);
} }
return map; return map;
} }
@ -74,4 +79,8 @@ public class RecipeSerializable implements ConfigurationSerializable {
public ItemStack[] getItems() { public ItemStack[] getItems() {
return items; return items;
} }
public ItemStack[] getReturnedItems() {
return returnedItems;
}
} }

View File

@ -52,7 +52,7 @@ public class AutoCraftingStorage extends AbstractStorage implements Configuratio
recipeSerializable = (RecipeSerializable) map.get("recipe"); recipeSerializable = (RecipeSerializable) map.get("recipe");
//If autocraft doesn't have a recipe in it it will be throw a NPE, this check seems to be working. Also the exception caused data loss in the data file //If autocraft doesn't have a recipe in it it will be throw a NPE, this check seems to be working. Also the exception caused data loss in the data file
if (recipeSerializable != null) { if (recipeSerializable != null) {
recipeSerializable.updateRecipe(getOwner().getPlayer()); recipeSerializable.updateRecipe();
} }
identifier = (String) map.get("identifier"); identifier = (String) map.get("identifier");
initInventory(); initInventory();
@ -63,12 +63,12 @@ public class AutoCraftingStorage extends AbstractStorage implements Configuratio
return false; return false;
} }
public void setRecipe(Recipe recipe, ItemStack[] items) { public void setRecipe(Recipe recipe, ItemStack[] items, ItemStack[] returnedItems) {
if (recipe == null) { if (recipe == null) {
recipeSerializable = null; recipeSerializable = null;
return; return;
} }
recipeSerializable = new RecipeSerializable(recipe, items); recipeSerializable = new RecipeSerializable(recipe, items, returnedItems);
} }
@Override @Override
@ -109,7 +109,7 @@ public class AutoCraftingStorage extends AbstractStorage implements Configuratio
virtualCraftingHolder.setCrafting((ShapedRecipe) recipe); virtualCraftingHolder.setCrafting((ShapedRecipe) recipe);
} }
else { else {
virtualCraftingHolder.setCrafting(recipe, recipeSerializable.getItems()); virtualCraftingHolder.setCrafting(recipe, recipeSerializable.getItems(), recipeSerializable.getReturnedItems());
} }
} else { } else {
virtualCraftingHolder.resetChoices(); virtualCraftingHolder.resetChoices();

View File

@ -1,4 +1,4 @@
# Chests++ Language File (Version 2.5.2-BETA-2) # Chests++ Language File (Version 2.5.2-BETA-3)
# NOTE: This file gets replaced when the plugin launches! If you want to make modifications create a copy first! # NOTE: This file gets replaced when the plugin launches! If you want to make modifications create a copy first!
# To create a new language file simply create a copy of this file and rename it to your desired choice for example 'en_US.properties' # To create a new language file simply create a copy of this file and rename it to your desired choice for example 'en_US.properties'
# It should be located in the 'lang' folder # It should be located in the 'lang' folder