diff --git a/Todo b/Todo new file mode 100644 index 0000000..933dcdd --- /dev/null +++ b/Todo @@ -0,0 +1,12 @@ +todo + commands + set + tap complete for the time args of the + list + all + help + where the commands are explained + info + (about) a game like Lobby/Start/quit pos; state; etc + get what game a stand belongs to + automode -> min/maxplayers; waiting time for players to join - in 2.0 \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 2cdd4e1..521c0cb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "de.greensurvivors" -version = "0.0.2-SNAPSHOT" +version = "1.0.0" description = "lets you find ... things." java { diff --git a/src/main/java/de/greensurvivors/findme/comands/CreateCmd.java b/src/main/java/de/greensurvivors/findme/comands/CreateCmd.java index 274e4af..b7aa03e 100644 --- a/src/main/java/de/greensurvivors/findme/comands/CreateCmd.java +++ b/src/main/java/de/greensurvivors/findme/comands/CreateCmd.java @@ -16,12 +16,14 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; public class CreateCmd { private static final String GAME = "game", HIDEAWAY_LONG = "hideaway", HIDEAWAY_SHORT = "hide", - SIGN = "sign"; + SIGN = "sign", + JOIN = "join", QUIT = "quit"; /** * creates new games, hiding places and join signs */ @@ -67,31 +69,48 @@ public static void handleCmd(CommandSender cs, String[] args) { } //fm c sign case SIGN -> { - if (PermissionUtils.hasPermission(cs, PermissionUtils.FINDME_ADMIN, PermissionUtils.FINDME_CREATE, PermissionUtils.FINDME_CREATE_HIDEAWAY)){ + if (PermissionUtils.hasPermission(cs, PermissionUtils.FINDME_ADMIN, PermissionUtils.FINDME_CREATE, PermissionUtils.FINDME_CREATE_SIGN)){ if (cs instanceof LivingEntity livingEntity){ - Game game = GameManager.inst().getGame(args[2]); + Block block = getSignLookingAt(livingEntity); - if (game != null){ - //set the sign text + //set the sign text + if (block != null){ + Sign sign = (Sign)block.getState(); - Block block = getSignLookingAt(livingEntity); + if (args[2].equalsIgnoreCase(JOIN)){ + if (args.length >= 4) { + Game game = GameManager.inst().getGame(args[3]); - if (block != null){ - Sign sign = (Sign)block.getState(); - sign.line(1, Lang.build(Lang.SIGN_JOIN.get())); - Component component = PlainTextComponentSerializer.plainText().deserialize(game.getName()); - component = component.color(NamedTextColor.GOLD); - sign.line(2, component); + if (game != null) { + sign.line(1, Lang.build(Lang.SIGN_JOIN.get())); - sign.update(); + Component component = PlainTextComponentSerializer.plainText().deserialize(game.getName()); + component = component.color(NamedTextColor.GOLD); + sign.line(2, component); + } else { + //no game by this name exits + cs.sendMessage(Lang.build(Lang.UNKNOWN_GAME.get().replace(Lang.VALUE, args[2]))); + return; + } + } else { + //no game to join was given + cs.sendMessage(Lang.build(Lang.NOT_ENOUGH_ARGS.get())); + return; + } + } else if (args[2].equalsIgnoreCase(QUIT)){ + sign.line(1, Lang.build(Lang.SIGN_QUIT.get())); - cs.sendMessage(Lang.build(Lang.SUCCESSFULLY_CREATED.get().replace(Lang.VALUE, SIGN))); } else { - cs.sendMessage(Lang.build(Lang.NO_SIGN.get())); + //no known signType + cs.sendMessage(Lang.build(Lang.UNKNOWN_ARGUMENT.get().replace(Lang.VALUE, args[2]))); + return; } + + //update sign (else the text won't be shown) & send success message + sign.update(); + cs.sendMessage(Lang.build(Lang.SUCCESSFULLY_CREATED.get().replace(Lang.VALUE, SIGN))); } else { - //no game by this name exits - cs.sendMessage(Lang.build(Lang.UNKNOWN_GAME.get().replace(Lang.VALUE, args[2]))); + cs.sendMessage(Lang.build(Lang.NO_SIGN.get())); } } else { //no location of cs @@ -106,6 +125,8 @@ public static void handleCmd(CommandSender cs, String[] args) { cs.sendMessage(Lang.build(Lang.UNKNOWN_ARGUMENT.get().replace(Lang.VALUE, args[1]))); } } + } else { + cs.sendMessage(Lang.build(Lang.NOT_ENOUGH_ARGS.get())); } } @@ -127,10 +148,21 @@ public static List handleTap(CommandSender cs, String[] args) { return result.stream().filter(s -> s.toLowerCase().startsWith(args[1])).collect(Collectors.toList()); } case 3 -> { - if (args[1].equalsIgnoreCase(HIDEAWAY_LONG) || args[1].equalsIgnoreCase(HIDEAWAY_SHORT) || args[1].equalsIgnoreCase(SIGN)){ - if (PermissionUtils.hasPermission(cs, PermissionUtils.FINDME_ADMIN, PermissionUtils.FINDME_CREATE, PermissionUtils.FINDME_CREATE_SIGN, PermissionUtils.FINDME_CREATE_HIDEAWAY)){ + if (args[1].equalsIgnoreCase(HIDEAWAY_LONG) || args[1].equalsIgnoreCase(HIDEAWAY_SHORT)){ + if (PermissionUtils.hasPermission(cs, PermissionUtils.FINDME_ADMIN, PermissionUtils.FINDME_CREATE, PermissionUtils.FINDME_CREATE_HIDEAWAY)){ return GameManager.inst().getGameNames().stream().filter(s -> s.toLowerCase().startsWith(args[2])).collect(Collectors.toList()); } + } else if (args[1].equalsIgnoreCase(SIGN)){ + if (PermissionUtils.hasPermission(cs, PermissionUtils.FINDME_ADMIN, PermissionUtils.FINDME_CREATE_SIGN)){ + return Stream.of(JOIN, QUIT).filter(s -> s.toLowerCase().startsWith(args[2])).collect(Collectors.toList()); + } + } + } + case 4 -> { + if (args[1].equalsIgnoreCase(SIGN) && args[2].equalsIgnoreCase(JOIN)){ + if (PermissionUtils.hasPermission(cs, PermissionUtils.FINDME_ADMIN, PermissionUtils.FINDME_CREATE_SIGN)){ + return GameManager.inst().getGameNames().stream().filter(s -> s.toLowerCase().startsWith(args[3])).collect(Collectors.toList()); + } } } } @@ -139,7 +171,7 @@ public static List handleTap(CommandSender cs, String[] args) { /** * Get location of a sign a living entity is looking at. * @param entity looking at a sign - * @return location of sign, or null if the entity is not looking at a sign + * @return block of sign, or null if the entity is not looking at a sign */ private static Block getSignLookingAt(LivingEntity entity) { // player is looking at a sign diff --git a/src/main/java/de/greensurvivors/findme/comands/FindMeCommands.java b/src/main/java/de/greensurvivors/findme/comands/FindMeCommands.java index a02142a..2b1fdf5 100644 --- a/src/main/java/de/greensurvivors/findme/comands/FindMeCommands.java +++ b/src/main/java/de/greensurvivors/findme/comands/FindMeCommands.java @@ -105,11 +105,6 @@ private void handle(CommandSender cs, String[] args) { } @Override - //get what game a stand belongs to - //todo quit sign - //info (about) a game -> Lobby/Start/quit pos; state; etc - //automode -> min/maxplayers; waiting time for players to join - //kann nicht in die Lobby porten wenn nicht geladen public List onTabComplete(@NotNull CommandSender cs, @NotNull Command cmd, @NotNull String label, String[] args) { if (args.length == 1) { List result = new ArrayList<>(); diff --git a/src/main/java/de/greensurvivors/findme/comands/HelpCmd.java b/src/main/java/de/greensurvivors/findme/comands/HelpCmd.java index 2d027b0..4c23045 100644 --- a/src/main/java/de/greensurvivors/findme/comands/HelpCmd.java +++ b/src/main/java/de/greensurvivors/findme/comands/HelpCmd.java @@ -8,8 +8,6 @@ import static de.greensurvivors.findme.PermissionUtils.hasPermission; public class HelpCmd { - //todo make help where the commands are explained - /** * Handle help command * @param cs CommandSender diff --git a/src/main/java/de/greensurvivors/findme/comands/ListCmd.java b/src/main/java/de/greensurvivors/findme/comands/ListCmd.java index 8bc91be..b3621e4 100644 --- a/src/main/java/de/greensurvivors/findme/comands/ListCmd.java +++ b/src/main/java/de/greensurvivors/findme/comands/ListCmd.java @@ -14,7 +14,7 @@ public class ListCmd { //list all games * @param cs * @param args */ - public static void handleCmd(CommandSender cs, String[] args) { //todo + public static void handleCmd(CommandSender cs, String[] args) { if (PermissionUtils.hasPermission(cs, PermissionUtils.FINDME_ADMIN, PermissionUtils.FINDME_LIST)){ cs.sendMessage("list"); for (String name : GameManager.inst().getGameNames()){ diff --git a/src/main/java/de/greensurvivors/findme/comands/SetCmd.java b/src/main/java/de/greensurvivors/findme/comands/SetCmd.java index 5621837..8f5974c 100644 --- a/src/main/java/de/greensurvivors/findme/comands/SetCmd.java +++ b/src/main/java/de/greensurvivors/findme/comands/SetCmd.java @@ -248,7 +248,6 @@ public static void handleCmd(CommandSender cs, String[] args) { } } - //todo tap complete for the time args public static List handleTap(CommandSender cs, String[] args) { switch (args.length){ case 2 -> { diff --git a/src/main/java/de/greensurvivors/findme/dataObjects/Game.java b/src/main/java/de/greensurvivors/findme/dataObjects/Game.java index fb06fa6..3c8f289 100644 --- a/src/main/java/de/greensurvivors/findme/dataObjects/Game.java +++ b/src/main/java/de/greensurvivors/findme/dataObjects/Game.java @@ -171,6 +171,9 @@ private Game(Scoreboard scoreboard, Team noCollisionTeam, objective.setDisplaySlot(DisplaySlot.SIDEBAR); noCollisionTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER); + + //save a potential new entity of the hideaway list or a new version of serialization of future updates + MainConfig.inst().saveGame(this); } /** @@ -275,12 +278,14 @@ public static Game deserialize(@NotNull Map data) { } hideaways_.put(hideaway.getUUIDSlime(), hideaway); + hideaway.gotSlimeUpdate(); } else if (obj instanceof MemorySection memorySection){ Hideaway hideaway = Hideaway.deserialize(memorySection.getValues(false), noCollisionTeam_); if (hideaway == null){ break; } hideaways_.put(hideaway.getUUIDSlime(), hideaway); + hideaway.gotSlimeUpdate(); } else { GreenLogger.log(Level.WARNING, "couldn't deserialize hidden stand: " + obj + ", skipping. Reason: unknown type."); } @@ -432,6 +437,7 @@ public static Game deserialize(@NotNull Map data) { public void addHideaway(@NotNull Location location){ Hideaway hideaway = new Hideaway(location, name, noCollisionTeam); hideaways.put(hideaway.getUUIDSlime(), hideaway); + hideaway.gotSlimeUpdate(); MainConfig.inst().saveGame(this); } @@ -443,10 +449,17 @@ public void addHideaway(@NotNull Location location){ */ public void showAroundLocation(@NotNull Location location, int range){ World world = location.getWorld(); + Set updatedHideaways = new HashSet<>(); for (Hideaway hideaway : hideaways.values()){ - if (hideaway.getSlime() != null){ - Location hidingLoc = hideaway.getSlime().getLocation(); + Slime slime = hideaway.getSlime(); + + if (slime != null){ + if (hideaway.isSlimeUpdated()){ + updatedHideaways.add(hideaway); + } + + Location hidingLoc = slime.getLocation(); if (world != hidingLoc.getWorld()) continue; @@ -457,10 +470,21 @@ public void showAroundLocation(@NotNull Location location, int range){ hideaway.getSlime().setGlowing(true); Bukkit.getScheduler().runTaskLater(FindMe.inst(), () -> - hideaway.getSlime().setGlowing(false), 200); + slime.setGlowing(false), 400); } } } + + //update the uuids + for (Hideaway hideaway : updatedHideaways){ + hideaways.entrySet().removeIf(entry -> entry.getValue() == hideaway); + hideaways.put(hideaway.getUUIDSlime(), hideaway); + + hideaway.gotSlimeUpdate(); + } + if (updatedHideaways.size() > 0){ + MainConfig.inst().saveGame(this); + } } /** @@ -473,11 +497,14 @@ public void showAroundLocation(@NotNull Location location, int range){ double lastDistance = Double.MAX_VALUE; Collection nearbySlimes = startingPos.getNearbyEntitiesByType(Slime.class, 5); + Set nearbyHidingPlaces = nearbySlimes.stream(). //get all tracked slimes that are in radius map(s -> hideaways.get(s.getUniqueId())).filter(Objects::nonNull). collect(Collectors.toSet()); + HashSet updatedHideaways = new HashSet<>(); + for(Hideaway hideaway : nearbyHidingPlaces) { //we don't need the root, if we only want to know what entity is further //also, hideaway.getSlime is backed up by getting the initial slimes from getNearbyEntitiesByType, @@ -487,6 +514,21 @@ public void showAroundLocation(@NotNull Location location, int range){ lastDistance = distance; result = hideaway; } + + if (hideaway.isSlimeUpdated()){ + updatedHideaways.add(hideaway); + } + } + + //update the uuids + for (Hideaway hideaway : updatedHideaways){ + hideaways.entrySet().removeIf(entry -> entry.getValue() == hideaway); + hideaways.put(hideaway.getUUIDSlime(), hideaway); + + hideaway.gotSlimeUpdate(); + } + if (updatedHideaways.size() > 0){ + MainConfig.inst().saveGame(this); } return result; @@ -573,8 +615,6 @@ protected void playerJoin(@NotNull Player player){ GreenLogger.log(Level.WARNING, "No start postion was given for FindMe! game \"" + name + "\". Couldn't teleport anybody."); } } else { - GreenLogger.log(Level.INFO, "player " + player.getName() + " joined idle game " + name); - if (lobbyLoc != null){ GameManager.inst().addTeleportingPlayer(player); @@ -665,6 +705,8 @@ private void GameTimer(){ } } + HashSet updatedHideaways = new HashSet<>(); + //hide new stuff in hidden stands, if they are not in cooldown //only try to hide if we have heads to begin with final int numOfHeads = heads.size(); @@ -675,15 +717,35 @@ private void GameTimer(){ for (Hideaway hideaway : hideaways.values()){ if (hideaway.getArmorStand() != null) { - - if (!hideaway.hasHead() && - hideaway.isCooldownOver(HideCooldownMillis) && - random.nextLong(averageHideTicks) == 1){ + if (hideaway.hasHead()){ + //make sure the slime didn't despawn and is still nice and updated + hideaway.getSlime(); + if (hideaway.isSlimeUpdated()){ + updatedHideaways.add(hideaway); + } + } else if (hideaway.isCooldownOver(HideCooldownMillis) && random.nextLong(averageHideTicks) == 1){ hideaway.setHasHead(true); hideaway.getArmorStand().setItem(EquipmentSlot.HEAD, headArray[random.nextInt(numOfHeads)]); + + //make sure the slime didn't despawn and is still nice and updated + hideaway.getSlime(); + if (hideaway.isSlimeUpdated()){ + updatedHideaways.add(hideaway); + } } } } + + //update the uuids + for (Hideaway hideaway : updatedHideaways){ + hideaways.entrySet().removeIf(entry -> entry.getValue() == hideaway); + hideaways.put(hideaway.getUUIDSlime(), hideaway); + + hideaway.gotSlimeUpdate(); + } + if (updatedHideaways.size() > 0){ + MainConfig.inst().saveGame(this); + } } //next game tick or end of game @@ -998,4 +1060,5 @@ public int getNumOfPlayers(){ public int getNumOfHeads(){ return heads.size(); } + } diff --git a/src/main/java/de/greensurvivors/findme/dataObjects/Hideaway.java b/src/main/java/de/greensurvivors/findme/dataObjects/Hideaway.java index 87ba0a1..99b237c 100644 --- a/src/main/java/de/greensurvivors/findme/dataObjects/Hideaway.java +++ b/src/main/java/de/greensurvivors/findme/dataObjects/Hideaway.java @@ -43,7 +43,10 @@ public class Hideaway implements ConfigurationSerializable { private boolean hasHead = false; private long cooldown = 0; + private boolean slimeUpdated = false; + private Slime summonSlime(@NotNull Location location, @NotNull String gameName){ + slimeUpdated = true; //get uuid and set all necessary properties of a freshly spawned slime //in other news: the settings are set with a lambda function, so no slime should ever flash for a moment. return location.getWorld().spawn(location, Slime.class, newSlime-> { @@ -95,7 +98,7 @@ public Hideaway(@NotNull Location location, @NotNull String gameName, @NotNull T summonArmorStand(location, gameName); } - public Hideaway(@NotNull UUID uuid_armorstand, @NotNull UUID uuid_slime, @NotNull Team noCollistionTeam){ + private Hideaway(@NotNull UUID uuid_armorstand, @NotNull UUID uuid_slime, @NotNull Team noCollistionTeam){ this.noCollistionTeam = noCollistionTeam; this.uuid_armorstand = uuid_armorstand; this.uuid_slime = uuid_slime; @@ -244,4 +247,16 @@ public boolean hasHead() { public void setHasHead(boolean hasHead) { this.hasHead = hasHead; } + + public boolean isSlimeUpdated() { + return slimeUpdated; + } + + /** + * gives feedback that the uuid change of the slime was reflected in the tracking map + * it's serves no functional purpose but helps to detect and correct errors. + */ + protected void gotSlimeUpdate() { + slimeUpdated = false; + } } diff --git a/src/main/java/de/greensurvivors/findme/language/Lang.java b/src/main/java/de/greensurvivors/findme/language/Lang.java index 6993beb..9f2b82f 100644 --- a/src/main/java/de/greensurvivors/findme/language/Lang.java +++ b/src/main/java/de/greensurvivors/findme/language/Lang.java @@ -20,6 +20,7 @@ public enum Lang implements Cons { ENDING_GAME(String.format("&2Ending game %s.", VALUE)), SIGN_JOIN("&2[join fm]"), + SIGN_QUIT("&2[quit fm]"), GAME_ALREADY_ACTIVE("The game is already active."), GAME_ALREADY_EXISTS(String.format("&cThe game &6'&e%s&6'&c already exists.", VALUE)), diff --git a/src/main/java/de/greensurvivors/findme/listener/SignListener.java b/src/main/java/de/greensurvivors/findme/listener/SignListener.java index 5192bdb..b7c4b03 100644 --- a/src/main/java/de/greensurvivors/findme/listener/SignListener.java +++ b/src/main/java/de/greensurvivors/findme/listener/SignListener.java @@ -75,6 +75,16 @@ private void onSignRightClick(PlayerInteractEvent event){ if (!foundGame){ ePlayer.sendMessage(Lang.build(Lang.UNKNOWN_GAME.get().replace(Lang.VALUE, line3))); } + + } else if (Lang.SIGN_QUIT.get().equalsIgnoreCase(LegacyComponentSerializer.legacyAmpersand().serialize(sign.line(1)))){ + Game gameOfPlayer = GameManager.inst().getGameOfPlayer(ePlayer); + if (gameOfPlayer != null){ + GameManager.inst().playerQuitGame(ePlayer, gameOfPlayer); + + ePlayer.sendMessage(Lang.build(Lang.QUIT_SELF.get())); + } else { + ePlayer.sendMessage(Lang.build(Lang.NOT_IN_GAME.get())); + } } } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 22e1b84..dafa479 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: FindMe -version: 0.0.2-SNAPSHOT +version: 1.0.0 main: de.greensurvivors.findme.FindMe api-version: 1.19 authors: [ Feuerreiter ]