diff --git a/build.gradle b/build.gradle index c82238b..047751a 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ apply plugin: 'net.minecraftforge.gradle' apply plugin: 'eclipse' apply plugin: 'maven-publish' -version = '0.1' +version = '0.1.1' group = 'magnileve.chungamod' // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = 'chungamod' diff --git a/src/main/java/magnileve/chungamod/Chungamod.java b/src/main/java/magnileve/chungamod/Chungamod.java index 84a45f3..d3c4237 100644 --- a/src/main/java/magnileve/chungamod/Chungamod.java +++ b/src/main/java/magnileve/chungamod/Chungamod.java @@ -7,8 +7,9 @@ import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Logger; +import magnileve.chungamod.settings.Settings; import magnileve.chungamod.time.TickTimer; @Mod(modid = Ref.MODID, name = Ref.NAME, version = Ref.VERSION, acceptedMinecraftVersions = Ref.ACCEPTED_MINECRAFT_VERSIONS) @@ -23,7 +24,7 @@ public class Chungamod { @EventHandler public void preInit(FMLPreInitializationEvent event) { mc = Minecraft.getMinecraft(); - log = event.getModLog(); + log = (Logger) event.getModLog(); log.info(Ref.MODID + ":Pre-Initialization"); Settings.load(log); Ref.init(mc); diff --git a/src/main/java/magnileve/chungamod/Commands.java b/src/main/java/magnileve/chungamod/Commands.java index 38fb969..4976e52 100644 --- a/src/main/java/magnileve/chungamod/Commands.java +++ b/src/main/java/magnileve/chungamod/Commands.java @@ -8,14 +8,14 @@ import java.util.Collection; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Logger; import magnileve.chungamod.itemstorage.AutoSort; +import magnileve.chungamod.settings.DiscordRPCManager; +import magnileve.chungamod.settings.LogSetting; +import magnileve.chungamod.settings.Settings; import magnileve.chungamod.time.ClientTps; import magnileve.chungamod.time.Activity; -import net.arikia.dev.drpc.DiscordEventHandlers; -import net.arikia.dev.drpc.DiscordRPC; -import net.arikia.dev.drpc.DiscordRichPresence; import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.client.Minecraft; @@ -29,11 +29,10 @@ @Mod.EventBusSubscriber(modid=Ref.MODID) public class Commands { -private static final long START_TIME = System.currentTimeMillis() / 1000; - private static Minecraft mc; private static Logger log; -private static final String HELP_MESSAGE = "Chungamod \\version by Magnileve\nCommands:\n\\prefixcancel - cancel current activities\n\\prefixset - set a setting\n\\prefixset - set a setting of a feature\n\\prefixhelp - sends this message\n\\prefixautosort - automatically sort shulker boxes\n\\prefixblockdata - get block state of selected block\n\\prefixclienttps - measure and periodically send client TPS"; +private static final String HELP_MESSAGE = "Chungamod \\version by Magnileve\nCommands:\n\\prefixhelp - sends this message\n\\prefixset - get list of settings\n\\prefixset - set a setting\n\\prefixset - set a setting of a feature\n\\prefixcancel - cancel current activities\n\\prefixautosort - automatically sort shulker boxes\n\\prefixdiscordrpc - send list of Discord RPC setting values"; +private static final String HELP_DEBUG_MESSAGE = "\nDebug commands:\n\\prefixblockdata - get block state of selected block\n\\prefixclienttps - measure and periodically send client TPS\n\\prefixplayerdirection - send pitch and yaw of camera and player\n\\prefixentitylist - send list of all entities in your current chunk\n\\prefixplayerpos - send current player position"; protected static void init(Minecraft minecraft, Logger logger) { mc = minecraft; @@ -41,16 +40,8 @@ protected static void init(Minecraft minecraft, Logger logger) { } public static void init2() { - //initiate DiscordRPC - if((Boolean) Settings.get("discordrpc")) { - discordRPCstart(); - } - java.lang.Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - if((Boolean) Settings.get("discordrpc")) DiscordRPC.discordShutdown(); - } - }); + Settings.addListener(new DiscordRPCManager()); + Settings.addListener(new LogSetting(log)); } @SubscribeEvent @@ -60,10 +51,10 @@ public static void onServerChatEvent(ClientChatEvent event) { event.setCanceled(true); log.info("Chungamod command called: " + event.getMessage()); String[] command = event.getMessage().split(" "); - if (command[0].length() == ((String) Settings.get("prefix")).length()) mc.player.sendMessage(new TextComponentString(HELP_MESSAGE.replaceAll("\\\\prefix", (String) Settings.get("prefix")).replaceFirst("\\\\version", Ref.VERSION))); + if (command[0].length() == ((String) Settings.get("prefix")).length()) mc.player.sendMessage(new TextComponentString(HELP_MESSAGE.concat((boolean) Settings.get("debug") ? HELP_DEBUG_MESSAGE : "").replaceAll("\\\\prefix", (String) Settings.get("prefix")).replaceFirst("\\\\version", Ref.VERSION))); else switch (command[0].substring(((String) Settings.get("prefix")).length()).toLowerCase()) { case "help": - mc.player.sendMessage(new TextComponentString(HELP_MESSAGE.replaceAll("\\n\\\\prefix", "\n" + (String) Settings.get("prefix")).replaceFirst("\\\\version", Ref.VERSION))); + mc.player.sendMessage(new TextComponentString(HELP_MESSAGE.concat((boolean) Settings.get("debug") ? HELP_DEBUG_MESSAGE : "").replaceAll("\\n\\\\prefix", "\n" + (String) Settings.get("prefix")).replaceFirst("\\\\version", Ref.VERSION))); break; case "set": if(command.length > 1) { @@ -73,9 +64,7 @@ else switch (command[0].substring(((String) Settings.get("prefix")).length()).to Settings.Type settingValueEnum = null; try { settingValueEnum = (Settings.Type) settingValue; - } catch(ClassCastException e) { - - } + } catch(ClassCastException e) {} if(settingValueEnum == null) { Object[] featureSettings = (Object[]) settingValue; if(command.length > 2) { @@ -123,13 +112,33 @@ else switch (command[0].substring(((String) Settings.get("prefix")).length()).to log.catching(Level.WARN, e); } break; + case BYTE: + case BYTE_POSITIVE: case SHORT: if(command.length == 4) { try { - Short newNumber = Short.valueOf(command[3]); - if(newNumber < 0) newNumber = 0; - Settings.set(command[1], command[2], newNumber); - Ref.sendMessage("Set " + command[1] + "." + command[2] + " to " + newNumber); + switch((Settings.Type) featureSettings[i]) { + case BYTE_POSITIVE: + if(Byte.valueOf(command[3]) > 0) featureSettings[i] = Settings.Type.BYTE; + else { + Ref.sendMessage("Number value must be above 0"); + break; + } + case BYTE: + Byte newByte = Byte.valueOf(command[3]); + if(newByte < 0) newByte = 0; + Settings.set(command[1], command[2], newByte); + Ref.sendMessage("Set " + command[1] + "." + command[2] + " to " + newByte); + break; + case SHORT: + Short newShort = Short.valueOf(command[3]); + if(newShort < 0) newShort = 0; + Settings.set(command[1], command[2], newShort); + Ref.sendMessage("Set " + command[1] + "." + command[2] + " to " + newShort); + break; + default: + break; + } } catch(NumberFormatException e) { Ref.sendMessage("Enter a number value"); } @@ -196,13 +205,33 @@ else switch (command[0].substring(((String) Settings.get("prefix")).length()).to log.catching(Level.WARN, e); } break; + case BYTE: + case BYTE_POSITIVE: case SHORT: if(command.length == 3) { try { - Short newNumber = Short.valueOf(command[2]); - if(newNumber < 0) newNumber = 0; - Settings.set(command[1], newNumber); - Ref.sendMessage("Set " + command[1] + " to " + newNumber); + switch(settingValueEnum) { + case BYTE_POSITIVE: + if(Byte.valueOf(command[2]) > 0) settingValueEnum = Settings.Type.BYTE; + else { + Ref.sendMessage("Number value must be above 0"); + break; + } + case BYTE: + Byte newByte = Byte.valueOf(command[2]); + if(newByte < 0) newByte = 0; + Settings.set(command[1], newByte); + Ref.sendMessage("Set " + command[1] + " to " + newByte); + break; + case SHORT: + Short newShort = Short.valueOf(command[2]); + if(newShort < 0) newShort = 0; + Settings.set(command[1], newShort); + Ref.sendMessage("Set " + command[1] + " to " + newShort); + break; + default: + break; + } } catch(NumberFormatException e) { Ref.sendMessage("Enter a number value"); } @@ -221,53 +250,57 @@ else switch (command[0].substring(((String) Settings.get("prefix")).length()).to } } } - } else Ref.sendMessage("Enter a setting and value following your command"); - case "autosort": - if(Settings.get("autosort", "pos1") != null && Settings.get("autosort", "pos2") != null && Settings.get("autosort", "source") != null) { - Ref.sendMessage("Running AutoSort"); - Ref.runningActivities.add(new AutoSort(mc, (BlockPos) Settings.get("autosort", "pos1"), (BlockPos) Settings.get("autosort", "pos2"), (BlockPos) Settings.get("autosort", "source"), (Short) Settings.get("autosort", "sourceemptytimeout"), (BlockPos) Settings.get("autosort", "overflow"), log)); - } - else Ref.sendMessage("Make sure to set AutoSort settings pos1, pos2, and source before running (use " + (String) Settings.get("prefix") + "set autosort "); + } else Ref.sendMessage("Settings: " + Settings.SETTINGS_LIST); break; case "cancel": Ref.sendMessage("Cancelling running activities"); for(Activity activity:Ref.runningActivities) activity.stop(); Ref.runningActivities.clear(); break; - case "clienttps": - Ref.runningActivities.add(new ClientTps()); - break; - case "blockdata": - BlockPos blockPos = mc.getRenderViewEntity().rayTrace(4.5D, 1.0F).getBlockPos(); - for(IProperty property:mc.world.getBlockState(blockPos).getBlock().getBlockState().getProperties()) { - Ref.sendMessage(property.toString()); - Ref.sendMessage(property.getName()); - Ref.sendMessage(property.getClass().toString()); - Ref.sendMessage("property value: " + mc.world.getBlockState(blockPos).getValue(property)); - } - if(Block.getIdFromBlock(mc.world.getBlockState(blockPos).getBlock()) == 68) { - TileEntitySign tileEntity = (TileEntitySign) mc.world.getChunkFromBlockCoords(blockPos).getTileEntity(blockPos, Chunk.EnumCreateEntityType.CHECK); - for(ITextComponent text:tileEntity.signText) Ref.sendMessage("Sign text: " + text); + case "autosort": + if(Settings.get("autosort", "pos1") != null && Settings.get("autosort", "pos2") != null && Settings.get("autosort", "source") != null) { + Ref.sendMessage("Running AutoSort"); + Ref.runningActivities.add(new AutoSort(mc, (BlockPos) Settings.get("autosort", "pos1"), (BlockPos) Settings.get("autosort", "pos2"), (BlockPos) Settings.get("autosort", "source"), (Short) Settings.get("autosort", "source_empty_timeout"), (BlockPos) Settings.get("autosort", "overflow"), log)); } + else Ref.sendMessage("Make sure to set AutoSort settings pos1, pos2, and source before running (use " + (String) Settings.get("prefix") + "set autosort "); + break; + case "discordrpc": + Ref.sendMessage(DiscordRPCManager.getDiscordRPCManager().getSettingValues()); break; default: - if((Boolean) Settings.get("debug")) { + if((boolean) Settings.get("debug")) { switch (command[0].substring(((String) Settings.get("prefix")).length()).toLowerCase()) { - case "cameradirection": + case "clienttps": + Ref.runningActivities.add(new ClientTps()); + break; + case "blockdata": + BlockPos blockPos = mc.getRenderViewEntity().rayTrace(4.5D, 1.0F).getBlockPos(); + for(IProperty property:mc.world.getBlockState(blockPos).getBlock().getBlockState().getProperties()) { + Ref.sendMessage(property.toString()); + Ref.sendMessage(property.getName()); + Ref.sendMessage(property.getClass().toString()); + Ref.sendMessage("property value: " + mc.world.getBlockState(blockPos).getValue(property)); + } + if(Block.getIdFromBlock(mc.world.getBlockState(blockPos).getBlock()) == 68) { + TileEntitySign tileEntity = (TileEntitySign) mc.world.getChunkFromBlockCoords(blockPos).getTileEntity(blockPos, Chunk.EnumCreateEntityType.CHECK); + for(ITextComponent text:tileEntity.signText) Ref.sendMessage("Sign text: " + text); + } + break; + case "playerdirection": Ref.sendMessage("Camera pitch: " + mc.player.cameraPitch + "\nCamera yaw: " + mc.player.cameraYaw + "\nRotation pitch: " + mc.player.rotationPitch + "\nRotation yaw: " + mc.player.rotationYaw); break; case "entitylist": for(Collection collection:mc.world.getChunkFromBlockCoords(mc.player.getPosition()).getEntityLists()) { - log.debug("\nCollection " + collection.getClass()); + Ref.sendMessage("\nCollection " + collection.getClass()); for(Object o:collection) { - log.debug(o.getClass().toString()); - log.debug(o.toString()); + Ref.sendMessage(o.getClass().toString()); + Ref.sendMessage(o.toString()); } } break; case "playerpos": - Ref.sendMessage(Ref.playerPos().toString()); + Ref.sendMessage(new BlockPos(mc.player.posX, mc.player.posY, mc.player.posZ).toString()); break; default: @@ -278,10 +311,4 @@ else switch (command[0].substring(((String) Settings.get("prefix")).length()).to } } -//setup DiscordRPC -private static void discordRPCstart() { - DiscordRPC.discordInitialize("832742372420091964", new DiscordEventHandlers.Builder().build(), true); - DiscordRPC.discordUpdatePresence(new DiscordRichPresence.Builder("Mincerfat client").setBigImage("chungustransparentcroppedlarge", "All hail Big Chungus").setDetails("The funniest").setStartTimestamps(START_TIME).build()); -} - } \ No newline at end of file diff --git a/src/main/java/magnileve/chungamod/Ref.java b/src/main/java/magnileve/chungamod/Ref.java index c550d30..361942a 100644 --- a/src/main/java/magnileve/chungamod/Ref.java +++ b/src/main/java/magnileve/chungamod/Ref.java @@ -4,7 +4,6 @@ import magnileve.chungamod.time.Activity; import net.minecraft.client.Minecraft; -import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -13,7 +12,7 @@ public class Ref { public static final String MODID = "chungamod"; public static final String NAME = "Chungamod"; - public static final String VERSION = "0.1"; + public static final String VERSION = "0.1.1"; public static final String ACCEPTED_MINECRAFT_VERSIONS = "[1.12]"; private static Minecraft mc; public static LinkedList runningActivities; @@ -44,24 +43,4 @@ public static final Vec3d getVectorForRotation(float pitch, float yaw) { float f3 = MathHelper.sin(-pitch * 0.017453292F); return new Vec3d((double)(f1 * f2), (double)f3, (double)(f * f2)); } - - public static BlockPos playerPos() { - return new BlockPos(mc.player.posX, mc.player.posY, mc.player.posZ); - } - - //get yaw from cardinal direction - public static float enumFacingToYaw(EnumFacing facing) { - switch(facing) { - case SOUTH: - return 0F; - case WEST: - return 90F; - case NORTH: - return 180F; - case EAST: - return -90F; - default: - throw new IllegalStateException("Unable to get yaw from vertical direction " + facing); - } - } } \ No newline at end of file diff --git a/src/main/java/magnileve/chungamod/itemstorage/AutoSort.java b/src/main/java/magnileve/chungamod/itemstorage/AutoSort.java index a9e7795..b0f9e56 100644 --- a/src/main/java/magnileve/chungamod/itemstorage/AutoSort.java +++ b/src/main/java/magnileve/chungamod/itemstorage/AutoSort.java @@ -3,9 +3,10 @@ import java.util.LinkedList; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Logger; import magnileve.chungamod.Ref; +import magnileve.chungamod.settings.Settings; import magnileve.chungamod.time.Activity; import magnileve.chungamod.time.TickListener; import magnileve.chungamod.time.TickTimer; @@ -30,57 +31,98 @@ public class AutoSort implements TickListener, Activity { +private final BlockPos source; +private final BlockPos overflow; +private final short sourceEmptyTimeout; +private final byte inventorySpace; +private final EnumFacing sourceFacing; +private final EnumFacing overflowFacing; +private final boolean sourceDoubleChest; +private final boolean overflowDoubleChest; + private Minecraft mc; private Logger log; private NetHandlerPlayClient connection; private LinkedList sortLocations; private Status status; -private BlockPos source; -private BlockPos overflow; private BlockPos destination; private StorageUnit unit; +private double prevDistance; private int nextTick; -private short sourceEmptyTimeout; private byte slot; private byte moveSlot; -private byte inventorySpace; -private EnumFacing sourceFacing; -private EnumFacing overflowFacing; +private byte stuckCheck; private EnumFacing destinationOffset; -private boolean sourceDoubleChest; -private boolean overflowDoubleChest; private boolean goToOverflow; -public AutoSort(Minecraft minecraft, BlockPos pos1, BlockPos pos2, BlockPos shulkerSource, short sourceEmptyTimeout, BlockPos shulkerOverflow, Logger logger) { - mc = minecraft; +public AutoSort(Minecraft mcIn, BlockPos pos1, BlockPos pos2, BlockPos sourceIn, short sourceEmptyTimeout, BlockPos overflowIn, Logger logIn) { + this(mcIn, getStorageUnits(mcIn, pos1, pos2, logIn), sourceIn, sourceEmptyTimeout, overflowIn, logIn); +} + +public AutoSort(Minecraft mcIn, LinkedList sortLocationsIn, BlockPos sourceIn, short sourceEmptyTimeout, BlockPos overflowIn, Logger logIn) { + mc = mcIn; connection = mc.player.connection; - log = logger; - source = shulkerSource; + log = logIn; + source = sourceIn; this.sourceEmptyTimeout = sourceEmptyTimeout; - overflow = shulkerOverflow; - if(source.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250 || - (overflow == null ? false : overflow.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250) || - pos1.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250 || - pos2.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250) { + overflow = overflowIn; + stuckCheck = 0; + sortLocations = sortLocationsIn; + goToOverflow = false; + if(sortLocations == null || source.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250 || + (overflow == null ? false : overflow.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250)) { Ref.sendMessage("AutoSort error: Chests too far away"); Ref.runningActivities.remove(this); + sourceFacing = null; + overflowFacing = null; + sourceDoubleChest = false; + overflowDoubleChest = false; + inventorySpace = 0; + status = Status.SOURCE_EMPTY_TIMEOUT; return; } - sortLocations = new LinkedList<>(); - goToOverflow = false; log.info("[AutoSort] Running AutoSort"); + EnumFacing getSourceFacing = null; + boolean getSourceDoubleChest = false; for(IProperty property:mc.world.getBlockState(source).getBlock().getBlockState().getProperties()) if(property.getName().equals("facing")) { - sourceFacing = (EnumFacing) mc.world.getBlockState(source).getValue(property); - sourceDoubleChest = (isChest(Block.getIdFromBlock(mc.world.getBlockState(source.offset(sourceFacing.rotateY())).getBlock())) || - isChest(Block.getIdFromBlock(mc.world.getBlockState(source.offset(sourceFacing.rotateYCCW())).getBlock()))); + getSourceFacing = (EnumFacing) mc.world.getBlockState(source).getValue(property); + getSourceDoubleChest = (isChest(Block.getIdFromBlock(mc.world.getBlockState(source.offset(getSourceFacing.rotateY())).getBlock())) || + isChest(Block.getIdFromBlock(mc.world.getBlockState(source.offset(getSourceFacing.rotateYCCW())).getBlock()))); break; } + sourceFacing = getSourceFacing; + sourceDoubleChest = getSourceDoubleChest; + EnumFacing getOverflowFacing = null; + boolean getOverflowDoubleChest = false; if(overflow != null) for(IProperty property:mc.world.getBlockState(overflow).getBlock().getBlockState().getProperties()) if(property.getName().equals("facing")) { - overflowFacing = (EnumFacing) mc.world.getBlockState(overflow).getValue(property); - overflowDoubleChest = (isChest(Block.getIdFromBlock(mc.world.getBlockState(overflow.offset(overflowFacing.rotateY())).getBlock())) || - isChest(Block.getIdFromBlock(mc.world.getBlockState(overflow.offset(overflowFacing.rotateYCCW())).getBlock()))); + getOverflowFacing = (EnumFacing) mc.world.getBlockState(overflow).getValue(property); + getOverflowDoubleChest = (isChest(Block.getIdFromBlock(mc.world.getBlockState(overflow.offset(getOverflowFacing.rotateY())).getBlock())) || + isChest(Block.getIdFromBlock(mc.world.getBlockState(overflow.offset(getOverflowFacing.rotateYCCW())).getBlock()))); break; } + overflowFacing = getOverflowFacing; + overflowDoubleChest = getOverflowDoubleChest; + + byte getInventorySpace = 0; + for(byte i = 9; i < 45; i++) { + Slot thisSlot = mc.player.openContainer.getSlot(i); + if(thisSlot.getHasStack()) { + int itemID = Item.getIdFromItem(thisSlot.getStack().getItem()); + if(itemID > 218 && itemID < 235 && overflow != null) getInventorySpace++; + } else getInventorySpace++; + } + inventorySpace = getInventorySpace; + slot = 9; + status = Status.SEARCHING_STORAGE; + TickTimer.addListener(this); + nextTick(1); + log.debug("finished initialization"); +} + +private static LinkedList getStorageUnits(Minecraft mc, BlockPos pos1, BlockPos pos2, Logger log) { + LinkedList sortLocations = new LinkedList<>(); + if(pos1.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250 || + pos2.getDistance((int) mc.player.posX, (int) mc.player.posY, (int) mc.player.posZ) > 250) return null; int minX = Math.min(pos1.getX(), pos2.getX()); int minY = Math.min(pos1.getY(), pos2.getY()); int minZ = Math.min(pos1.getZ(), pos2.getZ()); @@ -118,24 +160,13 @@ public AutoSort(Minecraft minecraft, BlockPos pos1, BlockPos pos2, BlockPos shul (doubleChestFacing == null ? true : (Block.getIdFromBlock(mc.world.getBlockState(blockPos.up(height).offset(doubleChestFacing)).getBlock())) == blockID) && height < 6) height++; sortLocations.add(new StorageUnit(blockPos, shulkerName, height, facing, doubleChestFacing != null)); log.debug("[AutoSort] Adding storage location of \"" + shulkerName + "\" with height " + height + " at " + blockPos); - for(char character:shulkerName.toCharArray()) log.debug(character); } break; } } } } - for(byte i = 9; i < 45; i++) { - Slot thisSlot = mc.player.openContainer.getSlot(i); - if(thisSlot.getHasStack()) { - int itemID = Item.getIdFromItem(thisSlot.getStack().getItem()); - if(itemID > 218 && itemID < 235 && overflow != null) inventorySpace++; - } else inventorySpace++; - } - slot = 8; - status = Status.SEARCHING_STORAGE; - TickTimer.addListener(this); - nextTick(1); + return sortLocations; } @Override @@ -149,6 +180,7 @@ public void onTick(int tick) { double distance = new BlockPos(mc.player.posX, mc.player.posY, mc.player.posZ).getDistance(destination.offset(destinationOffset).getX(), destination.getY(), destination.offset(destinationOffset).getZ()); if(distance == 0D) { mc.player.sendChatMessage("#cancel"); + stuckCheck = 0; //open chest double dx = destination.getX() - mc.player.posX + 0.5; @@ -191,18 +223,33 @@ public void onTick(int tick) { if(status == Status.GOING_TO_STORAGE) status = Status.WAITING_ON_STORAGE; else if(status == Status.GOING_TO_SOURCE) status = Status.WAITING_ON_SOURCE; else status = Status.WAITING_ON_OVERFLOW; - nextTick(1); - } else nextTick((int) (distance * 5)); + + prevDistance = 0D; + nextTick((Byte) Settings.get("tickdelay")); + } else { + if(distance == prevDistance) { + if(stuckCheck + distance * 5 > 127) stuckCheck = 127; + else stuckCheck += distance * 5; + } + prevDistance = distance; + nextTick((int) (distance * 5)); + } break; case WAITING_ON_SOURCE: if(mc.player.openContainer.windowId == 0) { + stuckCheck++; nextTick(1); break; } else { + stuckCheck = 0; slot = -1; moveSlot = 0; status = Status.TAKING_SHULKERS; log.debug("[AutoSort] Taking shulkers"); + if((short) Settings.get("autosort", "chest_open_tick_delay") > 0) { + nextTick((short) Settings.get("autosort", "chest_open_tick_delay")); + break; + } } case TAKING_SHULKERS: if(slot == (sourceDoubleChest ? 54 : 27)) { @@ -213,9 +260,8 @@ public void onTick(int tick) { break; } } else { - //connection.sendPacket(new CPacketCloseWindow(mc.player.openContainer.windowId)); mc.player.closeScreen(); - slot = 8; + slot = 9; status = Status.SEARCHING_STORAGE; } } else { @@ -232,11 +278,12 @@ public void onTick(int tick) { } } } - nextTick(2); + nextTick((Byte) Settings.get("tickdelay")); break; case SEARCHING_STORAGE: if(mc.player.openContainer.windowId == 0) { - for(slot++; slot < 45; slot++) { + stuckCheck = 0; + for(; slot < 45; slot++) { Slot thisSlot = mc.player.openContainer.getSlot(slot); if(thisSlot.getHasStack()) { int itemID = Item.getIdFromItem(thisSlot.getStack().getItem()); @@ -272,15 +319,17 @@ public void onTick(int tick) { } } mc.player.sendChatMessage("#goto ~" + (destination.offset(destinationOffset).getX() - (int) Math.floor(mc.player.posX)) + " ~" + (destination.getY() - (int) Math.floor(mc.player.posY)) + " ~" + (destination.offset(destinationOffset).getZ() - (int) Math.floor(mc.player.posZ))); - } + } else stuckCheck++; nextTick(1); break; case WAITING_ON_STORAGE: if(mc.player.openContainer.windowId == 0) { + stuckCheck++; nextTick(1); break; } else { - if(mc.player.openContainer.getSlot(unit.doubleChest() ? 53 : 26).getHasStack()) { + stuckCheck = 0; + if(mc.player.openContainer.getSlot(unit.isDoubleChest() ? 53 : 26).getHasStack() && mc.player.openContainer.getSlot(0).getHasStack()) { mc.player.closeScreen(); log.debug("[AutoSort] Chest full"); if(unit.nextUp()) { @@ -298,40 +347,46 @@ public void onTick(int tick) { nextTick(1); break; } else { - log.debug("Slot: " + slot + (unit.doubleChest() ? 44 : 17)); - moveSlot = (byte) (slot + (unit.doubleChest() ? 44 : 17)); + moveSlot = (byte) (slot + (unit.isDoubleChest() ? 44 : 17)); status = Status.PUTTING_SHULKERS; log.debug("Putting shulkers: " + unit.getName()); + if((short) Settings.get("autosort", "chest_open_tick_delay") > 0) { + nextTick((short) Settings.get("autosort", "chest_open_tick_delay")); + break; + } } } case PUTTING_SHULKERS: - for(moveSlot++; moveSlot < (unit.doubleChest() ? 90 : 63); moveSlot++) { + for(; moveSlot < (unit.isDoubleChest() ? 90 : 63); moveSlot++) { Slot thisSlot = mc.player.openContainer.getSlot(moveSlot); if(thisSlot.getHasStack()) { int itemID = Item.getIdFromItem(thisSlot.getStack().getItem()); - log.debug("MoveSlot: " + moveSlot); - log.debug(thisSlot.getStack().getDisplayName() + unit.getName()); - log.debug(thisSlot.getStack().getDisplayName().equals(unit.getName())); if(itemID > 218 && itemID < 235 && thisSlot.getStack().getDisplayName().equals(unit.getName())) { connection.sendPacket(new CPacketClickWindow(mc.player.openContainer.windowId, moveSlot, 0, ClickType.QUICK_MOVE, thisSlot.getStack(), mc.player.openContainer.getNextTransactionID(mc.player.inventory))); break; } } } - if(moveSlot == (unit.doubleChest() ? 90 : 63)) { + if(moveSlot == (unit.isDoubleChest() ? 90 : 63)) { mc.player.closeScreen(); status = Status.SEARCHING_STORAGE; - } else if(mc.player.openContainer.getSlot(unit.doubleChest() ? 53 : 26).getHasStack()) status = Status.WAITING_ON_STORAGE; - nextTick(2); + } else if(mc.player.openContainer.getSlot(unit.isDoubleChest() ? 53 : 26).getHasStack()) status = Status.WAITING_ON_STORAGE; + nextTick((Byte) Settings.get("tickdelay")); break; case WAITING_ON_OVERFLOW: if(mc.player.openContainer.windowId == 0) { + stuckCheck++; nextTick(1); break; } else { + stuckCheck = 0; slot = (byte) (overflowDoubleChest ? 53 : 26); status = Status.DUMPING_SHULKERS; log.debug("[AutoSort] Dumping shulkers"); + if((short) Settings.get("autosort", "chest_open_tick_delay") > 0) { + nextTick((short) Settings.get("autosort", "chest_open_tick_delay")); + break; + } } case DUMPING_SHULKERS: for(slot++; slot < (overflowDoubleChest ? 90 : 63); slot++) { @@ -346,15 +401,15 @@ public void onTick(int tick) { } if(slot == (overflowDoubleChest ? 90 : 63)) { mc.player.closeScreen(); - slot = 8; + slot = 9; status = Status.SEARCHING_STORAGE; - } else if(mc.player.openContainer.getSlot(overflowDoubleChest ? 53 : 26).getHasStack()) { + } else if(mc.player.openContainer.getSlot(overflowDoubleChest ? 53 : 26).getHasStack() && mc.player.openContainer.getSlot(0).getHasStack()) { Ref.sendMessage("[AutoSort] Overflow chest full"); stop(); Ref.runningActivities.remove(this); break; } - nextTick(2); + nextTick((Byte) Settings.get("tickdelay")); break; case SOURCE_EMPTY_TIMEOUT: Slot thisSlot = mc.player.openContainer.getSlot(0); @@ -379,13 +434,20 @@ public void onTick(int tick) { stop(); Ref.runningActivities.remove(this); } + if(stuckCheck == 127) { + log.warn("Autosort stuck\nStatus: {}\nStorage chests: {}\nDestination: {}\nPlayer window ID: {}\nDistance to destination: {}\nSlot: {}\nMoveSlot: {}", status, sortLocations, destination, mc.player.openContainer.windowId, prevDistance, slot, moveSlot); + Ref.sendMessage("Autosort stuck in status: " + status); + stop(); + Ref.runningActivities.remove(this); + Ref.runningActivities.add(new AutoSort(mc, sortLocations, source, sourceEmptyTimeout, overflow, log)); + } } } @Override public void stop() { log.info("[AutoSort] Stopping AutoSort"); - if(status.equals(Status.GOING_TO_SOURCE) || status.equals(Status.GOING_TO_STORAGE)) mc.player.sendChatMessage("#cancel"); + if(status.equals(Status.GOING_TO_SOURCE) || status.equals(Status.GOING_TO_STORAGE) || status.equals(Status.GOING_TO_OVERFLOW)) mc.player.sendChatMessage("#cancel"); TickTimer.removeListener(this); } @@ -398,7 +460,7 @@ private void nextTick(int tick) { TickTimer.add(tick); } -private boolean isChest(int blockID) { +private static boolean isChest(int blockID) { return (blockID == 54 || blockID == 146); } diff --git a/src/main/java/magnileve/chungamod/itemstorage/StorageUnit.java b/src/main/java/magnileve/chungamod/itemstorage/StorageUnit.java index 44e62c8..f997b66 100644 --- a/src/main/java/magnileve/chungamod/itemstorage/StorageUnit.java +++ b/src/main/java/magnileve/chungamod/itemstorage/StorageUnit.java @@ -5,14 +5,15 @@ public class StorageUnit { -private BlockPos location; -private String shulkerName; -private byte height; +private final BlockPos location; +private final String shulkerName; +private final byte height; +private final EnumFacing facing; +private final boolean doubleChest; + private byte fillHeight; -private EnumFacing facing; -private boolean doubleChest; -protected StorageUnit(BlockPos location, String shulkerName, byte height, EnumFacing facing, boolean doubleChest) { +public StorageUnit(BlockPos location, String shulkerName, byte height, EnumFacing facing, boolean doubleChest) { this.location = location; this.shulkerName = shulkerName; this.height = height; @@ -21,28 +22,33 @@ protected StorageUnit(BlockPos location, String shulkerName, byte height, EnumFa this.doubleChest = doubleChest; } -protected String getName() { +@Override +public String toString() { + return (height + (doubleChest ? " double chest" : " single chest") + (height > 1 ? "s" : "") + " for " + shulkerName + " at " + location); +} + +public String getName() { return shulkerName; } -protected BlockPos getBlockPos() { +public BlockPos getBlockPos() { return location; } -protected byte getFillHeight() { +public byte getFillHeight() { return fillHeight; } -protected boolean nextUp() { +public boolean nextUp() { fillHeight++; return fillHeight < height; } -protected EnumFacing getFacing() { +public EnumFacing getFacing() { return facing; } -protected boolean doubleChest() { +public boolean isDoubleChest() { return doubleChest; } diff --git a/src/main/java/magnileve/chungamod/settings/DiscordRPCManager.java b/src/main/java/magnileve/chungamod/settings/DiscordRPCManager.java new file mode 100644 index 0000000..a54d10d --- /dev/null +++ b/src/main/java/magnileve/chungamod/settings/DiscordRPCManager.java @@ -0,0 +1,121 @@ +package magnileve.chungamod.settings; + +import magnileve.chungamod.Ref; +import net.arikia.dev.drpc.DiscordEventHandlers; +import net.arikia.dev.drpc.DiscordRPC; +import net.arikia.dev.drpc.DiscordRichPresence; + +public class DiscordRPCManager implements SettingListener { + +private final String[] SETTING_LIST = {"visible", "upper_line", "lower_line", "minecraft_name", "minecraft_version"}; +private final String[] STATUS_LIST = {"Playing \\Mincerfat \\version", "The funniest client", "Version " + Ref.VERSION, "v" + Ref.VERSION + " | \\Mincerfat \\version", "9b9t.org", "9b9t.com", "2b2t.org", "2b2t.com", "Hypixel.net", "All hail Big Chungus", "Big Chungus on top", "ok", "ok chains on top", "Building highways", "Digging nether tunnels", "NHS on top", "Chungamod on top", "Chungia on top", "NHS > HWU", "9b9t > 2b2t"}; +private final String[] MINCERFAT_NAME_LIST = {"Minecraft", "Mincerfat", "Minceraft", "block game"}; +private final String[] MINCERFAT_VERSION_LIST = {"1.12", "1.12.2"}; +private final long START_TIME; +private boolean visible; + +private static DiscordRPCManager instance; +private byte details; +private byte state; +private byte mincerfatName; +private byte mincerfatVersion; + +public DiscordRPCManager() { + START_TIME = System.currentTimeMillis() / 1000; + java.lang.Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + if((boolean) Settings.get("discordrpc", "visible")) DiscordRPC.discordShutdown(); + } + }); + visible = (boolean) Settings.get("discordrpc", "visible"); + details = (byte) Settings.get("discordrpc", "upper_line"); + state = (byte) Settings.get("discordrpc", "lower_line"); + mincerfatName = (byte) Settings.get("discordrpc", "minecraft_name"); + mincerfatVersion = (byte) Settings.get("discordrpc", "minecraft_version"); + if(visible) { + DiscordRPC.discordInitialize("832742372420091964", new DiscordEventHandlers.Builder().build(), true); + discordRPCupdate(); + } + instance = this; +} + +@Override +public void onNewValue(String setting, Object value) { + switch(setting) { + case "upper_line": + if((byte) value > STATUS_LIST.length) { + Ref.sendMessage("Value must not be greater than " + STATUS_LIST.length); + Settings.set("discordrpc", setting, details); + } else details = (byte) value; + break; + case "lower_line": + if((byte) value > STATUS_LIST.length) { + Ref.sendMessage("Value must not be greater than " + STATUS_LIST.length); + Settings.set("discordrpc", setting, state); + } else state = (byte) value; + break; + case "minecraft_name": + if((byte) value > STATUS_LIST.length) { + Ref.sendMessage("Value must not be greater than " + MINCERFAT_NAME_LIST.length); + Settings.set("discordrpc", setting, mincerfatName); + } else mincerfatName = (byte) value; + break; + case "minecraft_version": + if((byte) value > STATUS_LIST.length) { + Ref.sendMessage("Value must not be greater than " + MINCERFAT_VERSION_LIST.length); + Settings.set("discordrpc", setting, mincerfatVersion); + } else mincerfatVersion = (byte) value; + break; + case "visible": + if(!visible == (boolean) value) { + visible = (boolean) value; + if(visible) DiscordRPC.discordInitialize("832742372420091964", new DiscordEventHandlers.Builder().build(), true); + else DiscordRPC.discordShutdown(); + } + } + if(visible) discordRPCupdate(); +} + +@Override +public boolean hasSetting(String setting) { + for(String thisSetting:SETTING_LIST) if(setting.equals("discordrpc " + thisSetting)) return true; + return false; +} + +public static DiscordRPCManager getDiscordRPCManager() { + return instance; +} + +public String getSettingValues() { + StringBuilder str = new StringBuilder().append("Status lines:"); + byte i = 0; + for(String value:STATUS_LIST) { + i++; + str.append("\n" + i + ". " + format(value)); + } + i = 0; + str.append("\nMinecraft names:"); + for(String value:MINCERFAT_NAME_LIST) { + i++; + str.append("\n" + i + ". " + format(value)); + } + i = 0; + str.append("\nMinecraft versions:"); + for(String value:MINCERFAT_VERSION_LIST) { + i++; + str.append("\n" + i + ". " + format(value)); + } + return str.toString(); +} + +//setup DiscordRPC +private void discordRPCupdate() { + DiscordRPC.discordUpdatePresence(new DiscordRichPresence.Builder(format(STATUS_LIST[state - 1])).setBigImage("chungamod-logo", "All hail Big Chungus").setDetails(format(STATUS_LIST[details - 1])).setStartTimestamps(START_TIME).build()); +} + +private String format(String string) { + return string.replaceFirst("\\\\Mincerfat", MINCERFAT_NAME_LIST[mincerfatName - 1]).replaceFirst("\\\\version", MINCERFAT_VERSION_LIST[mincerfatVersion - 1]); +} + +} diff --git a/src/main/java/magnileve/chungamod/settings/LogSetting.java b/src/main/java/magnileve/chungamod/settings/LogSetting.java new file mode 100644 index 0000000..8716e9e --- /dev/null +++ b/src/main/java/magnileve/chungamod/settings/LogSetting.java @@ -0,0 +1,39 @@ +package magnileve.chungamod.settings; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Logger; + +public class LogSetting implements SettingListener { + +private Logger log; +private Level defaultLevel; +private boolean currentSetting; + +public LogSetting(Logger log) { + this.log = log; + currentSetting = (boolean) Settings.get("debug"); + if(currentSetting) { + defaultLevel = log.getLevel(); + log.setLevel(Level.DEBUG); + log.debug("Log level set to debug"); + } +} + +@Override +public void onNewValue(String setting, Object value) { + if(setting.equals("debug") && !((Boolean) value).equals(currentSetting)) { + currentSetting = (Boolean) value; + if((Boolean) value) { + defaultLevel = log.getLevel(); + log.setLevel(Level.DEBUG); + log.debug("Log level set to debug"); + } else log.setLevel(defaultLevel); + } +} + +@Override +public boolean hasSetting(String setting) { + return setting.equals("debug"); +} + +} \ No newline at end of file diff --git a/src/main/java/magnileve/chungamod/settings/SettingListener.java b/src/main/java/magnileve/chungamod/settings/SettingListener.java new file mode 100644 index 0000000..d61d4f6 --- /dev/null +++ b/src/main/java/magnileve/chungamod/settings/SettingListener.java @@ -0,0 +1,6 @@ +package magnileve.chungamod.settings; + +public interface SettingListener { + public void onNewValue(String setting, Object value); + public boolean hasSetting(String setting); +} \ No newline at end of file diff --git a/src/main/java/magnileve/chungamod/Settings.java b/src/main/java/magnileve/chungamod/settings/Settings.java similarity index 73% rename from src/main/java/magnileve/chungamod/Settings.java rename to src/main/java/magnileve/chungamod/settings/Settings.java index 39623a5..a918957 100644 --- a/src/main/java/magnileve/chungamod/Settings.java +++ b/src/main/java/magnileve/chungamod/settings/Settings.java @@ -1,4 +1,4 @@ -package magnileve.chungamod; +package magnileve.chungamod.settings; import java.io.File; import java.io.FileInputStream; @@ -7,8 +7,11 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map.Entry; -import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Logger; import net.minecraft.util.math.BlockPos; @@ -16,15 +19,19 @@ public class Settings { private static final HashMap SETTING_VALUES = settingValues(); private static final HashMap DEFAULT_SETTINGS = defaultSettings(); +public static final String SETTINGS_LIST = settingList(); private static Logger log; private static HashMap settings; +private static LinkedList listeners; private static final HashMap settingValues() { HashMap settingValues = new HashMap<>(); settingValues.put("prefix", Type.STRING_ONE_WORD); - settingValues.put("discordrpc", Type.BOOLEAN); + Object[] discordRPCSettings = {"visible upper_line lower_line minecraft_name minecraft_version", Type.BOOLEAN, Type.BYTE_POSITIVE, Type.BYTE_POSITIVE, Type.BYTE_POSITIVE, Type.BYTE_POSITIVE}; + settingValues.put("discordrpc", discordRPCSettings); settingValues.put("debug", Type.BOOLEAN); - Object[] autoSortSettings = {"pos1 pos2 source sourceemptyimeout overflow", Type.BLOCKPOS, Type.BLOCKPOS, Type.BLOCKPOS, Type.SHORT, Type.BLOCKPOS}; + settingValues.put("tickdelay", Type.BYTE_POSITIVE); + Object[] autoSortSettings = {"pos1 pos2 source chest_open_tick_delay source_empty_timeout overflow", Type.BLOCKPOS, Type.BLOCKPOS, Type.BLOCKPOS, Type.SHORT, Type.SHORT, Type.BLOCKPOS}; settingValues.put("autosort", autoSortSettings); return settingValues; } @@ -32,13 +39,22 @@ private static final HashMap settingValues() { private static final HashMap defaultSettings() { HashMap defaultSettings = new HashMap<>(); defaultSettings.put("prefix", ","); - defaultSettings.put("discordrpc", true); + Object[] discordRPCSettings = {"visible upper_line lower_line minecraft_name minecraft_version", true, new Byte((byte) 1), new Byte((byte) 2), new Byte((byte) 1), new Byte((byte) 1)}; + defaultSettings.put("discordrpc", discordRPCSettings); defaultSettings.put("debug", false); - Object[] autoSortSettings = {"pos1 pos2 source sourceemptytimeout overflow", null, null, null, new Short((short) 2), null}; + defaultSettings.put("tickdelay", new Byte((byte) 2)); + Object[] autoSortSettings = {"pos1 pos2 source chest_open_tick_delay source_empty_timeout overflow", null, null, null, new Short((short) 2), new Short((short) 2), null}; defaultSettings.put("autosort", autoSortSettings); return defaultSettings; } +private static final String settingList() { + Iterator> iterator = SETTING_VALUES.entrySet().iterator(); + StringBuilder str = new StringBuilder().append(iterator.next().getKey()); + while(iterator.hasNext()) str.append(", " + iterator.next().getKey()); + return str.toString(); +} + public static Object get(String setting) { Object returnSetting = settings.get(setting); if(returnSetting instanceof Integer[]) { @@ -82,6 +98,7 @@ public static void set(String setting, Object value) { } settings.put(setting, value); save(settings); + for(SettingListener listener:listeners) if(listener.hasSetting(setting)) listener.onNewValue(setting, value); } public static void set(String feature, String setting, Object value) { @@ -108,6 +125,7 @@ public static void set(String feature, String setting, Object value) { settings.put(feature, featureSettings); } save(settings); + for(SettingListener listener:listeners) if(listener.hasSetting(feature + " " + setting)) listener.onNewValue(setting, value); } public static Object getValue(String setting) { @@ -122,8 +140,16 @@ public static Class getValue(String feature, String setting) { return (Class) featureSettings[i + 1]; } +public static void addListener(SettingListener listener) { + listeners.add(listener); +} + +public static void removeListener(SettingListener listener) { + listeners.remove(listener); +} + @SuppressWarnings("unchecked") -protected static void load(Logger logger) { +public static void load(Logger logger) { log = logger; HashMap loadedSettings; Object getSettingsResult = null; @@ -169,6 +195,7 @@ protected static void load(Logger logger) { save(loadedSettings); } settings = loadedSettings; + listeners = new LinkedList(); } private static void save(HashMap settings) { @@ -185,7 +212,7 @@ private static void save(HashMap settings) { } public static enum Type { - OBJECT_ARRAY, STRING, BOOLEAN, BLOCKPOS, SHORT, STRING_ONE_WORD + OBJECT_ARRAY, STRING, STRING_ONE_WORD, BOOLEAN, BLOCKPOS, BYTE, BYTE_POSITIVE, SHORT } } \ No newline at end of file diff --git a/src/main/java/magnileve/chungamod/time/TickTimer.java b/src/main/java/magnileve/chungamod/time/TickTimer.java index ac69ce6..d3314be 100644 --- a/src/main/java/magnileve/chungamod/time/TickTimer.java +++ b/src/main/java/magnileve/chungamod/time/TickTimer.java @@ -2,7 +2,7 @@ import java.util.LinkedList; -import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Logger; import magnileve.chungamod.Ref; import net.minecraftforge.fml.common.Mod; @@ -19,39 +19,43 @@ public class TickTimer { private static LinkedList listeners; private static Logger log; -public static void init(Logger logger) { +public static void init(Logger logIn) { tick = 0; listenTicks = new LinkedList(); listeners = new LinkedList(); - log = logger; + log = logIn; } @SubscribeEvent @SideOnly(value = Side.CLIENT) public static void onTick(ClientTickEvent event) { tick++; - if(!listenTicks.isEmpty() && listenTicks.peekFirst() == tick) { + if(!listenTicks.isEmpty() && listenTicks.getFirst() == tick) { listenTicks.remove(); for(TickListener listener:listeners) listener.onTick(tick); } } public static void add(int futureTicks) { - if (futureTicks > 0) { - futureTicks += tick; + if(futureTicks > 0) { int i = 0; - if(listenTicks.isEmpty()) listenTicks.add(i, futureTicks); - else for(int tickCount:listenTicks) { - if(tickCount > tick) { - listenTicks.add(i, futureTicks); - break; + if(listenTicks.isEmpty()) { + listenTicks.add(tick + futureTicks); + return; + } + for(int tickCount:listenTicks) { + if(tickCount > tick + futureTicks) { + listenTicks.add(i, tick + futureTicks); + return; } - if(tickCount == tick) break; + if(tickCount == tick + futureTicks) return; i++; } + listenTicks.add(tick + futureTicks); + } else { - log.fatal("Trying to add a tick in the past to the tick listener"); - throw new RuntimeException("Trying to add a tick in the past to the tick listener"); + log.error("Trying to add a tick in the past to the tick listener: " + futureTicks); + throw new NumberFormatException("Value must be above 0. Value: \"" + futureTicks + "\""); } } @@ -60,10 +64,7 @@ public static void addListener(TickListener listener) { } public static void removeListener(TickListener listener) { - for(TickListener recordedListener:listeners) if(recordedListener == listener) { - listeners.remove(listener); - break; - } + listeners.remove(listener); } public static int current() {