A lot of changes. Sorry, didn't keep track.
The next things to do are implementing the tile entity and getting the player's items upon death.master
parent
a618f200ee
commit
b1c80d7bde
|
@ -1,15 +1,18 @@
|
|||
package lostcave.deathchests;
|
||||
|
||||
import lostcave.deathchests.block.BlockDeathChest;
|
||||
import lostcave.deathchests.item.Obituary;
|
||||
import lostcave.deathchests.item.ItemObituary;
|
||||
import lostcave.deathchests.util.Config;
|
||||
import lostcave.deathchests.util.DeathChestStorage;
|
||||
import lostcave.deathchests.util.Debug;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.Mod;
|
||||
import cpw.mods.fml.common.Mod.EventHandler;
|
||||
|
@ -17,18 +20,22 @@ import cpw.mods.fml.common.event.FMLConstructionEvent;
|
|||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerAboutToStartEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerStoppedEvent;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
|
||||
@Mod(modid = DeathChests.MODID, version = DeathChests.VERSION)
|
||||
public class DeathChests {
|
||||
public static final String MODID = "deathchests";
|
||||
public static final String VERSION = "0-SNAPSHOT";
|
||||
|
||||
private static File worldSaveLocation;
|
||||
|
||||
@EventHandler
|
||||
public void init(FMLConstructionEvent event) {
|
||||
Debug.out("Received FMLConstructionEvent");
|
||||
Config.configDir = Loader.instance().getConfigDir();
|
||||
Debug.out("Config file is: " + Config.configDir.toString() + System.getProperty("file.separator") + Config.configFileName);
|
||||
Debug.out("Config file is: " + Config.configDir.toString() + System.getProperty("file.separator") + Config.config_file_name);
|
||||
|
||||
Config.loadConfig();
|
||||
Debug.out("Loaded config.");
|
||||
|
@ -49,10 +56,11 @@ public class DeathChests {
|
|||
Debug.out("Received FMLInitializationEvent");
|
||||
|
||||
GameRegistry.registerBlock(BlockDeathChest.getInstance(), "death_chest");
|
||||
GameRegistry.registerItem(Obituary.getInstance(), "obituary");
|
||||
GameRegistry.registerItem(ItemObituary.getInstance(), "obituary");
|
||||
Debug.out("Registered block and item.");
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(new EventHook());
|
||||
FMLCommonHandler.instance().bus().register(new EventHook());
|
||||
Debug.out("Registered event hook.");
|
||||
}
|
||||
|
||||
|
@ -60,5 +68,18 @@ public class DeathChests {
|
|||
public void init(FMLPostInitializationEvent event) {
|
||||
Debug.out("Received FMLPostInitializationEvent");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void init(FMLServerAboutToStartEvent event) {
|
||||
Debug.out("Received FMLServerAboutToStartEvent");
|
||||
//TODO: get world save location
|
||||
worldSaveLocation = DimensionManager.getCurrentSaveRootDirectory();
|
||||
DeathChestStorage.load(worldSaveLocation);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void init(FMLServerStoppedEvent event) {
|
||||
DeathChestStorage.save(worldSaveLocation);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
package lostcave.deathchests;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.PlayerEvent;
|
||||
import lostcave.deathchests.block.BlockDeathChest;
|
||||
import lostcave.deathchests.item.ItemObituary;
|
||||
import lostcave.deathchests.util.Config;
|
||||
import lostcave.deathchests.util.DeathChestStorage;
|
||||
import lostcave.deathchests.util.Debug;
|
||||
import net.minecraft.block.BlockAir;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.entity.EntityEvent.EntityConstructing;
|
||||
import net.minecraftforge.event.entity.player.PlayerDropsEvent;
|
||||
|
||||
public class EventHook {
|
||||
|
||||
@SubscribeEvent
|
||||
public void PlayerDropsEvent(net.minecraftforge.event.entity.player.PlayerDropsEvent event) {
|
||||
public void death(PlayerDropsEvent event) {
|
||||
// This is kinda misleadingly named.
|
||||
// The event fires only when a player entity produces drops (due to death),
|
||||
// not when a player drops an item.
|
||||
|
@ -29,9 +35,9 @@ public class EventHook {
|
|||
if (y < 0) y = 0;
|
||||
if (y > 255) y = 255;
|
||||
|
||||
boolean foundSuitableBlock = false;
|
||||
int[] suitableBlock = new int[3];
|
||||
World world = event.entity.worldObj;
|
||||
boolean foundSuitableBlock = false;
|
||||
int[] suitableBlock = new int[4]; // x y z dimension
|
||||
// search for air block by checking the outside walls of an expanding cube
|
||||
if (world.getBlock(x, y, z) instanceof BlockAir) {
|
||||
suitableBlock[0] = x;
|
||||
|
@ -151,16 +157,46 @@ public class EventHook {
|
|||
Debug.out("Suitable block X: " + Integer.toString(suitableBlock[0]));
|
||||
Debug.out("Suitable block Y: " + Integer.toString(suitableBlock[1]));
|
||||
Debug.out("Suitable block Z: " + Integer.toString(suitableBlock[2]));
|
||||
//TODO: place death chest
|
||||
|
||||
Debug.out("Dimension: " + Integer.toString(event.entityPlayer.dimension));
|
||||
suitableBlock[3] = event.entityPlayer.dimension;
|
||||
|
||||
world.setBlock(suitableBlock[0], suitableBlock[1], suitableBlock[2], BlockDeathChest.getInstance());
|
||||
//TODO: Get the player's items and put them in the death chest
|
||||
|
||||
String uuid = event.entityPlayer.getGameProfile().getId().toString();
|
||||
Debug.out(uuid);
|
||||
DeathChestStorage.addNewDeathChestLocation(uuid, suitableBlock);
|
||||
|
||||
event.setCanceled(true);
|
||||
Debug.out("Canceled PlayerDropEvent");
|
||||
//TODO: Tell the player about death chest location upon respawn
|
||||
} else {
|
||||
Debug.out("No suitable location could be found.");
|
||||
//TODO: tell player that a death chest couldn’t be placed and that the items have been dropped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void respawn(PlayerEvent.PlayerRespawnEvent event) {
|
||||
Debug.out(event.player.getDisplayName() + " respawned");
|
||||
|
||||
String uuid = event.player.getGameProfile().getId().toString();
|
||||
Debug.out("UUID: " + uuid);
|
||||
|
||||
//TODO: check for stored chest location
|
||||
if (DeathChestStorage.hasNewDeathChestLocation(uuid)) {
|
||||
int[] chestLocation = DeathChestStorage.popNewDeathChestLocation(uuid);
|
||||
Debug.out("Chest location X: " + Integer.toString(chestLocation[0]));
|
||||
Debug.out("Chest location Y: " + Integer.toString(chestLocation[1]));
|
||||
Debug.out("Chest location Z: " + Integer.toString(chestLocation[2]));
|
||||
Debug.out("Chest location dimension: " + Integer.toString(chestLocation[3]));
|
||||
|
||||
//TODO: NBT data
|
||||
event.player.inventory.addItemStackToInventory(new ItemStack(ItemObituary.getInstance()));
|
||||
} else {
|
||||
Debug.out("No death chest location was stored.");
|
||||
//TODO: tell player that a death chest couldn’t be placed and that the items have been dropped
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
package lostcave.deathchests.block;
|
||||
|
||||
import net.minecraft.block.BlockChest;
|
||||
import java.util.Random;
|
||||
|
||||
public class BlockDeathChest extends BlockChest {
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockEnderChest;
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.inventory.InventoryEnderChest;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityEnderChest;
|
||||
import net.minecraft.world.Explosion;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BlockDeathChest extends BlockEnderChest {
|
||||
|
||||
private static final BlockDeathChest instance = new BlockDeathChest();
|
||||
|
||||
|
@ -11,13 +25,89 @@ public class BlockDeathChest extends BlockChest {
|
|||
}
|
||||
|
||||
private BlockDeathChest() {
|
||||
super(0);
|
||||
super();
|
||||
this.setBlockName("death_chest");
|
||||
this.disableStats();
|
||||
this.setBlockUnbreakable();
|
||||
// same value as bedrock
|
||||
this.setResistance(6000000.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canSilkHarvest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDropFromExplosion(Explosion p_149659_1_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getItemDropped(int p_149650_1_, Random p_149650_2_, int p_149650_3_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called upon block activation (right click on the block.)
|
||||
*/
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int p_149727_6_, float p_149727_7_, float p_149727_8_, float p_149727_9_) {
|
||||
if (world.isRemote) return true;
|
||||
|
||||
TileDeathChest tiledeathchest = (TileDeathChest) world.getTileEntity(x, y, z);
|
||||
if (tiledeathchest != null) {
|
||||
//TODO: check if appropriate player
|
||||
//TODO: drop items
|
||||
return true;
|
||||
} else return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player hits the block. Args: world, x, y, z, player
|
||||
*/
|
||||
@Override
|
||||
public void onBlockClicked(World p_149699_1_, int p_149699_2_, int p_149699_3_, int p_149699_4_, EntityPlayer p_149699_5_) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of a block's tile entity class. Called on placing the
|
||||
* block.
|
||||
*/
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World p_149915_1_, int p_149915_2_) {
|
||||
return new TileDeathChest();
|
||||
}
|
||||
|
||||
/**
|
||||
* A randomly called display update to be able to add particles or other items
|
||||
* for display
|
||||
* <br />
|
||||
* <br/>
|
||||
* This is here to disable the particles that would otherwise be emitted
|
||||
*/
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void randomDisplayTick(World p_149734_1_, int p_149734_2_, int p_149734_3_, int p_149734_4_, Random p_149734_5_) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void registerBlockIcons(IIconRegister p_149651_1_) {
|
||||
this.blockIcon = p_149651_1_.registerIcon("cobblestone");
|
||||
}
|
||||
|
||||
public static class TileDeathChest extends TileEntity {
|
||||
//TODO
|
||||
}
|
||||
|
||||
//TODO: Make death chest unobtanium (don’t drop the chest when broken)
|
||||
//TODO: Change capacity somehow?
|
||||
//TODO: Custom texture? (optional)
|
||||
//TODO: add chest inventory
|
||||
//TODO: drop chest contents
|
||||
//TODO: Remove chest when empty
|
||||
//TODO: make unable to break by explosion (configurable?)
|
||||
|
||||
//TODO: Make it so items can only be taken out of the chest?
|
||||
// Custom GUI? Maybe remove GUI altogether and have it drop the items when broken?
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package lostcave.deathchests.item;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
|
||||
public class ItemObituary extends Item {
|
||||
|
||||
private static final ItemObituary instance = new ItemObituary();
|
||||
|
||||
public static ItemObituary getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ItemObituary() {
|
||||
this.setUnlocalizedName("obituary");
|
||||
this.setTextureName("paper");
|
||||
}
|
||||
|
||||
//TODO: NBT data
|
||||
//TODO: right click action
|
||||
//TODO: item description
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package lostcave.deathchests.item;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
|
||||
public class Obituary extends Item {
|
||||
|
||||
private static final Obituary instance = new Obituary();
|
||||
|
||||
public static Obituary getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Obituary() {
|
||||
this.setUnlocalizedName("obituary");
|
||||
this.setTextureName("paper");
|
||||
}
|
||||
}
|
|
@ -9,28 +9,28 @@ import cpw.mods.fml.common.FMLCommonHandler;
|
|||
|
||||
public class Config {
|
||||
|
||||
public static final String configFileName = "deathchests.txt";
|
||||
public static final String config_file_name = "deathchests.txt";
|
||||
public static File configDir = null;
|
||||
|
||||
public static boolean debug = true;
|
||||
public static boolean fixLog4J = true;
|
||||
public static int maxDistance = 50;
|
||||
|
||||
private static final String configHeader = "# The format of this file is strictly `option=value` (no spaces).\n# Lines starting with # and empty lines are ignored.\n";
|
||||
private static final String config_header = "# The format of this file is strictly `option=value` (no spaces).\n# Lines starting with # and empty lines are ignored.\n";
|
||||
|
||||
public static void writeConfig() {
|
||||
String configOut = configHeader;
|
||||
String configOut = config_header;
|
||||
configOut += "\n\n# Enable debug output?\n";
|
||||
configOut += "debug=";
|
||||
configOut += debug ? "true" : "false";
|
||||
configOut += "\n\n# Enable Log4Shell counter measures?\n";
|
||||
configOut += "\n\n# Enable Log4Shell counter measures? (this feature is currently not implemented)\n";
|
||||
configOut += "fixLog4J=";
|
||||
configOut += fixLog4J ? "true" : "false";
|
||||
configOut += "\n\n# The maximum search radius for finding a suitable location for placing the death chest\n";
|
||||
configOut += "maxDistance=";
|
||||
configOut += Integer.toString(maxDistance);
|
||||
|
||||
File configFile = new File(configDir, configFileName);
|
||||
|
||||
File configFile = new File(configDir, config_file_name);
|
||||
try {
|
||||
Files.write(configFile.toPath(), configOut.getBytes());
|
||||
} catch (IOException e) {
|
||||
|
@ -42,7 +42,7 @@ public class Config {
|
|||
|
||||
public static void loadConfig() {
|
||||
List<String> configData = null;
|
||||
File configFile = new File(configDir, configFileName);
|
||||
File configFile = new File(configDir, config_file_name);
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
configData = Files.readAllLines(configFile.toPath());
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package lostcave.deathchests.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.nbt.CompressedStreamTools;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public class DeathChestStorage {
|
||||
|
||||
private static LookUpTable<int[]> deathChestLocations;
|
||||
public static final String death_chests_dat_file = "deathchests.dat";
|
||||
|
||||
/**
|
||||
* When a new death chest has been placed, add it to the LUT. This does not
|
||||
* place the chest itself.
|
||||
*
|
||||
* @param uuid
|
||||
* @param location
|
||||
*/
|
||||
public static void addNewDeathChestLocation(String uuid, int[] location) {
|
||||
deathChestLocations.add(uuid, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location of a new death chest for a given player and remove it from
|
||||
* the LUT of new death chests.
|
||||
*
|
||||
* @param uuid
|
||||
* @return the location {x, y, z, dimension}
|
||||
*/
|
||||
public static int[] popNewDeathChestLocation(String uuid) {
|
||||
int[] location = deathChestLocations.get(uuid);
|
||||
deathChestLocations.remove(uuid);
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given player has a new death chest that no obituary item has been
|
||||
* created for.
|
||||
* This is used in respawn events.
|
||||
*
|
||||
* @param uuid
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasNewDeathChestLocation(String uuid) {
|
||||
return deathChestLocations.get(uuid) != null;
|
||||
}
|
||||
|
||||
public static void save(File worldSaveLocation) {
|
||||
Debug.out("Putting death chest LUT into a compound");
|
||||
NBTTagCompound compound = new NBTTagCompound();
|
||||
for (int i = 0; i < deathChestLocations.storedElements(); i++) {
|
||||
String uuid = deathChestLocations.getKey(i);
|
||||
compound.setIntArray(uuid, deathChestLocations.get(uuid));
|
||||
}
|
||||
|
||||
File file = new File(worldSaveLocation, death_chests_dat_file);
|
||||
Debug.out("Saving to file: " + file.toPath().toAbsolutePath().toString());
|
||||
try {
|
||||
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(file));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void load(File worldSaveLocation) {
|
||||
File file = new File(worldSaveLocation, death_chests_dat_file);
|
||||
Debug.out("Loading death chest LUT from file: " + file.toPath().toAbsolutePath().toString());
|
||||
|
||||
// reset the LUT in case one still exists from quitting to main menu and loading a world
|
||||
deathChestLocations = new LookUpTable<int[]>();
|
||||
|
||||
if (file.exists()) {
|
||||
try {
|
||||
NBTTagCompound compound = CompressedStreamTools.readCompressed(new FileInputStream(file));
|
||||
// func_150296_c() should be named getKeySet() but didn’t deobfuscate properly
|
||||
// This might be a problem with Forge, or it might be a problem with my Frankenstein setup.
|
||||
for (String uuid : (Set<String>) compound.func_150296_c()) {
|
||||
deathChestLocations.add(uuid, compound.getIntArray(uuid));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Debug.out("The following entries have been loaded:");
|
||||
if (Config.debug) {
|
||||
for (int i = 0; i < deathChestLocations.storedElements(); i++) {
|
||||
String uuid = deathChestLocations.getKey(i);
|
||||
int[] location = deathChestLocations.get(uuid);
|
||||
Debug.out(uuid + " - x=" + Integer.toString(location[0]) + " y=" + Integer.toString(location[1]) + " z=" + Integer.toString(location[2]) + " dim=" + Integer.toString(location[3]));
|
||||
}
|
||||
}
|
||||
Debug.out("--");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
package lostcave.deathchests.util;
|
||||
|
||||
// The code below is licensed under the WTFPL.
|
||||
|
||||
// Here is a copy for your convenience:
|
||||
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is a naive implementation of a look up table. Store and retrieve key
|
||||
* value pairs.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* I had no reason to implement this other than not wanting to go down a rabbit
|
||||
* hole of Java types rather than just using simple functionality.
|
||||
* </p>
|
||||
*
|
||||
* @author BodgeMaster
|
||||
*
|
||||
* @param <T> The type to be stored
|
||||
*/
|
||||
public class LookUpTable<T> {
|
||||
private List<T> values;
|
||||
private String[] keys;
|
||||
private boolean[] usedSlots;
|
||||
private int storedElements;
|
||||
|
||||
public LookUpTable() {
|
||||
this.values = new ArrayList<T>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
values.add(null);
|
||||
}
|
||||
this.keys = new String[10];
|
||||
this.usedSlots = new boolean[] { false, false, false, false, false, false, false, false, false, false };
|
||||
this.storedElements = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @throws DuplicateKeyException
|
||||
*/
|
||||
public void add(String key, T value) {
|
||||
// duplicate check
|
||||
for (int i = 0; i < this.keys.length; i++) {
|
||||
if (usedSlots[i]) {
|
||||
if (keys[i].equals(key)) throw new DuplicateKeyException(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Make bigger arrays when running out of space
|
||||
if (this.storedElements == this.keys.length) {
|
||||
String[] keys = this.keys;
|
||||
boolean[] usedSlots = this.usedSlots;
|
||||
this.keys = new String[keys.length + 10];
|
||||
this.usedSlots = new boolean[usedSlots.length + 10];
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
this.keys[i] = keys[i];
|
||||
this.usedSlots[i] = usedSlots[i];
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// ensure capacity
|
||||
this.values.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Find next unused slot
|
||||
int unusedSlot = 0;
|
||||
for (int i = 0; i < this.usedSlots.length; i++) {
|
||||
if (!this.usedSlots[i]) {
|
||||
unusedSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.keys[unusedSlot] = key;
|
||||
this.values.set(unusedSlot, value);
|
||||
usedSlots[unusedSlot] = true;
|
||||
this.storedElements++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value by key
|
||||
*
|
||||
* @param key
|
||||
* @return value (null if key not found)
|
||||
*/
|
||||
public T get(String key) {
|
||||
for (int i = 0; i < usedSlots.length; i++) {
|
||||
if (usedSlots[i]) {
|
||||
if (keys[i].equals(key)) return values.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void set(String key, T value) {
|
||||
for (int i = 0; i < usedSlots.length; i++) {
|
||||
if (usedSlots[i]) {
|
||||
if (keys[i].equals(key)) values.set(i, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Remove an element from the LUT
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This function marks the position of key as unused. If you actually want to
|
||||
* ensure that the object is removed from the LUT, use
|
||||
* {@link LookUpTable#fullRemove(String)} instead.
|
||||
* </p>
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public void remove(String key) {
|
||||
for (int i = 0; i < usedSlots.length; i++) {
|
||||
if (usedSlots[i]) {
|
||||
if (keys[i].equals(key)) usedSlots[i] = false;
|
||||
}
|
||||
}
|
||||
storedElements--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element from the LUT by actually setting it to null.
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public void fullRemove(String key) {
|
||||
for (int i = 0; i < usedSlots.length; i++) {
|
||||
if (usedSlots[i]) {
|
||||
if (keys[i].equals(key)) {
|
||||
values.set(i, null);
|
||||
usedSlots[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
storedElements--;
|
||||
}
|
||||
|
||||
public int storedElements() {
|
||||
return this.storedElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a key by its position in the LUT. Unused slots are ignored and do not
|
||||
* count towards the position.
|
||||
*
|
||||
* @param index
|
||||
* @return key
|
||||
*/
|
||||
public String getKey(int index) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < index) {
|
||||
j++;
|
||||
if (usedSlots[j]) i++;
|
||||
}
|
||||
return keys[j];
|
||||
}
|
||||
|
||||
public static class DuplicateKeyException extends RuntimeException {
|
||||
public DuplicateKeyException() {
|
||||
super("Tried adding an element with a duplicte key to a LookUpTable.");
|
||||
}
|
||||
|
||||
public DuplicateKeyException(String key) {
|
||||
super("Tried adding an element with a duplicte key to a LookUpTable: " + key);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import lostcave.deathchests.util.LookUpTable;
|
||||
import lostcave.deathchests.util.LookUpTable.DuplicateKeyException;
|
||||
|
||||
public class TestLUT {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Testing LookUpTable...");
|
||||
|
||||
LookUpTable<Integer> table = new LookUpTable<>();
|
||||
|
||||
table.add("one", 1);
|
||||
table.add("two", 2);
|
||||
table.add("three", 3);
|
||||
|
||||
if (table.get("one") != 1 || table.get("two") != 2 || table.get("three") != 3) System.err.println("Failed add test.");
|
||||
else System.out.println("Passed add test.");
|
||||
|
||||
if (table.getKey(1).equals("two")) System.out.println("Passed getKey test (1/2).");
|
||||
else System.err.println("Failed getKey test (1/2).");
|
||||
|
||||
table.remove("two");
|
||||
if (table.get("two") == null) System.out.println("Passed remove test.");
|
||||
else System.err.println("Failed remove test");
|
||||
|
||||
if (table.getKey(1).equals("three")) System.out.println("Passed getKey test (2/2).");
|
||||
else System.err.println("Failed getKey test (2/2): " + table.getKey(1));
|
||||
|
||||
if (table.storedElements()==2) System.out.println("Passes storedElements test.");
|
||||
else System.out.println("Failed storedElements test.");
|
||||
|
||||
table.set("three", 33);
|
||||
if (table.get("three")==33) System.out.println("Passed set test.");
|
||||
else System.out.println("Failed set test.");
|
||||
|
||||
try {
|
||||
table.add("three", 2);
|
||||
System.err.println("Failed duplicate key test.");
|
||||
} catch (DuplicateKeyException e) {
|
||||
System.out.println("Passed duplicate key test.");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue