/*******************************************************************************
* Copyright (C) 2014 Travis Ralston (turt2live)
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.turt2live.antishare.io.flatfile;
import com.turt2live.antishare.ASGameMode;
import com.turt2live.antishare.engine.Engine;
import com.turt2live.antishare.io.generics.GenericInventoryManager;
import com.turt2live.antishare.io.memory.MemoryInventoryManager;
import com.turt2live.antishare.object.AInventory;
import com.turt2live.antishare.object.AWorld;
import com.turt2live.antishare.utils.NBTItem;
import com.turt2live.lib.items.AbstractedItem;
import org.jnbt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
/**
* Represents an inventory manager that saves to disk
*
* @author turt2live
*/
// TODO: Unit test
public class FileInventoryManager extends GenericInventoryManager {
private File folder;
/**
* Creates a new inventory manager
*
* @param folder the folder to store files in. Cannot be null and will be created if it
* does not exist. If the folder does exist, it must be a folder and not
* any other type of file system object.
*/
public FileInventoryManager(File folder) {
if (folder == null) throw new IllegalArgumentException();
if (folder.exists() && !folder.isDirectory()) throw new IllegalArgumentException("Folder must be a folder");
this.folder = folder;
if (!folder.exists()) folder.mkdirs();
}
@Override
protected void saveInventories(Map<UUID, List<AInventory>> inventories) {
for (UUID player : inventories.keySet()) {
try {
List<AInventory> playerInventories = inventories.get(player);
Tag tag = createTag(playerInventories);
Map<String, Tag> tags = new HashMap<>();
tags.put("inventory", tag);
CompoundTag compoundTag = new CompoundTag(player.toString(), tags);
File fileName = new File(folder, player.toString() + ".dat");
NBTOutputStream stream = new NBTOutputStream(new FileOutputStream(fileName, false));
stream.writeTag(compoundTag);
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public List<AInventory> getInventories(UUID player) {
List<AInventory> inventories = getInventoriesFor(player);
if (!inventories.isEmpty()) return inventories;
File expected = new File(folder, player.toString() + ".dat");
if (expected.exists()) {
try {
NBTInputStream inputStream = new NBTInputStream(new FileInputStream(expected));
Tag baseTag = inputStream.readTag();
inputStream.close();
if (baseTag instanceof CompoundTag) {
CompoundTag root = (CompoundTag) baseTag;
ListTag inventoryList = (ListTag) root.getValue().get("inventories");
for (Tag listItem : inventoryList.getValue()) {
AInventory inventory = createInventory(((CompoundTag) listItem).getValue());
inventories.add(inventory);
}
} else throw new RuntimeException("Root tag is not a valid tag");
} catch (IOException e) {
e.printStackTrace();
}
}
return inventories;
}
@Override
protected AInventory createEmptyInventory(UUID player, ASGameMode gamemode, AWorld world) {
return new MemoryInventoryManager.MemoryInventory(world, gamemode);
}
private Tag createTag(List<AInventory> inventories) {
List<Tag> tags = new ArrayList<>();
for (AInventory inventory : inventories) {
tags.add(createTag(inventory));
}
return new ListTag("inventories", CompoundTag.class, tags);
}
private Tag createTag(AInventory inventory) {
Map<String, Tag> tags = new HashMap<>();
tags.put("world", new StringTag("world", inventory.getWorld().getName()));
tags.put("gamemode", new StringTag("gamemode", inventory.getGameMode().name()));
Map<String, Tag> items = new HashMap<>();
for (Map.Entry<Integer, AbstractedItem> content : inventory.getContents().entrySet()) {
int slot = content.getKey();
AbstractedItem item = content.getValue();
Tag itemTag = new NBTItem(item).getTag("slot " + slot);
items.put("item " + slot, itemTag);
}
tags.put("items", new CompoundTag("items", items));
return new CompoundTag("inventory", tags);
}
private AInventory createInventory(Map<String, Tag> tags) {
ASGameMode gamemode = ASGameMode.valueOf(((StringTag) tags.get("gamemode")).getValue());
String world = ((StringTag) tags.get("world")).getValue();
AWorld aWorld = Engine.getInstance().getWorld(world);
AInventory inventory = new MemoryInventoryManager.MemoryInventory(aWorld, gamemode);
// Start reading items
CompoundTag items = (CompoundTag) tags.get("items");
Map<Integer, AbstractedItem> itemMap = new HashMap<>();
for (Tag itemTag : items.getValue().values()) {
int slot = Integer.parseInt(itemTag.getName().substring("slot ".length()));
AbstractedItem item = NBTItem.reconstructItem(itemTag);
itemMap.put(slot, item);
}
inventory.setContents(itemMap);
return inventory;
}
}