/*
* Copyright (c) 2015 NOVA, All rights reserved.
* This library is free software, licensed under GNU Lesser General Public License version 3
*
* This file is part of NOVA.
*
* NOVA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NOVA. If not, see <http://www.gnu.org/licenses/>.
*/
package nova.core.wrapper.mc.forge.v18.wrapper.recipes.backward;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import nova.core.entity.component.Player;
import nova.core.recipes.crafting.CraftingGrid;
import nova.core.wrapper.mc.forge.v18.util.ReflectionUtil;
import nova.core.wrapper.mc.forge.v18.util.WrapUtility;
import nova.core.wrapper.mc.forge.v18.wrapper.item.ItemConverter;
import java.util.List;
import java.util.Optional;
/**
* @author Stan Hebben
*/
public class MCCraftingGrid implements CraftingGrid {
private static final ThreadLocal<MCCraftingGrid> cache = new ThreadLocal<MCCraftingGrid>();
private static final ThreadLocal<MCCraftingGrid> cache2 = new ThreadLocal<MCCraftingGrid>();
private final IInventory inventory;
private final Optional<Player> player;
private final EntityPlayer playerOrig;
private int width;
private int height;
private nova.core.item.Item[] items;
private ItemStack[] original;
private int itemCount;
private MCCraftingGrid(InventoryCrafting inventory) {
this.inventory = inventory;
width = height = (int) Math.sqrt(inventory.getSizeInventory());
items = new nova.core.item.Item[width * height];
original = new ItemStack[items.length];
itemCount = 0;
update();
Container container = ReflectionUtil.getCraftingContainer(inventory);
if (container != null) {
@SuppressWarnings("unchecked")
List<Slot> slots = container.inventorySlots;
EntityPlayer playerOrig = null;
Optional<Player> player = Optional.empty();
for (Slot slot : slots) {
if (slot instanceof SlotCrafting) {
playerOrig = ReflectionUtil.getCraftingSlotPlayer((SlotCrafting) slot);
player = WrapUtility.getNovaPlayer(playerOrig);
if (player.isPresent()) {
break;
}
}
}
this.playerOrig = playerOrig;
this.player = player;
} else {
playerOrig = null;
player = Optional.empty();
}
}
private MCCraftingGrid(IInventory inventory, EntityPlayer player) {
this.inventory = inventory;
width = height = (int) Math.sqrt(inventory.getSizeInventory());
items = new nova.core.item.Item[width * height];
original = new ItemStack[items.length];
itemCount = 0;
update();
playerOrig = player;
this.player = WrapUtility.getNovaPlayer(player);
}
public static MCCraftingGrid get(InventoryCrafting inventory) {
if (cache.get() == null || cache.get().inventory != inventory) {
MCCraftingGrid result = new MCCraftingGrid(inventory);
cache.set(result);
return result;
} else {
MCCraftingGrid result = cache.get();
result.update();
return result;
}
}
public static MCCraftingGrid get(IInventory inventory, EntityPlayer player) {
if (cache2.get() == null || cache2.get().inventory != inventory || cache2.get().playerOrig != player) {
MCCraftingGrid result = new MCCraftingGrid(inventory, player);
cache2.set(result);
return result;
} else {
MCCraftingGrid result = cache2.get();
result.update();
return result;
}
}
private void update() {
if (inventory.getSizeInventory() != original.length) {
width = height = (int) Math.sqrt(inventory.getSizeInventory());
items = new nova.core.item.Item[inventory.getSizeInventory()];
original = new ItemStack[items.length];
itemCount = 0;
}
for (int i = 0; i < inventory.getSizeInventory(); i++) {
if (changed(i)) {
//Game.logger().info("Slot {} changed", i);
original[i] = inventory.getStackInSlot(i);
if (inventory.getStackInSlot(i) != null) {
if (items[i] == null) {
itemCount++;
}
items[i] = ItemConverter.instance().toNova(original[i]);
} else {
if (items[i] != null) {
itemCount--;
}
items[i] = null;
}
}
}
//Game.logger().info("Num stack count: {}", itemCount);
}
@Override
public Optional<Player> getPlayer() {
return player;
}
@Override
public int size() {
return width * height;
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
@Override
public int countFilledStacks() {
return itemCount;
}
@Override
public Optional<nova.core.item.Item> getCrafting(int i) {
return Optional.ofNullable(items[i]);
}
@Override
public Optional<nova.core.item.Item> getCrafting(int x, int y) {
return Optional.ofNullable(items[y * width + x]);
}
@Override
public boolean setCrafting(int x, int y, Optional<nova.core.item.Item> item) {
//Game.logger().info("setCrafting({}, {}) {}", x, y, item);
int ix = y * width + x;
if (item.isPresent()) {
if (!item.get().equals(items[ix])) {
inventory.setInventorySlotContents(ix, ItemConverter.instance().toNative(item.get()));
if (items[ix] == null) {
itemCount++;
}
items[ix] = item.get();
}
} else {
itemCount--;
inventory.setInventorySlotContents(ix, null);
items[ix] = null;
}
return true;
}
@Override
public boolean setCrafting(int i, Optional<nova.core.item.Item> item) {
//Game.logger().info("setCrafting({}) {}", i, item);
if (item.isPresent()) {
if (items[i] == null) {
itemCount++;
}
inventory.setInventorySlotContents(i, ItemConverter.instance().toNative(item.get()));
items[i] = item.get();
} else {
if (items[i] == null) {
return true;
}
itemCount--;
inventory.setInventorySlotContents(i, null);
items[i] = null;
}
return true;
}
@Override
public void giveBack(nova.core.item.Item item) {
if (playerOrig != null) {
playerOrig.inventory.addItemStackToInventory(ItemConverter.instance().toNative(item));
}
}
@Override
public String getTopology() {
return CraftingGrid.TOPOLOGY_SQUARE;
}
@Override
public String getType() {
return CraftingGrid.TYPE_CRAFTING;
}
private boolean changed(int i) {
if (original[i] != inventory.getStackInSlot(i)) {
return true;
}
if (original[i] != null && items[i].count() != original[i].stackSize) {
return true;
}
return false;
}
}