From a56513d85180c699b566783d7e1ce1f12d641aa4 Mon Sep 17 00:00:00 2001 From: Myles Date: Sat, 10 Dec 2022 01:23:40 -0600 Subject: 1AM COMMIT LETS GOOOO - fixed about 20 bugs, glitches, exploits, you name it--Jacob can break anything (not even joking, did my first *real* playtest; it was...valuable...we'll leave it at that) - added some sort of block balancing (want to improve on it later maybe?) - change the prefix back to lowercase because we're emo or something (COMMONALITY SHUT UP) - game env is now more controlled (thanks Jacob) - can I go to bed now --- README.md | 2 +- .../com/MylesAndMore/tumble/EventListener.java | 120 +++++++++++++++++---- src/main/java/com/MylesAndMore/tumble/Game.java | 40 ++++++- src/main/java/com/MylesAndMore/tumble/Main.java | 10 +- .../tumble/commands/SetWorldConfig.java | 1 + src/main/resources/config.yml | 2 +- 6 files changed, 142 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index e3135c0..e0d0663 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ once this list is complete and all bugs are fixed, we *should* be ready for rele - [x] make the shovel in shovels mode not lose any durabilty - [x] make it so that you can't move until the game begins -- [ ] make the game blocks breakable very fast, but **not instantly--very important for balancing!!** +- [x] make the game blocks breakable very fast, but **not instantly--very important for balancing!!** - Basically, just set a "cooldown" on both snowballs and shovels--not a long one--but one at that - [ ] add infinite snowballs in the gamemanager for tumble mode - [x] make it so that you can't remove any of the game items from your inventory diff --git a/src/main/java/com/MylesAndMore/tumble/EventListener.java b/src/main/java/com/MylesAndMore/tumble/EventListener.java index dd42ea2..a18a9d3 100644 --- a/src/main/java/com/MylesAndMore/tumble/EventListener.java +++ b/src/main/java/com/MylesAndMore/tumble/EventListener.java @@ -4,14 +4,15 @@ import java.util.Objects; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.entity.Snowball; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.entity.FoodLevelChangeEvent; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.entity.ProjectileHitEvent; -import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockDropItemEvent; +import org.bukkit.event.entity.*; import org.bukkit.event.player.*; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; @@ -105,20 +106,18 @@ public class EventListener implements Listener { } @EventHandler - public void ItemDamageEvent(PlayerItemDamageEvent event) { + public void PlayerItemDamageEvent(PlayerItemDamageEvent event) { if (TumbleManager.getGameWorld() == null) { return; } - // On a BlockBreakEvent, - // check to see if the block was broken in the gameWorld, + // On an ItemDamageEvent + // check to see if the item was damaged in the gameWorld, if (event.getPlayer().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { - // If it was in the gameWorld, check if the roundType was shovels - if (Objects.equals(Game.getGame().getRoundType(), "shovels")) { - event.setCancelled(true); - } + event.setCancelled(true); } } + private long lastTimeP; @EventHandler public void ProjectileLaunchEvent(ProjectileLaunchEvent event) { if (TumbleManager.getGameWorld() == null) { @@ -129,7 +128,22 @@ public class EventListener implements Listener { if (event.getEntity().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { if (event.getEntity() instanceof Snowball) { if (event.getEntity().getShooter() instanceof Player player) { - player.getInventory().addItem(new ItemStack(Material.SNOWBALL, 1)); + // Check to see if the last snowball was thrown less than 200ms ago, if so, don't allow another + if ((System.currentTimeMillis() - lastTimeP) < 200) { event.setCancelled(true); } + else { + // Otherwise, continue with logic + lastTimeP = System.currentTimeMillis(); + // This prevents players from shooting snowballs before the game actually begins + if (Objects.equals(Game.getGame().getGameState(), "starting")) { + event.setCancelled(true); + } + else { + // This gives players a snowball when they've used one + Bukkit.getServer().getScheduler().runTask(TumbleManager.getPlugin(), () -> { + player.getInventory().addItem(new ItemStack(Material.SNOWBALL, 1)); + }); + } + } } } } @@ -140,6 +154,10 @@ public class EventListener implements Listener { if (TumbleManager.getGameWorld() == null) { return; } + // Weird stacktrace thing + else if (event.getHitBlock() == null) { + return; + } // When a projectile hits // check to see if the projectile hit in the gameWorld, if (event.getHitBlock().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { @@ -151,8 +169,8 @@ public class EventListener implements Listener { if (event.getHitBlock() != null) { // if it was a block, check if that block is within the game area, if (event.getHitBlock().getLocation().distanceSquared(Bukkit.getWorld(TumbleManager.getGameWorld()).getSpawnLocation()) < 402) { - // then remove that block. - event.getHitBlock().setType(Material.AIR); + // then remove that block. + event.getHitBlock().setType(Material.AIR); } } else if (event.getHitEntity() != null) { @@ -161,15 +179,11 @@ public class EventListener implements Listener { // then cancel the knockback (has to be delayed by a tick for some reason) Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(TumbleManager.getPlugin(), () -> { hitPlayer.setVelocity(new Vector()); - }, 1); + }); } } } } - // Weird stacktrace thing - else if (event.getHitBlock().getWorld() == null) { - event.setCancelled(true); - } } } @@ -187,10 +201,58 @@ public class EventListener implements Listener { @EventHandler public void PlayerMoveEvent(PlayerMoveEvent event) { + if (TumbleManager.getGameWorld() == null) { + return; + } // On a PlayerMoveEvent, check if the game is starting if (Objects.equals(Game.getGame().getGameState(), "starting")) { - // Cancel the event if the game is starting (so players can't move before the - // game starts) + // Cancel the event if the game is starting (so players can't move before the game starts) + event.setCancelled(true); + } + } + + @EventHandler + public void BlockDropItemEvent(BlockDropItemEvent event) { + if (TumbleManager.getGameWorld() == null) { + return; + } + // If a block was going to drop an item (ex. snow dropping snowballs) in the GameWorld, cancel it + if (event.getBlock().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { + event.setCancelled(true); + } + } + + private long lastTimeI; + @EventHandler + public void PlayerInteractEvent(PlayerInteractEvent event) { + if (TumbleManager.getGameWorld() == null) { + return; + } + // Check if a player was left clicking a block in the gameWorld + if (event.getAction() == Action.LEFT_CLICK_BLOCK) { + if (event.getClickedBlock().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { + // Then check if it was with an item enchanted w/ silk touch + if (event.getPlayer().getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH)) { + // Then check to see if the player interacted less than 150ms ago + if ((System.currentTimeMillis() - lastTimeI) < 150) return; + // If not, set that block to air (break it) + else { + lastTimeI = System.currentTimeMillis(); + event.getClickedBlock().setType(Material.AIR); + } + } + } + } + } + + @EventHandler + public void BlockBreakEvent(BlockBreakEvent event) { + if (TumbleManager.getGameWorld() == null) { + return; + } + // This just doesn't allow blocks to break in the gameWorld; the PlayerInteractEvent will take care of everything + // It just keeps client commonality w/ animations and stuff + if (event.getBlock().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { event.setCancelled(true); } } @@ -200,10 +262,22 @@ public class EventListener implements Listener { if (TumbleManager.getGameWorld() == null) { return; } - // When someone's food level changes - // check if that happened in the gameWorld + // When someone's food level changes, check if that happened in the gameWorld, then cancel it if (event.getEntity().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { event.setCancelled(true); } } + + @EventHandler + public void EntityDamageEvent(EntityDamageEvent event) { + if (TumbleManager.getGameWorld() == null) { + return; + } + // Check to see if a player got damaged in the gameWorld, if so, cancel it + if (event.getEntity().getWorld() == Bukkit.getWorld(TumbleManager.getGameWorld())) { + if (event.getEntity() instanceof Player) { + event.setCancelled(true); + } + } + } } diff --git a/src/main/java/com/MylesAndMore/tumble/Game.java b/src/main/java/com/MylesAndMore/tumble/Game.java index 6d085df..7de988a 100644 --- a/src/main/java/com/MylesAndMore/tumble/Game.java +++ b/src/main/java/com/MylesAndMore/tumble/Game.java @@ -6,6 +6,7 @@ import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.*; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -78,6 +79,8 @@ public class Game { gameState = "starting"; // Set the roundType to gameType since it won't change for this mode roundType = type; + // Clear the players' inventories so they can't bring any items into the game + clearInventories(TumbleManager.getPlayersInLobby()); // Generate the correct layers for a Shovels game // The else statement is just in case the generator fails; this command will fail if (generateLayers(type)) { @@ -92,6 +95,7 @@ public class Game { else if (Objects.equals(type, "snowballs")) { gameState = "starting"; roundType = type; + clearInventories(TumbleManager.getPlayersInLobby()); if (generateLayers(type)) { scatterPlayers(TumbleManager.getPlayersInLobby()); } @@ -102,6 +106,7 @@ public class Game { else if (Objects.equals(type, "mixed")) { gameState = "starting"; roundType = type; + clearInventories(TumbleManager.getPlayersInLobby()); if (generateLayers(type)) { scatterPlayers(TumbleManager.getPlayersInLobby()); } @@ -187,7 +192,7 @@ public class Game { // Otherwise, the game must have two people left (and one just died), meaning it is over // This logic is so that it will not remove the last player standing from the list, so we know who the winner is. else { - // roundPlayers.remove(player); + roundPlayers.remove(player); // End the game, passing the winner to the gameEnd method roundEnd(roundPlayers.get(0)); } @@ -229,11 +234,19 @@ public class Game { Generator.generateLayer(layer, 13, 1, Material.AIR); layer.setY(layer.getY() - 1); Generator.generateLayer(layer, 13, 1, Material.GRASS_BLOCK); + Generator.generateLayer(layer, 4, 1, Material.AIR); layer.setY(layer.getY() - 1); Generator.generateLayer(layer, 4, 1, Material.PODZOL); layer.setY(layer.getY() + 2); Generator.generateLayer(layer, 4, 2, Material.TALL_GRASS); - giveItems(TumbleManager.getPlayersInLobby(), new ItemStack(Material.IRON_SHOVEL)); + ItemStack shovel = new ItemStack(Material.IRON_SHOVEL); + shovel.addEnchantment(Enchantment.SILK_TOUCH, 1); + if (Objects.equals(gameState, "running")) { + giveItems(TumbleManager.getPlayersInGame(), shovel); + } + else if (Objects.equals(gameState, "starting")) { + giveItems(TumbleManager.getPlayersInLobby(), shovel); + } } else if (Objects.equals(type, "snowballs")) { layer.setY(layer.getY() - 1); @@ -244,7 +257,12 @@ public class Game { Generator.generateLayer(layer, 4, 1, Material.AIR); layer.setY(layer.getY() - 1); Generator.generateLayer(layer, 4, 1, Material.LIME_GLAZED_TERRACOTTA); - giveItems(TumbleManager.getPlayersInLobby(), new ItemStack(Material.SNOWBALL)); + if (Objects.equals(gameState, "running")) { + giveItems(TumbleManager.getPlayersInGame(), new ItemStack(Material.SNOWBALL)); + } + else if (Objects.equals(gameState, "starting")) { + giveItems(TumbleManager.getPlayersInLobby(), new ItemStack(Material.SNOWBALL)); + } } else if (Objects.equals(type, "mixed")) { // Randomly select either shovels or snowballs and re-run the method @@ -273,6 +291,16 @@ public class Game { } } + /** + * Clears the inventories of a provided player list + * @param players The player list for which to clear the inventories of + */ + private void clearInventories(List players) { + for (Player aPlayer : players) { + aPlayer.getInventory().clear(); + } + } + /** * Sets the gamemodes of a provided list of players * @param players The player list for which to set the gamemodes of @@ -370,6 +398,10 @@ public class Game { } // If that player doesn't have three wins, nobody else does, so we need another round else { + roundPlayers.get(0).setGameMode(GameMode.SPECTATOR); + roundPlayers.remove(0); + roundPlayers.addAll(gamePlayers); + clearInventories(gamePlayers); displayTitles(gamePlayers, ChatColor.RED + "Round over!", ChatColor.GOLD + winner.getName() + " has won the round!", 5, 60, 5); // Re-generate layers generateLayers(roundType); @@ -399,6 +431,8 @@ public class Game { } private void gameEnd(Player winner) { + winner.setGameMode(GameMode.SPECTATOR); + clearInventories(gamePlayers); // Announce win displayTitles(gamePlayers, ChatColor.RED + "Game over!", ChatColor.GOLD + winner.getName() + " has won the game!", 5, 60, 5); displayActionbar(gamePlayers, ChatColor.BLUE + "Returning to lobby in ten seconds..."); diff --git a/src/main/java/com/MylesAndMore/tumble/Main.java b/src/main/java/com/MylesAndMore/tumble/Main.java index a35a519..16f32c4 100644 --- a/src/main/java/com/MylesAndMore/tumble/Main.java +++ b/src/main/java/com/MylesAndMore/tumble/Main.java @@ -25,15 +25,15 @@ public class Main extends JavaPlugin{ // Check if worlds are null in config if (TumbleManager.getGameWorld() == null) { - Bukkit.getServer().getLogger().warning("[Tumble] It appears you have not configured a game world for Tumble."); - Bukkit.getServer().getLogger().info("[Tumble] If this is your first time running the plugin, you may disregard this message."); + Bukkit.getServer().getLogger().warning("[tumble] It appears you have not configured a game world for Tumble."); + Bukkit.getServer().getLogger().info("[tumble] If this is your first time running the plugin, you may disregard this message."); } if (TumbleManager.getLobbyWorld() == null) { - Bukkit.getServer().getLogger().warning("[Tumble] It appears you have not configured a lobby world for Tumble."); - Bukkit.getServer().getLogger().info("[Tumble] If this is your first time running the plugin, you may disregard this message."); + Bukkit.getServer().getLogger().warning("[tumble] It appears you have not configured a lobby world for Tumble."); + Bukkit.getServer().getLogger().info("[tumble] If this is your first time running the plugin, you may disregard this message."); } // Init message - Bukkit.getServer().getLogger().info("[Tumble] Tumble initialization complete!"); + Bukkit.getServer().getLogger().info("[tumble] Tumble initialization complete!"); } } \ No newline at end of file diff --git a/src/main/java/com/MylesAndMore/tumble/commands/SetWorldConfig.java b/src/main/java/com/MylesAndMore/tumble/commands/SetWorldConfig.java index 74eaf0d..695c248 100644 --- a/src/main/java/com/MylesAndMore/tumble/commands/SetWorldConfig.java +++ b/src/main/java/com/MylesAndMore/tumble/commands/SetWorldConfig.java @@ -52,6 +52,7 @@ public class SetWorldConfig implements CommandExecutor { TumbleManager.getPlugin().saveConfig(); // Set the gamerule of doImmediateRespawn in the gameWorld for later Bukkit.getWorld(world).setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true); + Bukkit.getWorld(world).setGameRule(GameRule.KEEP_INVENTORY, true); sender.sendMessage(ChatColor.GREEN + "Game world successfully linked: " + ChatColor.GRAY + world); sender.sendMessage(ChatColor.GREEN + "Please restart your server for the changes to take effect; " + ChatColor.RED + "reloading the plugin is insufficient!"); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 6a9f62d..bc68c35 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,5 @@ # Hides join/leave messages in public chat -# Default is true +# Default is false hideJoinLeaveMessages: false # Customize the message that displays when the player does not have permission to execute a command from this plugin -- cgit v1.2.3