Experimental PlayerInventory serdes support.
This commit is contained in:
parent
4c70897d87
commit
9cc687dab0
@ -2,11 +2,14 @@ package com.massivecraft.mcore.adapter;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftInventoryCustom;
|
||||
import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftInventoryPlayer;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
import com.massivecraft.mcore.MCore;
|
||||
import com.massivecraft.mcore.inventory.MCorePlayerInventory;
|
||||
import com.massivecraft.mcore.xlib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore.xlib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore.xlib.gson.JsonElement;
|
||||
@ -16,6 +19,11 @@ import com.massivecraft.mcore.xlib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore.xlib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore.xlib.gson.JsonSerializer;
|
||||
|
||||
/**
|
||||
* This is my Gson adapter for Inventories.
|
||||
* It handles all inventories as CraftInventoryCustom "Chest"s with size of your choice
|
||||
* except for PlayerInventory which it handles pretty darn well!
|
||||
*/
|
||||
public class InventoryAdapter implements JsonDeserializer<Inventory>, JsonSerializer<Inventory>
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
@ -23,6 +31,13 @@ public class InventoryAdapter implements JsonDeserializer<Inventory>, JsonSerial
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static final String SIZE = "size";
|
||||
|
||||
public static final String PLAYER = "player";
|
||||
|
||||
public static final String HELMET = "helmet";
|
||||
public static final String CHESTPLATE = "chestplate";
|
||||
public static final String LEGGINGS = "leggings";
|
||||
public static final String BOOTS = "boots";
|
||||
|
||||
// -------------------------------------------- //
|
||||
// IMPLEMENTATION
|
||||
@ -46,42 +61,161 @@ public class InventoryAdapter implements JsonDeserializer<Inventory>, JsonSerial
|
||||
|
||||
public static JsonElement toJson(Inventory src)
|
||||
{
|
||||
// The return value is this object:
|
||||
JsonObject jsonInventory = new JsonObject();
|
||||
ItemStack[] itemStacks = src.getContents();
|
||||
jsonInventory.add(SIZE, new JsonPrimitive(itemStacks.length));
|
||||
|
||||
// These variables are used in loops and repetitive logic.
|
||||
ItemStack itemStack = null;
|
||||
JsonElement jsonItemStack = null;
|
||||
|
||||
// Every inventory has a content part. Lets handle it at once:
|
||||
ItemStack[] itemStacks = src.getContents();
|
||||
for (int i = 0; i < itemStacks.length; i++)
|
||||
{
|
||||
ItemStack itemStack = itemStacks[i];
|
||||
JsonElement jsonItemStack = MCore.gson.toJsonTree(itemStack, ItemStack.class);
|
||||
itemStack = itemStacks[i];
|
||||
jsonItemStack = MCore.gson.toJsonTree(itemStack, ItemStack.class);
|
||||
if (jsonItemStack == null) continue;
|
||||
jsonInventory.add(String.valueOf(i), jsonItemStack);
|
||||
}
|
||||
|
||||
if (src instanceof PlayerInventory)
|
||||
{
|
||||
// Add the size "player"
|
||||
jsonInventory.addProperty(SIZE, PLAYER);
|
||||
|
||||
// Cast to PlayerInventory
|
||||
PlayerInventory psrc = (PlayerInventory)src;
|
||||
|
||||
// helmet
|
||||
itemStack = psrc.getHelmet();
|
||||
if (itemStack != null)
|
||||
{
|
||||
jsonItemStack = MCore.gson.toJsonTree(itemStack, ItemStack.class);
|
||||
jsonInventory.add(HELMET, jsonItemStack);
|
||||
}
|
||||
|
||||
// chestplate
|
||||
itemStack = psrc.getChestplate();
|
||||
if (itemStack != null)
|
||||
{
|
||||
jsonItemStack = MCore.gson.toJsonTree(itemStack, ItemStack.class);
|
||||
jsonInventory.add(CHESTPLATE, jsonItemStack);
|
||||
}
|
||||
|
||||
// leggings
|
||||
itemStack = psrc.getLeggings();
|
||||
if (itemStack != null)
|
||||
{
|
||||
jsonItemStack = MCore.gson.toJsonTree(itemStack, ItemStack.class);
|
||||
jsonInventory.add(LEGGINGS, jsonItemStack);
|
||||
}
|
||||
|
||||
// boots
|
||||
itemStack = psrc.getBoots();
|
||||
if (itemStack != null)
|
||||
{
|
||||
jsonItemStack = MCore.gson.toJsonTree(itemStack, ItemStack.class);
|
||||
jsonInventory.add(BOOTS, jsonItemStack);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the size *length*
|
||||
jsonInventory.addProperty(SIZE, itemStacks.length);
|
||||
}
|
||||
|
||||
return jsonInventory;
|
||||
}
|
||||
|
||||
public static Inventory fromJson(JsonElement json)
|
||||
{
|
||||
// If must be an object!
|
||||
if ( ! json.isJsonObject()) return null;
|
||||
JsonObject jsonInventory = json.getAsJsonObject();
|
||||
|
||||
// The return value
|
||||
Inventory ret = null;
|
||||
|
||||
// These variables are used in loops and repetitive logic.
|
||||
ItemStack itemStack = null;
|
||||
JsonElement jsonItemStack = null;
|
||||
|
||||
// There must be a size entry!
|
||||
if ( ! jsonInventory.has(SIZE)) return null;
|
||||
int size = jsonInventory.get(SIZE).getAsInt();
|
||||
JsonPrimitive jsonSize = jsonInventory.get(SIZE).getAsJsonPrimitive();
|
||||
int size = 0;
|
||||
|
||||
// What size/type is it?
|
||||
if (jsonSize.isString())
|
||||
{
|
||||
// Only makes sense if stating "player".
|
||||
if (!jsonSize.getAsString().equals(PLAYER)) return null;
|
||||
|
||||
// We use 36 here since it's the size of the player inventory (without armor)
|
||||
size = 36;
|
||||
|
||||
// This is a PlayerInventory
|
||||
ret = new CraftInventoryPlayer(new MCorePlayerInventory());
|
||||
PlayerInventory pret = (PlayerInventory)ret;
|
||||
|
||||
// helmet
|
||||
if (jsonInventory.has(HELMET))
|
||||
{
|
||||
jsonItemStack = jsonInventory.get(HELMET);
|
||||
itemStack = MCore.gson.fromJson(jsonItemStack, ItemStack.class);
|
||||
pret.setHelmet(itemStack);
|
||||
}
|
||||
|
||||
// chestplate
|
||||
if (jsonInventory.has(CHESTPLATE))
|
||||
{
|
||||
jsonItemStack = jsonInventory.get(CHESTPLATE);
|
||||
itemStack = MCore.gson.fromJson(jsonItemStack, ItemStack.class);
|
||||
pret.setChestplate(itemStack);
|
||||
}
|
||||
|
||||
// leggings
|
||||
if (jsonInventory.has(LEGGINGS))
|
||||
{
|
||||
jsonItemStack = jsonInventory.get(LEGGINGS);
|
||||
itemStack = MCore.gson.fromJson(jsonItemStack, ItemStack.class);
|
||||
pret.setLeggings(itemStack);
|
||||
}
|
||||
|
||||
// boots
|
||||
if (jsonInventory.has(BOOTS))
|
||||
{
|
||||
jsonItemStack = jsonInventory.get(BOOTS);
|
||||
itemStack = MCore.gson.fromJson(jsonItemStack, ItemStack.class);
|
||||
pret.setBoots(itemStack);
|
||||
}
|
||||
}
|
||||
else if (jsonSize.isNumber())
|
||||
{
|
||||
// A custom size were specified
|
||||
size = jsonSize.getAsInt();
|
||||
|
||||
// This is a "Custom" Inventory (content only).
|
||||
ret = new CraftInventoryCustom(null, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It must be either string or number
|
||||
return null;
|
||||
}
|
||||
|
||||
// Now process content
|
||||
ItemStack[] itemStacks = new ItemStack[size];
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
// Fetch the jsonItemStack or mark it as empty and continue
|
||||
String stackIdx = String.valueOf(i);
|
||||
JsonElement jsonItemStack = jsonInventory.get(stackIdx);
|
||||
ItemStack itemStack = MCore.gson.fromJson(jsonItemStack, ItemStack.class);
|
||||
jsonItemStack = jsonInventory.get(stackIdx);
|
||||
itemStack = MCore.gson.fromJson(jsonItemStack, ItemStack.class);
|
||||
itemStacks[i] = itemStack;
|
||||
}
|
||||
|
||||
Inventory ret = Bukkit.createInventory(null, size);
|
||||
ret.setContents(itemStacks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
111
src/com/massivecraft/mcore/inventory/MCorePlayerInventory.java
Normal file
111
src/com/massivecraft/mcore/inventory/MCorePlayerInventory.java
Normal file
@ -0,0 +1,111 @@
|
||||
package com.massivecraft.mcore.inventory;
|
||||
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
import net.minecraft.server.v1_5_R2.EntityHuman;
|
||||
import net.minecraft.server.v1_5_R2.ItemStack;
|
||||
import net.minecraft.server.v1_5_R2.PlayerInventory;
|
||||
|
||||
/**
|
||||
* This is an extended version of the NMS.PlayerInventory.
|
||||
* It is extended in such a way that it has a no-arg constructor.
|
||||
* It is mainly used for deserialization of PlayerInventor.
|
||||
*
|
||||
* What is tricky about the NMS.PlayerInventory is that it does hold a link/field to the holder/player.
|
||||
* It is however acceptable for this field "public EntityHuman player" to be null as long as some internal methods are rewritten.
|
||||
*
|
||||
* NPE evasion is achieved by overriding all internal methods using the player field.
|
||||
*
|
||||
* How to update:
|
||||
* Do go to NMS.PlayerInventory and search for references to "player".
|
||||
* As of 1.5.1 these are the references:
|
||||
*
|
||||
* a(EntityHuman) (2 matches)
|
||||
* g(int)
|
||||
* getOwner()
|
||||
* k() (2 matches)
|
||||
* m() (2 matches)
|
||||
* pickup(ItemStack) (2 matches)
|
||||
* PlayerInventory(EntityHuman)
|
||||
*
|
||||
*/
|
||||
public class MCorePlayerInventory extends PlayerInventory
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
public MCorePlayerInventory()
|
||||
{
|
||||
super(null);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// NPE EVASION
|
||||
// -------------------------------------------- //
|
||||
|
||||
// Is the entityhuman within reach?
|
||||
// Can it edit the inventory content?
|
||||
// According to the source code design entityhuman is never null. However we go for safety first.
|
||||
@Override
|
||||
public boolean a(EntityHuman entityhuman)
|
||||
{
|
||||
// Null cases
|
||||
if (entityhuman == null) return true;
|
||||
if (this.player == null) return true;
|
||||
|
||||
// Other people can reach at any time
|
||||
if (!this.player.equals(entityhuman)) return true;
|
||||
|
||||
return super.a(entityhuman);
|
||||
}
|
||||
|
||||
// This method handles damage dealt to the armor inside the inventory.
|
||||
// We simply ignore damage if there is no player.
|
||||
@Override
|
||||
public void g(int arg0)
|
||||
{
|
||||
if (this.player == null) return;
|
||||
|
||||
super.g(arg0);
|
||||
}
|
||||
|
||||
// If the player is null there is no owner.
|
||||
@Override
|
||||
public InventoryHolder getOwner()
|
||||
{
|
||||
if (this.player == null) return null;
|
||||
|
||||
return super.getOwner();
|
||||
}
|
||||
|
||||
// This method looks like some sort of recurring tick to the items but not inventories.
|
||||
// Let's just ignore it if the player is elsewhere.
|
||||
@Override
|
||||
public void k()
|
||||
{
|
||||
if (this.player == null) return;
|
||||
|
||||
super.k();
|
||||
}
|
||||
|
||||
// Called when the player dies and no items should be kept.
|
||||
// This will cause the player to drop all the items.
|
||||
@Override
|
||||
public void m()
|
||||
{
|
||||
if (this.player == null) return;
|
||||
|
||||
super.m();
|
||||
}
|
||||
|
||||
// Pickup the item. Return if the pickup was successful or not.
|
||||
@Override
|
||||
public boolean pickup(ItemStack arg0)
|
||||
{
|
||||
if (this.player == null) return false;
|
||||
|
||||
return super.pickup(arg0);
|
||||
}
|
||||
|
||||
}
|
@ -2,14 +2,18 @@ package com.massivecraft.mcore.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftInventoryCustom;
|
||||
import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftInventoryPlayer;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.inventory.InventoryType.SlotType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
import com.massivecraft.mcore.inventory.MCorePlayerInventory;
|
||||
|
||||
public class InventoryUtil
|
||||
{
|
||||
@ -115,16 +119,38 @@ public class InventoryUtil
|
||||
public static boolean isEmpty(Inventory inv)
|
||||
{
|
||||
if (inv == null) return true;
|
||||
for (ItemStack stack : inv.getContents())
|
||||
|
||||
for (ItemStack itemStack : inv.getContents())
|
||||
{
|
||||
if (stack == null) continue;
|
||||
if (stack.getAmount() == 0) continue;
|
||||
if (stack.getTypeId() == 0) continue;
|
||||
return false;
|
||||
if (isSomething(itemStack)) return false;
|
||||
}
|
||||
|
||||
if (inv instanceof PlayerInventory)
|
||||
{
|
||||
PlayerInventory pinv = (PlayerInventory)inv;
|
||||
|
||||
if (isSomething(pinv.getHelmet())) return false;
|
||||
if (isSomething(pinv.getChestplate())) return false;
|
||||
if (isSomething(pinv.getLeggings())) return false;
|
||||
if (isSomething(pinv.getBoots())) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isNothing(ItemStack itemStack)
|
||||
{
|
||||
if (itemStack == null) return true;
|
||||
if (itemStack.getAmount() == 0) return true;
|
||||
if (itemStack.getTypeId() == 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSomething(ItemStack itemStack)
|
||||
{
|
||||
return !isNothing(itemStack);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CLONE ITEMSTACKS/INVENTORY
|
||||
// -------------------------------------------- //
|
||||
@ -141,18 +167,35 @@ public class InventoryUtil
|
||||
return ret;
|
||||
}
|
||||
|
||||
// NOTE: This method does not handle the armor part of player inventories.
|
||||
// That is expected behavior for now.
|
||||
public static Inventory cloneInventory(Inventory inventory)
|
||||
{
|
||||
if (inventory == null) return null;
|
||||
|
||||
InventoryHolder holder = inventory.getHolder();
|
||||
int size = inventory.getSize();
|
||||
String title = inventory.getTitle();
|
||||
ItemStack[] contents = cloneItemStacks(inventory.getContents());
|
||||
Inventory ret = null;
|
||||
|
||||
Inventory ret = Bukkit.createInventory(holder, size, title);
|
||||
int size = inventory.getSize();
|
||||
InventoryHolder holder = inventory.getHolder();
|
||||
String title = inventory.getTitle();
|
||||
|
||||
if (inventory instanceof PlayerInventory)
|
||||
{
|
||||
MCorePlayerInventory nmsret = new MCorePlayerInventory();
|
||||
CraftInventoryPlayer pret = new CraftInventoryPlayer(nmsret);
|
||||
ret = pret;
|
||||
|
||||
PlayerInventory pinventory = (PlayerInventory)inventory;
|
||||
|
||||
pret.setHelmet(pinventory.getHelmet() == null ? null : new ItemStack(pinventory.getHelmet()));
|
||||
pret.setChestplate(pinventory.getChestplate() == null ? null : new ItemStack(pinventory.getChestplate()));
|
||||
pret.setLeggings(pinventory.getLeggings() == null ? null : new ItemStack(pinventory.getLeggings()));
|
||||
pret.setBoots(pinventory.getBoots() == null ? null : new ItemStack(pinventory.getBoots()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = new CraftInventoryCustom(holder, size, title);
|
||||
}
|
||||
|
||||
ItemStack[] contents = cloneItemStacks(inventory.getContents());
|
||||
ret.setContents(contents);
|
||||
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user