diff --git a/anticheat/src/main/java/net/swofty/anticheat/engine/SwoftyPlayer.java b/anticheat/src/main/java/net/swofty/anticheat/engine/SwoftyPlayer.java index 113d3eef5..d8c3cee73 100644 --- a/anticheat/src/main/java/net/swofty/anticheat/engine/SwoftyPlayer.java +++ b/anticheat/src/main/java/net/swofty/anticheat/engine/SwoftyPlayer.java @@ -87,7 +87,7 @@ public int ticksSinceLastPingResponse() { public void sendPingRequest() { // Between 1 and 50000000 - int randomId = new Random().nextInt(50000000) + 1; + int randomId = java.util.concurrent.ThreadLocalRandom.current().nextInt(50000000) + 1; PingRequest request = new PingRequest(randomId); pingRequests.offerLast(request); diff --git a/anticheat/src/main/java/net/swofty/anticheat/math/ChunkUtils.java b/anticheat/src/main/java/net/swofty/anticheat/math/ChunkUtils.java index b1af7900d..895d59db1 100644 --- a/anticheat/src/main/java/net/swofty/anticheat/math/ChunkUtils.java +++ b/anticheat/src/main/java/net/swofty/anticheat/math/ChunkUtils.java @@ -1,6 +1,11 @@ package net.swofty.anticheat.math; -public class ChunkUtils { +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ChunkUtils { + public static int getChunkCoordinate(double xz) { return getChunkCoordinate((int) Math.floor(xz)); } diff --git a/build.gradle.kts b/build.gradle.kts index f80468c61..1034ffc3e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,8 @@ -import org.gradle.api.artifacts.VersionCatalog -import org.gradle.api.artifacts.VersionCatalogsExtension -import org.gradle.kotlin.dsl.getByType - plugins { base java - id("io.freefair.lombok") version "9.1.0" - id("io.sentry.jvm.gradle") version "5.12.2" + id("io.freefair.lombok") version "9.1.0" apply false + id("io.sentry.jvm.gradle") version "6.4.0" apply false } group = "net.swofty" diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index 828815d35..5dc94206e 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { // Must match AtlasRedisAPI's Jedis version to avoid conflicts implementation(libs.jedis) + implementation(libs.atlas.redis) implementation(libs.configlib.yaml) diff --git a/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java b/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java index cb7ae1bf5..ccfbbf17e 100644 --- a/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java +++ b/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java @@ -138,6 +138,8 @@ public enum ItemType { ATTACK_SPEED_ENRICHMENT(Material.PLAYER_HEAD, Rarity.COMMON), + AUGER_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + AUTOPET_RULES_2_PACK(Material.PLAYER_HEAD, Rarity.SPECIAL), AUTO_RECOMBOBULATOR(Material.PLAYER_HEAD, Rarity.COMMON), @@ -318,6 +320,8 @@ public enum ItemType { BLAZE_ROD_DISTILLATE(Material.PLAYER_HEAD, Rarity.RARE), + BLESSED_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + BLOCK_DATA_TOOL(Material.DEBUG_STICK, Rarity.ADMIN), BLOCK_ZAPPER(Material.FLINT, Rarity.COMMON), @@ -402,8 +406,50 @@ public enum ItemType { BROKEN_RADAR(Material.PLAYER_HEAD, Rarity.UNCOMMON), + BRONZE_BLOBFISH(Material.PLAYER_HEAD, Rarity.COMMON), + BRONZE_BOWL(Material.PLAYER_HEAD, Rarity.UNCOMMON), + BRONZE_FLYFISH(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_GOLDEN_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_GUSHER(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_KARATE_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_LAVAHORSE(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_MANA_RAY(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_MOLDFIN(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_OBFUSCATED_1(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_OBFUSCATED_2(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_OBFUSCATED_3(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_SHIP_ENGINE(Material.PLAYER_HEAD, Rarity.RARE), + + BRONZE_SHIP_HELM(Material.PLAYER_HEAD, Rarity.RARE), + + BRONZE_SHIP_HULL(Material.PLAYER_HEAD, Rarity.RARE), + + BRONZE_SKELETON_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_SLUGFISH(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_SOUL_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_STEAMING_HOT_FLOUNDER(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_SULPHUR_SKITTER(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_VANILLE(Material.PLAYER_HEAD, Rarity.COMMON), + + BRONZE_VOLCANIC_STONEFISH(Material.PLAYER_HEAD, Rarity.COMMON), + BROWN_BANNER(Material.BROWN_BANNER, Rarity.COMMON), BROWN_BED(Material.BROWN_BED, Rarity.COMMON), @@ -520,6 +566,8 @@ public enum ItemType { CARROT(Material.CARROT, Rarity.COMMON), + CARROT_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + CARROT_CRYSTAL(Material.PLAYER_HEAD, Rarity.COMMON), CARROT_MINION(Material.PLAYER_HEAD, Rarity.COMMON), @@ -552,8 +600,12 @@ public enum ItemType { CHAINMAIL_LEGGINGS(Material.CHAINMAIL_LEGGINGS, Rarity.COMMON), + CHALLENGE_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + CHAMPION(Material.ENCHANTED_BOOK, Rarity.COMMON), + CHAMP_ROD(Material.FISHING_ROD, Rarity.RARE), + CHARCOAL(Material.CHARCOAL, Rarity.COMMON), CHARLIE_TROUSERS(Material.LEATHER_LEGGINGS, Rarity.COMMON), @@ -622,6 +674,10 @@ public enum ItemType { CHUM(Material.PLAYER_HEAD, Rarity.UNCOMMON), + CHUM_ROD(Material.FISHING_ROD, Rarity.RARE), + + CHUM_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + CLAY_BALL(Material.CLAY_BALL, Rarity.COMMON), CLAY_MINION(Material.PLAYER_HEAD, Rarity.COMMON), @@ -656,6 +712,8 @@ public enum ItemType { COMBAT_EXP_BOOST(Material.IRON_SWORD, Rarity.COMMON), + COMMON_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + COMPACT(Material.ENCHANTED_BOOK, Rarity.COMMON), COMPACTED_MOONFLOWER(Material.BLUE_ORCHID, Rarity.COMMON), @@ -680,6 +738,8 @@ public enum ItemType { CORNFLOWER(Material.CORNFLOWER, Rarity.COMMON), + CORRUPTED_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + COW_MINION(Material.PLAYER_HEAD, Rarity.COMMON), CRACKED_PIGGY_BANK(Material.PLAYER_HEAD, Rarity.UNCOMMON), @@ -772,6 +832,8 @@ public enum ItemType { DANDELION(Material.DANDELION, Rarity.COMMON), + DARK_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + DARK_OAK_BOAT(Material.DARK_OAK_BOAT, Rarity.COMMON), DARK_OAK_BUTTON(Material.DARK_OAK_BUTTON, Rarity.COMMON), @@ -874,32 +936,68 @@ public enum ItemType { DIAMOND_AXE(Material.DIAMOND_AXE, Rarity.COMMON), + DIAMOND_BLOBFISH(Material.PLAYER_HEAD, Rarity.COMMON), + DIAMOND_BLOCK(Material.DIAMOND_BLOCK, Rarity.COMMON), - DIAMOND_BOOTS(Material.DIAMOND_BOOTS, Rarity.RARE), + DIAMOND_BOOTS(Material.DIAMOND_BOOTS, Rarity.COMMON), + + DIAMOND_CHESTPLATE(Material.DIAMOND_CHESTPLATE, Rarity.COMMON), + + DIAMOND_FLYFISH(Material.PLAYER_HEAD, Rarity.COMMON), - DIAMOND_CHESTPLATE(Material.DIAMOND_CHESTPLATE, Rarity.RARE), + DIAMOND_GOLDEN_FISH(Material.PLAYER_HEAD, Rarity.COMMON), - DIAMOND_HELMET(Material.DIAMOND_HELMET, Rarity.RARE), + DIAMOND_GUSHER(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_HELMET(Material.DIAMOND_HELMET, Rarity.COMMON), DIAMOND_HOE(Material.DIAMOND_HOE, Rarity.COMMON), - DIAMOND_LEGGINGS(Material.DIAMOND_LEGGINGS, Rarity.RARE), + DIAMOND_KARATE_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_LAVAHORSE(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_LEGGINGS(Material.DIAMOND_LEGGINGS, Rarity.COMMON), DIAMOND_MAGMAFISH(Material.PLAYER_HEAD, Rarity.COMMON), + DIAMOND_MANA_RAY(Material.PLAYER_HEAD, Rarity.COMMON), + DIAMOND_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + DIAMOND_MOLDFIN(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_OBFUSCATED_1(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_OBFUSCATED_2(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_OBFUSCATED_3(Material.PLAYER_HEAD, Rarity.COMMON), + DIAMOND_ORE(Material.DIAMOND_ORE, Rarity.COMMON), DIAMOND_PICKAXE(Material.DIAMOND_PICKAXE, Rarity.COMMON), DIAMOND_SHOVEL(Material.DIAMOND_SHOVEL, Rarity.COMMON), + DIAMOND_SKELETON_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_SLUGFISH(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_SOUL_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + DIAMOND_SPREADING(Material.DIAMOND, Rarity.COMMON), + DIAMOND_STEAMING_HOT_FLOUNDER(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_SULPHUR_SKITTER(Material.PLAYER_HEAD, Rarity.COMMON), + DIAMOND_SWORD(Material.DIAMOND_SWORD, Rarity.COMMON), + DIAMOND_VANILLE(Material.PLAYER_HEAD, Rarity.COMMON), + + DIAMOND_VOLCANIC_STONEFISH(Material.PLAYER_HEAD, Rarity.COMMON), + DIGESTED_MOSQUITO(Material.ROTTEN_FLESH, Rarity.LEGENDARY), DIORITE(Material.DIORITE, Rarity.COMMON), @@ -912,6 +1010,8 @@ public enum ItemType { DIRT(Material.DIRT, Rarity.COMMON), + DIRT_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + DISPENSER(Material.DISPENSER, Rarity.COMMON), DITTO_BLOB(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1296,6 +1396,8 @@ public enum ItemType { FANCY_TUXEDO_LEGGINGS(Material.LEATHER_LEGGINGS, Rarity.COMMON), + FARMER_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + FARMING_EXP_BOOST_COMMON(Material.IRON_HOE, Rarity.COMMON), FARMING_EXP_BOOST_RARE(Material.IRON_HOE, Rarity.COMMON), @@ -1326,6 +1428,8 @@ public enum ItemType { FEROCITY_ENRICHMENT(Material.PLAYER_HEAD, Rarity.COMMON), + FESTIVE_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + FIERY_KUUDRA_CORE(Material.PLAYER_HEAD, Rarity.EPIC), FIGSTONE(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1368,6 +1472,8 @@ public enum ItemType { FISHING_ROD(Material.FISHING_ROD, Rarity.COMMON), + FISH_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + FLAMES(Material.BLAZE_POWDER, Rarity.COMMON), FLAWED_AMBER_GEM(Material.PLAYER_HEAD, Rarity.UNCOMMON), @@ -1448,6 +1554,8 @@ public enum ItemType { FRIED_FROZEN_CHICKEN(Material.PLAYER_HEAD, Rarity.EPIC), + FROZEN_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + FROZEN_CHICKEN(Material.PLAYER_HEAD, Rarity.RARE), FTX_3070(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1474,6 +1582,8 @@ public enum ItemType { GHAST_TEAR(Material.GHAST_TEAR, Rarity.UNCOMMON), + GIANT_FISHING_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + GILL_MEMBRANE(Material.PLAYER_HEAD, Rarity.COMMON), GLACIAL_ARTIFACT(Material.PLAYER_HEAD, Rarity.RARE), @@ -1512,12 +1622,16 @@ public enum ItemType { GLOWSTONE_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + GLOWY_CHUM_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + GOBLIN_EGG(Material.EGG, Rarity.COMMON), GOD_POTION(Material.PLAYER_HEAD, Rarity.COMMON), GOLDEN_AXE(Material.GOLDEN_AXE, Rarity.COMMON), + GOLDEN_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + GOLDEN_BOOTS(Material.GOLDEN_BOOTS, Rarity.COMMON), GOLDEN_CARROT(Material.GOLDEN_CARROT, Rarity.COMMON), @@ -1538,20 +1652,56 @@ public enum ItemType { GOLDEN_TOOTH(Material.GOLD_NUGGET, Rarity.RARE), + GOLD_BLOBFISH(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_BLOCK(Material.GOLD_BLOCK, Rarity.COMMON), + GOLD_FLYFISH(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_GIFT_TALISMAN(Material.PLAYER_HEAD, Rarity.LEGENDARY), + GOLD_GOLDEN_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_GUSHER(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_INGOT(Material.GOLD_INGOT, Rarity.COMMON), + GOLD_KARATE_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_LAVAHORSE(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_MAGMAFISH(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_MANA_RAY(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_MOLDFIN(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_NUGGET(Material.GOLD_NUGGET, Rarity.COMMON), + GOLD_OBFUSCATED_1(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_OBFUSCATED_2(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_OBFUSCATED_3(Material.PLAYER_HEAD, Rarity.COMMON), + GOLD_ORE(Material.GOLD_ORE, Rarity.COMMON), + GOLD_SKELETON_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_SLUGFISH(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_SOUL_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_STEAMING_HOT_FLOUNDER(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_SULPHUR_SKITTER(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_VANILLE(Material.PLAYER_HEAD, Rarity.COMMON), + + GOLD_VOLCANIC_STONEFISH(Material.PLAYER_HEAD, Rarity.COMMON), + GRANITE(Material.GRANITE, Rarity.COMMON), GRANITE_SLAB(Material.GRANITE_SLAB, Rarity.COMMON), @@ -1672,6 +1822,8 @@ public enum ItemType { HELIX(Material.PLAYER_HEAD, Rarity.COMMON), + HELLFIRE_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + HIGH_CLASS_ARCHFIEND_DICE(Material.PLAYER_HEAD, Rarity.LEGENDARY), HOLOGRAM(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1688,6 +1840,14 @@ public enum ItemType { HORSEMAN_CANDLE(Material.PLAYER_HEAD, Rarity.RARE), + HOTSPOT_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + + HOTSPOT_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + + HOTSPOT_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + + HOT_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + HOT_POTATO_BOOK(Material.BOOK, Rarity.EPIC), HUB_CASTLE_TRAVEL_SCROLL(Material.PAPER, Rarity.UNCOMMON), @@ -1712,12 +1872,20 @@ public enum ItemType { ICE(Material.ICE, Rarity.COMMON), + ICE_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + ICE_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + ICE_ROD(Material.FISHING_ROD, Rarity.RARE), + + ICY_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + INFERNAL_KUUDRA_CORE(Material.PLAYER_HEAD, Rarity.LEGENDARY), INFERNO_FUEL_BLOCK(Material.PLAYER_HEAD, Rarity.COMMON), + INFERNO_ROD(Material.FISHING_ROD, Rarity.EPIC), + INFINI_TORCH(Material.TORCH, Rarity.EPIC), INK_SAC(Material.INK_SAC, Rarity.COMMON), @@ -1832,6 +2000,8 @@ public enum ItemType { JUNK_RING(Material.PLAYER_HEAD, Rarity.UNCOMMON), + JUNK_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + JUNK_TALISMAN(Material.PLAYER_HEAD, Rarity.COMMON), KAT_BOUQUET(Material.ROSE_BUSH, Rarity.COMMON), @@ -1914,10 +2084,14 @@ public enum ItemType { LEATHER_LEGGINGS(Material.LEATHER_LEGGINGS, Rarity.COMMON), + LEGEND_ROD(Material.FISHING_ROD, Rarity.EPIC), + LEVER(Material.LEVER, Rarity.COMMON), LIGHTER_BLUE_ABICASE(Material.PLAYER_HEAD, Rarity.COMMON), + LIGHT_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + LIGHT_BLUE_BANNER(Material.LIGHT_BLUE_BANNER, Rarity.COMMON), LIGHT_BLUE_BED(Material.LIGHT_BLUE_BED, Rarity.COMMON), @@ -2034,6 +2208,8 @@ public enum ItemType { MAGMA_CUBE_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + MAGMA_ROD(Material.FISHING_ROD, Rarity.RARE), + MANA_DISINTEGRATOR(Material.PLAYER_HEAD, Rarity.RARE), MANGCORE(Material.PLAYER_HEAD, Rarity.COMMON), @@ -2162,6 +2338,8 @@ public enum ItemType { MINION_STORAGE_EXPANDER(Material.PLAYER_HEAD, Rarity.COMMON), + MINNOW_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + MINOS_RELIC(Material.PLAYER_HEAD, Rarity.EPIC), MITHRIL(Material.PRISMARINE_CRYSTALS, Rarity.COMMON), @@ -2434,6 +2612,10 @@ public enum ItemType { PET_LUCK_POTION_1(Material.POTION, Rarity.COMMON), + PHANTOM_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + + PHANTOM_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + PICKONIMBUS_2000(Material.DIAMOND_PICKAXE, Rarity.COMMON), PIGGY_BANK(Material.PLAYER_HEAD, Rarity.UNCOMMON), @@ -2504,6 +2686,8 @@ public enum ItemType { POLISHED_PUMPKIN(Material.PLAYER_HEAD, Rarity.COMMON), + POLISHED_TOPAZ_ROD(Material.FISHING_ROD, Rarity.RARE), + POOCH_SWORD(Material.GOLDEN_SWORD, Rarity.LEGENDARY), POPPY(Material.POPPY, Rarity.COMMON), @@ -2550,8 +2734,12 @@ public enum ItemType { PRISMARINE_CRYSTALS(Material.PRISMARINE_CRYSTALS, Rarity.COMMON), + PRISMARINE_ROD(Material.FISHING_ROD, Rarity.COMMON), + PRISMARINE_SHARD(Material.PRISMARINE_SHARD, Rarity.COMMON), + PRISMARINE_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + PROMISING_AXE(Material.IRON_AXE, Rarity.COMMON), PROMISING_PICKAXE(Material.IRON_PICKAXE, Rarity.UNCOMMON), @@ -2768,6 +2956,8 @@ public enum ItemType { ROBOTRON_REFLECTOR(Material.PLAYER_HEAD, Rarity.COMMON), + ROD_OF_THE_SEA(Material.FISHING_ROD, Rarity.LEGENDARY), + ROGUE_SWORD(Material.GOLDEN_SWORD, Rarity.COMMON), ROOKIE_AXE(Material.STONE_AXE, Rarity.COMMON), @@ -2826,6 +3016,8 @@ public enum ItemType { RUSTY_COIN(Material.PLAYER_HEAD, Rarity.UNCOMMON), + RUSTY_SHIP_ENGINE(Material.PLAYER_HEAD, Rarity.SPECIAL), + SAND(Material.SAND, Rarity.COMMON), SANDBOX_ITEM(Material.BLAZE_POWDER, Rarity.COMMON), @@ -2882,6 +3074,8 @@ public enum ItemType { SHARD_OF_THE_SHREDDED(Material.PLAYER_HEAD, Rarity.COMMON), + SHARK_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + SHARK_FIN(Material.PRISMARINE_SHARD, Rarity.RARE), SHARPENED_CLAWS(Material.PRISMARINE_SHARD, Rarity.COMMON), @@ -2894,10 +3088,48 @@ public enum ItemType { SHORT_GRASS(Material.SHORT_GRASS, Rarity.COMMON), + SHREDDED_LINE(Material.PLAYER_HEAD, Rarity.RARE), + + SILVER_BLOBFISH(Material.PLAYER_HEAD, Rarity.COMMON), + SILVER_FANG(Material.IRON_SWORD, Rarity.UNCOMMON), + SILVER_FLYFISH(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_GOLDEN_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_GUSHER(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_KARATE_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_LAVAHORSE(Material.PLAYER_HEAD, Rarity.COMMON), + SILVER_MAGMAFISH(Material.PLAYER_HEAD, Rarity.COMMON), + SILVER_MANA_RAY(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_MOLDFIN(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_OBFUSCATED_1(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_OBFUSCATED_2(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_OBFUSCATED_3(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_SKELETON_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_SLUGFISH(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_SOUL_FISH(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_STEAMING_HOT_FLOUNDER(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_SULPHUR_SKITTER(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_VANILLE(Material.PLAYER_HEAD, Rarity.COMMON), + + SILVER_VOLCANIC_STONEFISH(Material.PLAYER_HEAD, Rarity.COMMON), + SINFUL_DICE(Material.PLAYER_HEAD, Rarity.EPIC), SINSEEKER_SCYTHE(Material.GOLDEN_HOE, Rarity.EPIC), @@ -3028,6 +3260,10 @@ public enum ItemType { SOUL_STRING(Material.STRING, Rarity.COMMON), + SPEEDSTER_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + + SPEEDY_LINE(Material.PLAYER_HEAD, Rarity.RARE), + SPEED_ARTIFACT(Material.PLAYER_HEAD, Rarity.COMMON), SPEED_ENRICHMENT(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3058,8 +3294,16 @@ public enum ItemType { SPIDER_TALISMAN(Material.PLAYER_HEAD, Rarity.COMMON), + SPIKED_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + SPONGE(Material.SPONGE, Rarity.COMMON), + SPONGE_ROD(Material.FISHING_ROD, Rarity.COMMON), + + SPONGE_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + + SPOOKY_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + SPOOKY_SHARD(Material.PLAYER_HEAD, Rarity.RARE), SPRUCE_BOAT(Material.SPRUCE_BOAT, Rarity.COMMON), @@ -3122,10 +3366,14 @@ public enum ItemType { STARLYN_PRIZE(Material.PLAYER_HEAD, Rarity.COMMON), + STARTER_LAVA_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + STICK(Material.STICK, Rarity.COMMON), STICKY_PISTON(Material.STICKY_PISTON, Rarity.COMMON), + STINGY_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + STONE(Material.STONE, Rarity.COMMON), STONE_AXE(Material.STONE_AXE, Rarity.COMMON), @@ -3262,6 +3510,8 @@ public enum ItemType { TESSELLATED_ENDER_PEARL(Material.PLAYER_HEAD, Rarity.LEGENDARY), + THE_SHREDDER(Material.FISHING_ROD, Rarity.LEGENDARY), + TIGER_SHARK_TOOTH(Material.GHAST_TEAR, Rarity.EPIC), TIGHTLY_TIED_HAY_BALE(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3276,6 +3526,8 @@ public enum ItemType { TITANIUM_TALISMAN(Material.PLAYER_HEAD, Rarity.UNCOMMON), + TITAN_LINE(Material.PLAYER_HEAD, Rarity.RARE), + TNT(Material.TNT, Rarity.COMMON), TNT_MINECART(Material.TNT_MINECART, Rarity.COMMON), @@ -3292,6 +3544,10 @@ public enum ItemType { TREASURE_ARTIFACT(Material.PLAYER_HEAD, Rarity.COMMON), + TREASURE_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + + TREASURE_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + TREASURE_RING(Material.PLAYER_HEAD, Rarity.COMMON), TREASURE_TALISMAN(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3382,6 +3638,8 @@ public enum ItemType { WET_WATER(Material.PLAYER_HEAD, Rarity.COMMON), + WHALE_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + WHEAT(Material.WHEAT, Rarity.COMMON), WHEAT_CRYSTAL(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3420,6 +3678,8 @@ public enum ItemType { WILSON_ENGINEERING_PLANS(Material.PAPER, Rarity.LEGENDARY), + WINTER_ROD(Material.FISHING_ROD, Rarity.RARE), + WISHING_COMPASS(Material.PLAYER_HEAD, Rarity.COMMON), WITHER_ARTIFACT(Material.PLAYER_HEAD, Rarity.EPIC), @@ -3440,6 +3700,8 @@ public enum ItemType { WOODEN_AXE(Material.WOODEN_AXE, Rarity.COMMON), + WOODEN_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + WOODEN_HOE(Material.WOODEN_HOE, Rarity.COMMON), WOODEN_PICKAXE(Material.WOODEN_PICKAXE, Rarity.COMMON), @@ -3448,6 +3710,8 @@ public enum ItemType { WOODEN_SWORD(Material.WOODEN_SWORD, Rarity.COMMON), + WORM_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + WORM_MEMBRANE(Material.ROTTEN_FLESH, Rarity.COMMON), YELLOW_BANNER(Material.YELLOW_BANNER, Rarity.COMMON), @@ -3472,6 +3736,8 @@ public enum ItemType { YELLOW_WOOL(Material.YELLOW_WOOL, Rarity.COMMON), + YETI_ROD(Material.FISHING_ROD, Rarity.EPIC), + ZOMBIE_ARTIFACT(Material.PLAYER_HEAD, Rarity.COMMON), ZOMBIE_BRAIN_MIXIN(Material.PLAYER_HEAD, Rarity.COMMON), diff --git a/commons/src/main/java/net/swofty/commons/ChatColor.java b/commons/src/main/java/net/swofty/commons/ChatColor.java index 27dae1885..293e76e08 100644 --- a/commons/src/main/java/net/swofty/commons/ChatColor.java +++ b/commons/src/main/java/net/swofty/commons/ChatColor.java @@ -31,6 +31,14 @@ public enum ChatColor { public static final char COLOR_CHAR = '§'; private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + '§' + "[0-9A-FK-OR]"); + private static final java.util.Map BY_CODE = new java.util.HashMap<>(); + + static { + for (ChatColor color : values()) { + BY_CODE.put(color.code, color); + } + } + private final int intCode; private final char code; private final boolean isFormat; @@ -53,16 +61,10 @@ public static ChatColor getLastColor(String text) { return null; } for (int i = text.length() - 2; i >= 0; i--) { - - char currentChar = text.charAt(i); - if (currentChar == ChatColor.COLOR_CHAR) { - - char colorCode = text.charAt(i + 1); - for (ChatColor chatColor : ChatColor.values()) { - - if (chatColor.getCode() == colorCode) { - return chatColor; - } + if (text.charAt(i) == ChatColor.COLOR_CHAR) { + ChatColor color = BY_CODE.get(text.charAt(i + 1)); + if (color != null) { + return color; } } } diff --git a/commons/src/main/java/net/swofty/commons/ChatUtility.java b/commons/src/main/java/net/swofty/commons/ChatUtility.java index 0b60cf6ca..5d20b226a 100644 --- a/commons/src/main/java/net/swofty/commons/ChatUtility.java +++ b/commons/src/main/java/net/swofty/commons/ChatUtility.java @@ -1,10 +1,15 @@ package net.swofty.commons; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import lombok.Getter; import java.util.List; -public class ChatUtility { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ChatUtility { + public enum FontInfo { A('A', 5), diff --git a/commons/src/main/java/net/swofty/commons/MethodLister.java b/commons/src/main/java/net/swofty/commons/MethodLister.java deleted file mode 100644 index d2f699ffe..000000000 --- a/commons/src/main/java/net/swofty/commons/MethodLister.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.swofty.commons; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -public class MethodLister { - - public static void listMethods(Class clazz) { - // Get all declared methods including public, protected, default (package) access, - // and private methods, but excluding inherited methods. - Method[] methods = clazz.getDeclaredMethods(); - - System.out.println("Methods of " + clazz.getName() + ":"); - - for (Method method : methods) { - // Get the method name - String methodName = method.getName(); - - // Get the method modifiers - String modifier = Modifier.toString(method.getModifiers()); - - // Get the return type - Class returnType = method.getReturnType(); - String returnTypeName = returnType.getSimpleName(); - - // Get the parameter types - Class[] parameterTypes = method.getParameterTypes(); - String parameters = getParameterString(parameterTypes); - - // Print method signature - System.out.println(modifier + " " + returnTypeName + " " + methodName + "(" + parameters + ")"); - } - } - - private static String getParameterString(Class[] parameterTypes) { - StringBuilder parameters = new StringBuilder(); - for (int i = 0; i < parameterTypes.length; i++) { - Class paramType = parameterTypes[i]; - parameters.append(paramType.getSimpleName()); - if (i < parameterTypes.length - 1) { - parameters.append(", "); - } - } - return parameters.toString(); - } -} diff --git a/commons/src/main/java/net/swofty/commons/MinecraftVersion.java b/commons/src/main/java/net/swofty/commons/MinecraftVersion.java deleted file mode 100644 index 3bf3d1843..000000000 --- a/commons/src/main/java/net/swofty/commons/MinecraftVersion.java +++ /dev/null @@ -1,76 +0,0 @@ -package net.swofty.commons; - -import lombok.Getter; - -import java.util.Arrays; -@Getter -public enum MinecraftVersion { - MINECRAFT_1_7_2(4, new String[]{"1.7.2", "1.7.3", "1.7.4", "1.7.5"}), - MINECRAFT_1_7_6(5, new String[]{"1.7.6", "1.7.7", "1.7.8", "1.7.9", "1.7.10"}), - MINECRAFT_1_8(47, new String[]{"1.8", "1.8.1", "1.8.2", "1.8.3", "1.8.4", "1.8.5", "1.8.6", "1.8.7", "1.8.8", "1.8.9"}), - MINECRAFT_1_9(107, new String[]{"1.9"}), - MINECRAFT_1_9_1(108, new String[]{"1.9.1"}), - MINECRAFT_1_9_2(109, new String[]{"1.9.2"}), - MINECRAFT_1_9_4(110, new String[]{"1.9.3", "1.9.4"}), - MINECRAFT_1_10(210, new String[]{"1.10", "1.10.1", "1.10.2"}), - MINECRAFT_1_11(315, new String[]{"1.11"}), - MINECRAFT_1_11_1(316, new String[]{"1.11.1", "1.11.2"}), - MINECRAFT_1_12(335, new String[]{"1.12"}), - MINECRAFT_1_12_1(338, new String[]{"1.12.1"}), - MINECRAFT_1_12_2(340, new String[]{"1.12.2"}), - MINECRAFT_1_13(393, new String[]{"1.13"}), - MINECRAFT_1_13_1(401, new String[]{"1.13.1"}), - MINECRAFT_1_13_2(404, new String[]{"1.13.2"}), - MINECRAFT_1_14(477, new String[]{"1.14"}), - MINECRAFT_1_14_1(480, new String[]{"1.14.1"}), - MINECRAFT_1_14_2(485, new String[]{"1.14.2"}), - MINECRAFT_1_14_3(490, new String[]{"1.14.3"}), - MINECRAFT_1_14_4(498, new String[]{"1.14.4"}), - MINECRAFT_1_15(573, new String[]{"1.15"}), - MINECRAFT_1_15_1(575, new String[]{"1.15.1"}), - MINECRAFT_1_15_2(578, new String[]{"1.15.2"}), - MINECRAFT_1_16(735, new String[]{"1.16"}), - MINECRAFT_1_16_1(736, new String[]{"1.16.1"}), - MINECRAFT_1_16_2(751, new String[]{"1.16.2"}), - MINECRAFT_1_16_3(753, new String[]{"1.16.3"}), - MINECRAFT_1_16_4(754, new String[]{"1.16.4", "1.16.5"}), - MINECRAFT_1_17(755, new String[]{"1.17"}), - MINECRAFT_1_17_1(756, new String[]{"1.17.1"}), - MINECRAFT_1_18(757, new String[]{"1.18", "1.18.1"}), - MINECRAFT_1_18_2(758, new String[]{"1.18.2"}), - MINECRAFT_1_19(759, new String[]{"1.19"}), - MINECRAFT_1_19_1(760, new String[]{"1.19.1", "1.19.2"}), - MINECRAFT_1_19_3(761, new String[]{"1.19.3"}), - MINECRAFT_1_19_4(762, new String[]{"1.19.4"}), - MINECRAFT_1_20(763, new String[]{"1.20", "1.20.1"}), - MINECRAFT_1_20_2(764, new String[]{"1.20.2"}), - MINECRAFT_1_20_3(765, new String[]{"1.20.3", "1.20.4"}), - MINECRAFT_1_20_5(766, new String[]{"1.20.5", "1.20.6"}), - MINECRAFT_1_21(767, new String[]{"1.21", "1.21.1"}), - MINECRAFT_1_21_2(768, new String[]{"1.21.2", "1.21.3"}), - MINECRAFT_1_21_4(769, new String[]{"1.21.4"}), - MINECRAFT_1_21_5(770, new String[]{"1.21.5"}), - MINECRAFT_1_21_6(771, new String[]{"1.21.6"}), - MINECRAFT_1_21_7(772, new String[]{"1.21.7"}), - MINECRAFT_1_21_8(772, new String[]{"1.21.8"}), - MINECRAFT_1_21_9(773, new String[]{"1.21.9"}), - MINECRAFT_1_21_10(773, new String[]{"1.21.10"}), - MINECRAFT_1_21_11(774, new String[]{"1.21.11"}), - ; - - private final int protocol; - private final String[] versions; - - MinecraftVersion(int protocol, String[] versions) { - this.protocol = protocol; - this.versions = versions; - } - - public static MinecraftVersion byProtocolId(int protocolID) { - return Arrays.stream(MinecraftVersion.values()) - .filter(version -> version.protocol == protocolID) - .findFirst() - .orElse(null); - } - -} diff --git a/commons/src/main/java/net/swofty/commons/Result.java b/commons/src/main/java/net/swofty/commons/Result.java new file mode 100644 index 000000000..b7e49d5c6 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/Result.java @@ -0,0 +1,175 @@ +package net.swofty.commons; + +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Either a success value of type {@code T} or an error of type {@code E}, + * never both. Use as a return type when a method has a meaningful failure + * case that the caller is expected to handle — keeps the happy path on the + * type signature instead of forcing a try/catch. + * + *

Modelled as a sealed two-variant interface so {@code switch} over a + * Result is exhaustive at the compiler level: + *

{@code
+ * String message = switch (result) {
+ *     case Result.Ok ok    -> "got " + ok.value();
+ *     case Result.Err err  -> "failed: " + err.error();
+ * };
+ * }
+ * + *

Variants are records, so destructuring works: + *

{@code
+ * if (result instanceof Result.Ok(Integer value)) {
+ *     useValue(value);
+ * }
+ * }
+ */ +public sealed interface Result { + + static Result ok(T value) { + return new Ok<>(value); + } + + static Result err(E error) { + return new Err<>(error); + } + + /** + * Runs {@code action} and wraps a thrown exception as the {@code Err} + * variant. Useful at the boundary of a try-block to keep failure as a + * value instead of a control-flow jump. + */ + static Result attempt(Supplier action) { + try { + return ok(action.get()); + } catch (Exception e) { + return err(e); + } + } + + boolean isOk(); + + default boolean isErr() { + return !isOk(); + } + + /** Returns the success value or throws if this is an error. Prefer {@link #orElse}. */ + T unwrap(); + + /** Returns the error or throws if this is a success. */ + E unwrapErr(); + + /** Returns the success value or {@code other} if this is an error. */ + T orElse(T other); + + /** Returns the success value or applies {@code mapper} to the error to produce one. */ + T orElseGet(Function mapper); + + Optional ok(); + + Optional err(); + + /** Maps the success value, leaving an error untouched. */ + Result map(Function mapper); + + /** Maps the error, leaving the success untouched. */ + Result mapErr(Function mapper); + + /** Monadic bind: chains operations that may themselves fail. */ + Result flatMap(Function> mapper); + + /** Executes the consumer if this is a success. */ + Result ifOk(Consumer action); + + /** Executes the consumer if this is an error. */ + Result ifErr(Consumer action); + + record Ok(T value) implements Result { + public Ok { + Objects.requireNonNull(value, "Ok value must not be null; use Optional for absence"); + } + + @Override public boolean isOk() { return true; } + @Override public T unwrap() { return value; } + @Override public E unwrapErr() { throw new NoSuchElementException("Result is Ok, not Err"); } + @Override public T orElse(T other) { return value; } + @Override public T orElseGet(Function mapper) { return value; } + @Override public Optional ok() { return Optional.of(value); } + @Override public Optional err() { return Optional.empty(); } + + @Override + public Result map(Function mapper) { + return new Ok<>(mapper.apply(value)); + } + + @Override + public Result mapErr(Function mapper) { + return new Ok<>(value); + } + + @Override + public Result flatMap(Function> mapper) { + return mapper.apply(value); + } + + @Override + public Result ifOk(Consumer action) { + action.accept(value); + return this; + } + + @Override + public Result ifErr(Consumer action) { + return this; + } + } + + record Err(E error) implements Result { + public Err { + Objects.requireNonNull(error, "Err value must not be null"); + } + + @Override public boolean isOk() { return false; } + @Override public T unwrap() { + throw error instanceof Throwable t + ? new RuntimeException("Result is Err: " + error, t) + : new NoSuchElementException("Result is Err: " + error); + } + @Override public E unwrapErr() { return error; } + @Override public T orElse(T other) { return other; } + @Override public T orElseGet(Function mapper) { return mapper.apply(error); } + @Override public Optional ok() { return Optional.empty(); } + @Override public Optional err() { return Optional.of(error); } + + @Override + public Result map(Function mapper) { + return new Err<>(error); + } + + @Override + public Result mapErr(Function mapper) { + return new Err<>(mapper.apply(error)); + } + + @Override + public Result flatMap(Function> mapper) { + return new Err<>(error); + } + + @Override + public Result ifOk(Consumer action) { + return this; + } + + @Override + public Result ifErr(Consumer action) { + action.accept(error); + return this; + } + } +} diff --git a/commons/src/main/java/net/swofty/commons/StringUtility.java b/commons/src/main/java/net/swofty/commons/StringUtility.java index 2c7b36e98..6f4756cec 100644 --- a/commons/src/main/java/net/swofty/commons/StringUtility.java +++ b/commons/src/main/java/net/swofty/commons/StringUtility.java @@ -1,5 +1,8 @@ package net.swofty.commons; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -16,7 +19,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class StringUtility { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class StringUtility { + public static final char[] ALPHABET = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z' }; diff --git a/commons/src/main/java/net/swofty/commons/TestFlow.java b/commons/src/main/java/net/swofty/commons/TestFlow.java index 4b0e7ee50..474998106 100644 --- a/commons/src/main/java/net/swofty/commons/TestFlow.java +++ b/commons/src/main/java/net/swofty/commons/TestFlow.java @@ -15,25 +15,21 @@ public class TestFlow { private static List currentTestPlayers; /** - * Checks if any test flow is currently active on this server - * @return true if a test flow is active + * Checks if any test flow is currently active on this server. */ public static boolean isTestFlowActive() { return currentTestFlow != null; } /** - * Checks if a specific test flow is active - * @param testFlowName the name of the test flow - * @return true if the specified test flow is active + * Checks if a specific test flow is active. */ public static boolean isTestFlowActive(String testFlowName) { return currentTestFlow != null && currentTestFlow.equals(testFlowName); } /** - * Gets the current test flow instance - * @return a simple TestFlowInstance or null if no test flow is active + * Gets the current test flow instance, or {@code null} if no test flow is active. */ public static TestFlowInstance getTestFlowInstance() { if (currentTestFlow == null) return null; @@ -41,9 +37,7 @@ public static TestFlowInstance getTestFlowInstance() { } /** - * Sets the current test flow for this server - * @param testFlowName the name of the test flow - * @param players the list of test flow players + * Sets the current test flow for this server. */ public static void setCurrentTestFlow(String testFlowName, List players) { currentTestFlow = testFlowName; @@ -51,33 +45,16 @@ public static void setCurrentTestFlow(String testFlowName, List players) } /** - * Clears the current test flow + * Clears the current test flow. */ public static void clearTestFlow() { currentTestFlow = null; currentTestPlayers = null; } - /** - * Simple test flow instance for server-side usage - */ - @Getter - public static class TestFlowInstance { - private final String name; - private final List players; - - public TestFlowInstance(String name, List players) { - this.name = name; - this.players = players; - } - - /** - * Checks if a player is part of this test flow - * @param playerName the player name to check - * @return true if the player is in this test flow - */ + public record TestFlowInstance(String name, List players) { public boolean hasPlayer(String playerName) { return players != null && players.contains(playerName); } } -} \ No newline at end of file +} diff --git a/commons/src/main/java/net/swofty/commons/TrackedItem.java b/commons/src/main/java/net/swofty/commons/TrackedItem.java index 82d3036ae..38ed2c14e 100644 --- a/commons/src/main/java/net/swofty/commons/TrackedItem.java +++ b/commons/src/main/java/net/swofty/commons/TrackedItem.java @@ -1,7 +1,6 @@ package net.swofty.commons; import lombok.Getter; -import lombok.Setter; import org.bson.Document; import org.json.JSONObject; @@ -11,13 +10,12 @@ import java.util.UUID; @Getter -@Setter public class TrackedItem { - public final UUID itemUUID; - public final long created; - public final ArrayList attachedPlayers; - public final String itemType; - public final Integer numberMade; + private final UUID itemUUID; + private final long created; + private final ArrayList attachedPlayers; + private final String itemType; + private final Integer numberMade; public TrackedItem(UUID itemUUID, long created, ArrayList attachedPlayers, String itemType, Integer numberMade) { this.itemUUID = itemUUID; diff --git a/commons/src/main/java/net/swofty/commons/YamlFileUtils.java b/commons/src/main/java/net/swofty/commons/YamlFileUtils.java index 4738d32ac..2dac76e30 100644 --- a/commons/src/main/java/net/swofty/commons/YamlFileUtils.java +++ b/commons/src/main/java/net/swofty/commons/YamlFileUtils.java @@ -1,5 +1,8 @@ package net.swofty.commons; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import org.yaml.snakeyaml.Yaml; import java.io.*; @@ -13,7 +16,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class YamlFileUtils { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class YamlFileUtils { + /** * Get all YAML files in a directory and its subdirectories * @param directory The base directory to search in diff --git a/commons/src/main/java/net/swofty/commons/bedwars/BedwarsLevelUtil.java b/commons/src/main/java/net/swofty/commons/bedwars/BedwarsLevelUtil.java index fe0403458..5fcdc101d 100644 --- a/commons/src/main/java/net/swofty/commons/bedwars/BedwarsLevelUtil.java +++ b/commons/src/main/java/net/swofty/commons/bedwars/BedwarsLevelUtil.java @@ -1,8 +1,12 @@ package net.swofty.commons.bedwars; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import java.text.DecimalFormat; -public class BedwarsLevelUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class BedwarsLevelUtil { private static final DecimalFormat FORMAT = new DecimalFormat("#,###.#"); diff --git a/commons/src/main/java/net/swofty/commons/friend/Friend.java b/commons/src/main/java/net/swofty/commons/friend/Friend.java index 43b00fc5d..97ec70dd1 100644 --- a/commons/src/main/java/net/swofty/commons/friend/Friend.java +++ b/commons/src/main/java/net/swofty/commons/friend/Friend.java @@ -4,13 +4,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.UUID; @Getter public class Friend { + private static final Serializer SERIALIZER = new JacksonSerializer<>(Friend.class); + private final UUID uuid; @Setter private String nickname; @@ -35,36 +37,10 @@ public static Friend create(UUID uuid) { } public static Serializer getStaticSerializer() { - return new Friend(UUID.randomUUID(), null, false, 0).getSerializer(); + return SERIALIZER; } public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(Friend value) { - JSONObject json = new JSONObject(); - json.put("uuid", value.uuid.toString()); - json.put("nickname", value.nickname != null ? value.nickname : JSONObject.NULL); - json.put("bestFriend", value.bestFriend); - json.put("addedTimestamp", value.addedTimestamp); - return json.toString(); - } - - @Override - public Friend deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new Friend( - UUID.fromString(jsonObject.getString("uuid")), - jsonObject.isNull("nickname") ? null : jsonObject.getString("nickname"), - jsonObject.getBoolean("bestFriend"), - jsonObject.getLong("addedTimestamp") - ); - } - - @Override - public Friend clone(Friend value) { - return new Friend(value.uuid, value.nickname, value.bestFriend, value.addedTimestamp); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/FriendData.java b/commons/src/main/java/net/swofty/commons/friend/FriendData.java index 2cdc228d2..a7ad30d43 100644 --- a/commons/src/main/java/net/swofty/commons/friend/FriendData.java +++ b/commons/src/main/java/net/swofty/commons/friend/FriendData.java @@ -4,9 +4,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONArray; -import org.json.JSONObject; import java.util.ArrayList; import java.util.List; @@ -14,6 +13,8 @@ @Getter public class FriendData { + private static final Serializer SERIALIZER = new JacksonSerializer<>(FriendData.class); + private final UUID playerUuid; private final List friends; @Setter @@ -71,57 +72,10 @@ public void removeAllNonBestFriends() { } public static Serializer getStaticSerializer() { - return createEmpty(UUID.randomUUID()).getSerializer(); + return SERIALIZER; } public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendData value) { - JSONObject json = new JSONObject(); - json.put("playerUuid", value.playerUuid.toString()); - - JSONArray friendsArray = new JSONArray(); - for (Friend friend : value.friends) { - friendsArray.put(new JSONObject(friend.getSerializer().serialize(friend))); - } - json.put("friends", friendsArray); - - json.put("settings", new JSONObject(value.settings.getSerializer().serialize(value.settings))); - return json.toString(); - } - - @Override - public FriendData deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - UUID playerUuid = UUID.fromString(jsonObject.getString("playerUuid")); - - List friends = new ArrayList<>(); - JSONArray friendsArray = jsonObject.getJSONArray("friends"); - Serializer friendSerializer = Friend.getStaticSerializer(); - for (int i = 0; i < friendsArray.length(); i++) { - friends.add(friendSerializer.deserialize(friendsArray.getJSONObject(i).toString())); - } - - FriendSettings settings = FriendSettings.getStaticSerializer() - .deserialize(jsonObject.getJSONObject("settings").toString()); - - return new FriendData(playerUuid, friends, settings); - } - - @Override - public FriendData clone(FriendData value) { - List clonedFriends = new ArrayList<>(); - Serializer friendSerializer = Friend.getStaticSerializer(); - for (Friend friend : value.friends) { - clonedFriends.add(friendSerializer.clone(friend)); - } - return new FriendData( - value.playerUuid, - clonedFriends, - value.settings.getSerializer().clone(value.settings) - ); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/FriendEvent.java b/commons/src/main/java/net/swofty/commons/friend/FriendEvent.java index af1d22f44..6b7bdbf50 100644 --- a/commons/src/main/java/net/swofty/commons/friend/FriendEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/FriendEvent.java @@ -8,7 +8,10 @@ import net.swofty.commons.friend.events.response.*; import net.swofty.commons.protocol.Serializer; +import java.lang.reflect.Constructor; +import java.lang.reflect.Parameter; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -28,6 +31,12 @@ @JsonSubTypes.Type(value = FriendResponseEvent.class) }) public abstract class FriendEvent { + + private static final String[] EVENT_PACKAGES = { + "net.swofty.commons.friend.events", + "net.swofty.commons.friend.events.response" + }; + public FriendEvent() { } @@ -35,127 +44,65 @@ public FriendEvent() { public abstract List getParticipants(); + /** + * Returns a placeholder instance of the named event subclass. Used by the + * Redis dispatch layer to obtain a {@link Serializer} for incoming + * payloads — the dummy itself is discarded once its serializer is held. + * + *

The dummy is built by picking the first declared constructor of the + * subclass and filling every parameter with a default of the appropriate + * type. This replaces a ~100-line switch over each event class name with + * one reflection pass; adding a new event subtype no longer requires a + * matching case here.

+ */ public static @NonNull FriendEvent findFromType(String className) { - String[] packageNames = { - "net.swofty.commons.friend.events", - "net.swofty.commons.friend.events.response" - }; - - for (String packageName : packageNames) { + for (String packageName : EVENT_PACKAGES) { try { Class clazz = Class.forName(packageName + "." + className); return createDummyInstance(clazz); + } catch (ClassNotFoundException ignored) { + // try next package } catch (Exception e) { - // Try next package + throw new RuntimeException( + "Failed to instantiate friend event class " + className, e); } } - - throw new RuntimeException("Failed to find friend event class: " + className + " in " + Arrays.toString(packageNames)); + throw new RuntimeException( + "Failed to find friend event class: " + className + + " in " + Arrays.toString(EVENT_PACKAGES)); } private static FriendEvent createDummyInstance(Class clazz) throws Exception { - String className = clazz.getSimpleName(); + Constructor[] constructors = clazz.getDeclaredConstructors(); + if (constructors.length == 0) { + throw new IllegalStateException("No constructors on " + clazz.getName()); + } - switch (className) { - // Request events - case "FriendAddRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID()); - } - case "FriendAcceptRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID()); - } - case "FriendDenyRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID()); - } - case "FriendRemoveRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID()); - } - case "FriendRemoveAllRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID()); - } - case "FriendToggleBestRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID()); - } - case "FriendSetNicknameRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); - } - case "FriendToggleSettingRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, FriendSettingType.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), FriendSettingType.ACCEPTING_REQUESTS); - } - case "FriendListRequestEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, int.class, boolean.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), 1, false); - } - case "FriendRequestsListEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, int.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), 1); - } - // Response events - case "FriendRequestSentResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); - } - case "FriendRequestReceivedResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); - } - case "FriendAddedResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), "", ""); - } - case "FriendDeniedResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); - } - case "FriendRemovedResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); - } - case "FriendRemoveAllResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, int.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), 0); - } - case "FriendBestToggledResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class, boolean.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), "", false); - } - case "FriendNicknameSetResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), "", ""); - } - case "FriendSettingToggledResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, FriendSettingType.class, boolean.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), FriendSettingType.ACCEPTING_REQUESTS, false); - } - case "FriendJoinNotificationEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); - } - case "FriendLeaveNotificationEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); - } - case "FriendRequestExpiredResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class, String.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID(), "", ""); - } - case "FriendListResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, List.class, int.class, int.class, boolean.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), List.of(), 1, 1, false); - } - case "FriendRequestsListResponseEvent" -> { - var constructor = clazz.getDeclaredConstructor(UUID.class, List.class, int.class, int.class); - return (FriendEvent) constructor.newInstance(UUID.randomUUID(), List.of(), 1, 1); - } - default -> throw new IllegalArgumentException("Unknown friend event class: " + className); + Constructor constructor = constructors[0]; + Object[] args = Arrays.stream(constructor.getParameters()) + .map(FriendEvent::placeholderFor) + .toArray(); + constructor.setAccessible(true); + return (FriendEvent) constructor.newInstance(args); + } + + private static Object placeholderFor(Parameter parameter) { + Class type = parameter.getType(); + if (type == UUID.class) return UUID.randomUUID(); + if (type == String.class) return ""; + if (type == int.class || type == Integer.class) return 0; + if (type == long.class || type == Long.class) return 0L; + if (type == double.class || type == Double.class) return 0.0D; + if (type == float.class || type == Float.class) return 0F; + if (type == boolean.class || type == Boolean.class) return false; + if (type == byte.class || type == Byte.class) return (byte) 0; + if (type == short.class || type == Short.class) return (short) 0; + if (type == char.class || type == Character.class) return '\0'; + if (type == List.class) return Collections.emptyList(); + if (type.isEnum()) { + Object[] constants = type.getEnumConstants(); + return constants.length == 0 ? null : constants[0]; } + return null; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/FriendSettings.java b/commons/src/main/java/net/swofty/commons/friend/FriendSettings.java index 3e96e150a..8e12b2dad 100644 --- a/commons/src/main/java/net/swofty/commons/friend/FriendSettings.java +++ b/commons/src/main/java/net/swofty/commons/friend/FriendSettings.java @@ -4,12 +4,14 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; @Getter @Setter public class FriendSettings { + private static final Serializer SERIALIZER = new JacksonSerializer<>(FriendSettings.class); + private boolean acceptingRequests; private boolean joinLeaveNotifications; @@ -26,32 +28,10 @@ public static FriendSettings createDefault() { } public static Serializer getStaticSerializer() { - return createDefault().getSerializer(); + return SERIALIZER; } public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendSettings value) { - JSONObject json = new JSONObject(); - json.put("acceptingRequests", value.acceptingRequests); - json.put("joinLeaveNotifications", value.joinLeaveNotifications); - return json.toString(); - } - - @Override - public FriendSettings deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendSettings( - jsonObject.getBoolean("acceptingRequests"), - jsonObject.getBoolean("joinLeaveNotifications") - ); - } - - @Override - public FriendSettings clone(FriendSettings value) { - return new FriendSettings(value.acceptingRequests, value.joinLeaveNotifications); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/PendingFriendRequest.java b/commons/src/main/java/net/swofty/commons/friend/PendingFriendRequest.java index af8a042d9..be034c917 100644 --- a/commons/src/main/java/net/swofty/commons/friend/PendingFriendRequest.java +++ b/commons/src/main/java/net/swofty/commons/friend/PendingFriendRequest.java @@ -3,14 +3,17 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter public class PendingFriendRequest { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(PendingFriendRequest.class); + private final UUID from; private final UUID to; private final String fromName; @@ -40,38 +43,10 @@ public List getParticipants() { } public static Serializer getStaticSerializer() { - return create(UUID.randomUUID(), UUID.randomUUID(), "", "").getSerializer(); + return SERIALIZER; } public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(PendingFriendRequest value) { - JSONObject json = new JSONObject(); - json.put("from", value.from.toString()); - json.put("to", value.to.toString()); - json.put("fromName", value.fromName); - json.put("toName", value.toName); - json.put("timestamp", value.timestamp); - return json.toString(); - } - - @Override - public PendingFriendRequest deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new PendingFriendRequest( - UUID.fromString(jsonObject.getString("from")), - UUID.fromString(jsonObject.getString("to")), - jsonObject.optString("fromName", "Unknown"), - jsonObject.optString("toName", "Unknown"), - jsonObject.getLong("timestamp") - ); - } - - @Override - public PendingFriendRequest clone(PendingFriendRequest value) { - return new PendingFriendRequest(value.from, value.to, value.fromName, value.toName, value.timestamp); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendAcceptRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendAcceptRequestEvent.java index e3f766a09..0daacd6a2 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendAcceptRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendAcceptRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendAcceptRequestEvent extends FriendEvent { +public final class FriendAcceptRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendAcceptRequestEvent.class); + private final UUID accepter; private final UUID requester; @@ -29,28 +32,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendAcceptRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("accepter", value.accepter.toString()); - json.put("requester", value.requester.toString()); - return json.toString(); - } - - @Override - public FriendAcceptRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendAcceptRequestEvent( - UUID.fromString(jsonObject.getString("accepter")), - UUID.fromString(jsonObject.getString("requester")) - ); - } - - @Override - public FriendAcceptRequestEvent clone(FriendAcceptRequestEvent value) { - return new FriendAcceptRequestEvent(value.accepter, value.requester); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendAddRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendAddRequestEvent.java index c8b0b6499..89e65f1fb 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendAddRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendAddRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendAddRequestEvent extends FriendEvent { +public final class FriendAddRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendAddRequestEvent.class); + private final UUID sender; private final UUID target; @@ -29,28 +32,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendAddRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("sender", value.sender.toString()); - json.put("target", value.target.toString()); - return json.toString(); - } - - @Override - public FriendAddRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendAddRequestEvent( - UUID.fromString(jsonObject.getString("sender")), - UUID.fromString(jsonObject.getString("target")) - ); - } - - @Override - public FriendAddRequestEvent clone(FriendAddRequestEvent value) { - return new FriendAddRequestEvent(value.sender, value.target); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendDenyRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendDenyRequestEvent.java index 1f9471b91..614741c70 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendDenyRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendDenyRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendDenyRequestEvent extends FriendEvent { +public final class FriendDenyRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendDenyRequestEvent.class); + private final UUID denier; private final UUID requester; @@ -29,28 +32,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendDenyRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("denier", value.denier.toString()); - json.put("requester", value.requester.toString()); - return json.toString(); - } - - @Override - public FriendDenyRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendDenyRequestEvent( - UUID.fromString(jsonObject.getString("denier")), - UUID.fromString(jsonObject.getString("requester")) - ); - } - - @Override - public FriendDenyRequestEvent clone(FriendDenyRequestEvent value) { - return new FriendDenyRequestEvent(value.denier, value.requester); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendListRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendListRequestEvent.java index da60bea92..346392981 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendListRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendListRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendListRequestEvent extends FriendEvent { +public final class FriendListRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendListRequestEvent.class); + private final UUID player; private final int page; private final boolean bestOnly; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendListRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("page", value.page); - json.put("bestOnly", value.bestOnly); - return json.toString(); - } - - @Override - public FriendListRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendListRequestEvent( - UUID.fromString(jsonObject.getString("player")), - jsonObject.getInt("page"), - jsonObject.getBoolean("bestOnly") - ); - } - - @Override - public FriendListRequestEvent clone(FriendListRequestEvent value) { - return new FriendListRequestEvent(value.player, value.page, value.bestOnly); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveAllRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveAllRequestEvent.java index ea84ad532..8dbba9783 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveAllRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveAllRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRemoveAllRequestEvent extends FriendEvent { +public final class FriendRemoveAllRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRemoveAllRequestEvent.class); + private final UUID player; @JsonCreator @@ -27,26 +30,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRemoveAllRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - return json.toString(); - } - - @Override - public FriendRemoveAllRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRemoveAllRequestEvent( - UUID.fromString(jsonObject.getString("player")) - ); - } - - @Override - public FriendRemoveAllRequestEvent clone(FriendRemoveAllRequestEvent value) { - return new FriendRemoveAllRequestEvent(value.player); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveRequestEvent.java index 9806a28a3..0ce0b3ce8 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendRemoveRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRemoveRequestEvent extends FriendEvent { +public final class FriendRemoveRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRemoveRequestEvent.class); + private final UUID remover; private final UUID target; @@ -29,28 +32,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRemoveRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("remover", value.remover.toString()); - json.put("target", value.target.toString()); - return json.toString(); - } - - @Override - public FriendRemoveRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRemoveRequestEvent( - UUID.fromString(jsonObject.getString("remover")), - UUID.fromString(jsonObject.getString("target")) - ); - } - - @Override - public FriendRemoveRequestEvent clone(FriendRemoveRequestEvent value) { - return new FriendRemoveRequestEvent(value.remover, value.target); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendRequestsListEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendRequestsListEvent.java index e70fd689b..af44773f3 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendRequestsListEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendRequestsListEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRequestsListEvent extends FriendEvent { +public final class FriendRequestsListEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRequestsListEvent.class); + private final UUID player; private final int page; @@ -29,28 +32,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRequestsListEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("page", value.page); - return json.toString(); - } - - @Override - public FriendRequestsListEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRequestsListEvent( - UUID.fromString(jsonObject.getString("player")), - jsonObject.getInt("page") - ); - } - - @Override - public FriendRequestsListEvent clone(FriendRequestsListEvent value) { - return new FriendRequestsListEvent(value.player, value.page); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendSetNicknameRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendSetNicknameRequestEvent.java index f3e301292..b9a37ee5c 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendSetNicknameRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendSetNicknameRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendSetNicknameRequestEvent extends FriendEvent { +public final class FriendSetNicknameRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendSetNicknameRequestEvent.class); + private final UUID player; private final UUID target; private final String nickname; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendSetNicknameRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("target", value.target.toString()); - json.put("nickname", value.nickname != null ? value.nickname : JSONObject.NULL); - return json.toString(); - } - - @Override - public FriendSetNicknameRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendSetNicknameRequestEvent( - UUID.fromString(jsonObject.getString("player")), - UUID.fromString(jsonObject.getString("target")), - jsonObject.isNull("nickname") ? null : jsonObject.getString("nickname") - ); - } - - @Override - public FriendSetNicknameRequestEvent clone(FriendSetNicknameRequestEvent value) { - return new FriendSetNicknameRequestEvent(value.player, value.target, value.nickname); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleBestRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleBestRequestEvent.java index 9bffd85fd..8a1043819 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleBestRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleBestRequestEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendToggleBestRequestEvent extends FriendEvent { +public final class FriendToggleBestRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendToggleBestRequestEvent.class); + private final UUID player; private final UUID target; @@ -29,28 +32,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendToggleBestRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("target", value.target.toString()); - return json.toString(); - } - - @Override - public FriendToggleBestRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendToggleBestRequestEvent( - UUID.fromString(jsonObject.getString("player")), - UUID.fromString(jsonObject.getString("target")) - ); - } - - @Override - public FriendToggleBestRequestEvent clone(FriendToggleBestRequestEvent value) { - return new FriendToggleBestRequestEvent(value.player, value.target); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleSettingRequestEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleSettingRequestEvent.java index 5075a0bf3..e48c64081 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleSettingRequestEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/FriendToggleSettingRequestEvent.java @@ -5,14 +5,17 @@ import lombok.Getter; import net.swofty.commons.friend.FriendEvent; import net.swofty.commons.friend.FriendSettingType; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendToggleSettingRequestEvent extends FriendEvent { +public final class FriendToggleSettingRequestEvent extends FriendEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendToggleSettingRequestEvent.class); + private final UUID player; private final FriendSettingType settingType; @@ -30,28 +33,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendToggleSettingRequestEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("settingType", value.settingType.name()); - return json.toString(); - } - - @Override - public FriendToggleSettingRequestEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendToggleSettingRequestEvent( - UUID.fromString(jsonObject.getString("player")), - FriendSettingType.valueOf(jsonObject.getString("settingType")) - ); - } - - @Override - public FriendToggleSettingRequestEvent clone(FriendToggleSettingRequestEvent value) { - return new FriendToggleSettingRequestEvent(value.player, value.settingType); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendAddedResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendAddedResponseEvent.java index 930a0dc8e..421c43aa5 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendAddedResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendAddedResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendAddedResponseEvent extends FriendResponseEvent { +public final class FriendAddedResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendAddedResponseEvent.class); + private final UUID player1; private final UUID player2; private final String player1Name; @@ -33,32 +36,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendAddedResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("player1", value.player1.toString()); - json.put("player2", value.player2.toString()); - json.put("player1Name", value.player1Name); - json.put("player2Name", value.player2Name); - return json.toString(); - } - - @Override - public FriendAddedResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendAddedResponseEvent( - UUID.fromString(jsonObject.getString("player1")), - UUID.fromString(jsonObject.getString("player2")), - jsonObject.getString("player1Name"), - jsonObject.getString("player2Name") - ); - } - - @Override - public FriendAddedResponseEvent clone(FriendAddedResponseEvent value) { - return new FriendAddedResponseEvent(value.player1, value.player2, value.player1Name, value.player2Name); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendBestToggledResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendBestToggledResponseEvent.java index 43bdfe48e..5274e4b6c 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendBestToggledResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendBestToggledResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendBestToggledResponseEvent extends FriendResponseEvent { +public final class FriendBestToggledResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendBestToggledResponseEvent.class); + private final UUID player; private final UUID target; private final String targetName; @@ -33,32 +36,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendBestToggledResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("target", value.target.toString()); - json.put("targetName", value.targetName); - json.put("isBest", value.isBest); - return json.toString(); - } - - @Override - public FriendBestToggledResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendBestToggledResponseEvent( - UUID.fromString(jsonObject.getString("player")), - UUID.fromString(jsonObject.getString("target")), - jsonObject.getString("targetName"), - jsonObject.getBoolean("isBest") - ); - } - - @Override - public FriendBestToggledResponseEvent clone(FriendBestToggledResponseEvent value) { - return new FriendBestToggledResponseEvent(value.player, value.target, value.targetName, value.isBest); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendDeniedResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendDeniedResponseEvent.java index 3edec7a9c..acb3f873c 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendDeniedResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendDeniedResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendDeniedResponseEvent extends FriendResponseEvent { +public final class FriendDeniedResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendDeniedResponseEvent.class); + private final UUID denier; private final UUID requester; private final String denierName; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendDeniedResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("denier", value.denier.toString()); - json.put("requester", value.requester.toString()); - json.put("denierName", value.denierName); - return json.toString(); - } - - @Override - public FriendDeniedResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendDeniedResponseEvent( - UUID.fromString(jsonObject.getString("denier")), - UUID.fromString(jsonObject.getString("requester")), - jsonObject.getString("denierName") - ); - } - - @Override - public FriendDeniedResponseEvent clone(FriendDeniedResponseEvent value) { - return new FriendDeniedResponseEvent(value.denier, value.requester, value.denierName); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendJoinNotificationEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendJoinNotificationEvent.java index b02dcc2d7..ccf9f0727 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendJoinNotificationEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendJoinNotificationEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendJoinNotificationEvent extends FriendResponseEvent { +public final class FriendJoinNotificationEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendJoinNotificationEvent.class); + private final UUID player; private final UUID friend; private final String friendName; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendJoinNotificationEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("friend", value.friend.toString()); - json.put("friendName", value.friendName); - return json.toString(); - } - - @Override - public FriendJoinNotificationEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendJoinNotificationEvent( - UUID.fromString(jsonObject.getString("player")), - UUID.fromString(jsonObject.getString("friend")), - jsonObject.getString("friendName") - ); - } - - @Override - public FriendJoinNotificationEvent clone(FriendJoinNotificationEvent value) { - return new FriendJoinNotificationEvent(value.player, value.friend, value.friendName); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendLeaveNotificationEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendLeaveNotificationEvent.java index 0cd735b07..0957cb0c9 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendLeaveNotificationEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendLeaveNotificationEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendLeaveNotificationEvent extends FriendResponseEvent { +public final class FriendLeaveNotificationEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendLeaveNotificationEvent.class); + private final UUID player; private final UUID friend; private final String friendName; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendLeaveNotificationEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("friend", value.friend.toString()); - json.put("friendName", value.friendName); - return json.toString(); - } - - @Override - public FriendLeaveNotificationEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendLeaveNotificationEvent( - UUID.fromString(jsonObject.getString("player")), - UUID.fromString(jsonObject.getString("friend")), - jsonObject.getString("friendName") - ); - } - - @Override - public FriendLeaveNotificationEvent clone(FriendLeaveNotificationEvent value) { - return new FriendLeaveNotificationEvent(value.player, value.friend, value.friendName); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendListResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendListResponseEvent.java index 80a33e6c5..563ba4510 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendListResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendListResponseEvent.java @@ -4,16 +4,18 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONArray; -import org.json.JSONObject; import java.util.ArrayList; import java.util.List; import java.util.UUID; @Getter -public class FriendListResponseEvent extends FriendResponseEvent { +public final class FriendListResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendListResponseEvent.class); + private final UUID player; private final List friends; private final int page; @@ -37,67 +39,7 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendListResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - - JSONArray friendsArray = new JSONArray(); - for (FriendListEntry entry : value.friends) { - JSONObject entryJson = new JSONObject(); - entryJson.put("uuid", entry.uuid.toString()); - entryJson.put("name", entry.name); - entryJson.put("nickname", entry.nickname != null ? entry.nickname : JSONObject.NULL); - entryJson.put("isBest", entry.isBest); - entryJson.put("isOnline", entry.isOnline); - entryJson.put("lastSeen", entry.lastSeen); - entryJson.put("friendSince", entry.friendSince); - entryJson.put("server", entry.server != null ? entry.server : JSONObject.NULL); - friendsArray.put(entryJson); - } - json.put("friends", friendsArray); - - json.put("page", value.page); - json.put("totalPages", value.totalPages); - json.put("bestOnly", value.bestOnly); - return json.toString(); - } - - @Override - public FriendListResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - - List friends = new ArrayList<>(); - JSONArray friendsArray = jsonObject.getJSONArray("friends"); - for (int i = 0; i < friendsArray.length(); i++) { - JSONObject entryJson = friendsArray.getJSONObject(i); - friends.add(new FriendListEntry( - UUID.fromString(entryJson.getString("uuid")), - entryJson.getString("name"), - entryJson.isNull("nickname") ? null : entryJson.getString("nickname"), - entryJson.getBoolean("isBest"), - entryJson.getBoolean("isOnline"), - entryJson.optLong("lastSeen", 0L), - entryJson.optLong("friendSince", 0L), - entryJson.isNull("server") ? null : entryJson.getString("server") - )); - } - - return new FriendListResponseEvent( - UUID.fromString(jsonObject.getString("player")), - friends, - jsonObject.getInt("page"), - jsonObject.getInt("totalPages"), - jsonObject.getBoolean("bestOnly") - ); - } - - @Override - public FriendListResponseEvent clone(FriendListResponseEvent value) { - return new FriendListResponseEvent(value.player, new ArrayList<>(value.friends), value.page, value.totalPages, value.bestOnly); - } - }; + return SERIALIZER; } @Getter diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendNicknameSetResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendNicknameSetResponseEvent.java index 0f7bcea73..b71f5c33b 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendNicknameSetResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendNicknameSetResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendNicknameSetResponseEvent extends FriendResponseEvent { +public final class FriendNicknameSetResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendNicknameSetResponseEvent.class); + private final UUID player; private final UUID target; private final String targetName; @@ -33,32 +36,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendNicknameSetResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("target", value.target.toString()); - json.put("targetName", value.targetName); - json.put("nickname", value.nickname != null ? value.nickname : JSONObject.NULL); - return json.toString(); - } - - @Override - public FriendNicknameSetResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendNicknameSetResponseEvent( - UUID.fromString(jsonObject.getString("player")), - UUID.fromString(jsonObject.getString("target")), - jsonObject.getString("targetName"), - jsonObject.isNull("nickname") ? null : jsonObject.getString("nickname") - ); - } - - @Override - public FriendNicknameSetResponseEvent clone(FriendNicknameSetResponseEvent value) { - return new FriendNicknameSetResponseEvent(value.player, value.target, value.targetName, value.nickname); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemoveAllResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemoveAllResponseEvent.java index 95ac65804..ec49cf23b 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemoveAllResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemoveAllResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRemoveAllResponseEvent extends FriendResponseEvent { +public final class FriendRemoveAllResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRemoveAllResponseEvent.class); + private final UUID player; private final int removedCount; @@ -29,28 +32,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRemoveAllResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("removedCount", value.removedCount); - return json.toString(); - } - - @Override - public FriendRemoveAllResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRemoveAllResponseEvent( - UUID.fromString(jsonObject.getString("player")), - jsonObject.getInt("removedCount") - ); - } - - @Override - public FriendRemoveAllResponseEvent clone(FriendRemoveAllResponseEvent value) { - return new FriendRemoveAllResponseEvent(value.player, value.removedCount); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemovedResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemovedResponseEvent.java index e8ceeb569..f2be032f5 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemovedResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRemovedResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRemovedResponseEvent extends FriendResponseEvent { +public final class FriendRemovedResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRemovedResponseEvent.class); + private final UUID remover; private final UUID removed; private final String removerName; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRemovedResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("remover", value.remover.toString()); - json.put("removed", value.removed.toString()); - json.put("removerName", value.removerName); - return json.toString(); - } - - @Override - public FriendRemovedResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRemovedResponseEvent( - UUID.fromString(jsonObject.getString("remover")), - UUID.fromString(jsonObject.getString("removed")), - jsonObject.getString("removerName") - ); - } - - @Override - public FriendRemovedResponseEvent clone(FriendRemovedResponseEvent value) { - return new FriendRemovedResponseEvent(value.remover, value.removed, value.removerName); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestExpiredResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestExpiredResponseEvent.java index 29050cc34..40d7d2755 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestExpiredResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestExpiredResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRequestExpiredResponseEvent extends FriendResponseEvent { +public final class FriendRequestExpiredResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRequestExpiredResponseEvent.class); + private final UUID sender; private final UUID target; private final String senderName; @@ -33,32 +36,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRequestExpiredResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("sender", value.sender.toString()); - json.put("target", value.target.toString()); - json.put("senderName", value.senderName); - json.put("targetName", value.targetName); - return json.toString(); - } - - @Override - public FriendRequestExpiredResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRequestExpiredResponseEvent( - UUID.fromString(jsonObject.getString("sender")), - UUID.fromString(jsonObject.getString("target")), - jsonObject.getString("senderName"), - jsonObject.getString("targetName") - ); - } - - @Override - public FriendRequestExpiredResponseEvent clone(FriendRequestExpiredResponseEvent value) { - return new FriendRequestExpiredResponseEvent(value.sender, value.target, value.senderName, value.targetName); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestReceivedResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestReceivedResponseEvent.java index 0c19b1962..67d736661 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestReceivedResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestReceivedResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRequestReceivedResponseEvent extends FriendResponseEvent { +public final class FriendRequestReceivedResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRequestReceivedResponseEvent.class); + private final UUID sender; private final UUID target; private final String senderName; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRequestReceivedResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("sender", value.sender.toString()); - json.put("target", value.target.toString()); - json.put("senderName", value.senderName); - return json.toString(); - } - - @Override - public FriendRequestReceivedResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRequestReceivedResponseEvent( - UUID.fromString(jsonObject.getString("sender")), - UUID.fromString(jsonObject.getString("target")), - jsonObject.getString("senderName") - ); - } - - @Override - public FriendRequestReceivedResponseEvent clone(FriendRequestReceivedResponseEvent value) { - return new FriendRequestReceivedResponseEvent(value.sender, value.target, value.senderName); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestSentResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestSentResponseEvent.java index b786468d2..1259fd9e6 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestSentResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestSentResponseEvent.java @@ -4,14 +4,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendRequestSentResponseEvent extends FriendResponseEvent { +public final class FriendRequestSentResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRequestSentResponseEvent.class); + private final UUID sender; private final UUID target; private final String targetName; @@ -31,30 +34,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRequestSentResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("sender", value.sender.toString()); - json.put("target", value.target.toString()); - json.put("targetName", value.targetName); - return json.toString(); - } - - @Override - public FriendRequestSentResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendRequestSentResponseEvent( - UUID.fromString(jsonObject.getString("sender")), - UUID.fromString(jsonObject.getString("target")), - jsonObject.getString("targetName") - ); - } - - @Override - public FriendRequestSentResponseEvent clone(FriendRequestSentResponseEvent value) { - return new FriendRequestSentResponseEvent(value.sender, value.target, value.targetName); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestsListResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestsListResponseEvent.java index 1d301dd1c..86374d608 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestsListResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendRequestsListResponseEvent.java @@ -4,16 +4,18 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONArray; -import org.json.JSONObject; import java.util.ArrayList; import java.util.List; import java.util.UUID; @Getter -public class FriendRequestsListResponseEvent extends FriendResponseEvent { +public final class FriendRequestsListResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendRequestsListResponseEvent.class); + private final UUID player; private final List requests; private final int page; @@ -35,55 +37,7 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendRequestsListResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - - JSONArray requestsArray = new JSONArray(); - for (FriendRequestEntry entry : value.requests) { - JSONObject entryJson = new JSONObject(); - entryJson.put("senderUuid", entry.senderUuid.toString()); - entryJson.put("senderName", entry.senderName); - entryJson.put("timestamp", entry.timestamp); - requestsArray.put(entryJson); - } - json.put("requests", requestsArray); - - json.put("page", value.page); - json.put("totalPages", value.totalPages); - return json.toString(); - } - - @Override - public FriendRequestsListResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - - List requests = new ArrayList<>(); - JSONArray requestsArray = jsonObject.getJSONArray("requests"); - for (int i = 0; i < requestsArray.length(); i++) { - JSONObject entryJson = requestsArray.getJSONObject(i); - requests.add(new FriendRequestEntry( - UUID.fromString(entryJson.getString("senderUuid")), - entryJson.getString("senderName"), - entryJson.getLong("timestamp") - )); - } - - return new FriendRequestsListResponseEvent( - UUID.fromString(jsonObject.getString("player")), - requests, - jsonObject.getInt("page"), - jsonObject.getInt("totalPages") - ); - } - - @Override - public FriendRequestsListResponseEvent clone(FriendRequestsListResponseEvent value) { - return new FriendRequestsListResponseEvent(value.player, new ArrayList<>(value.requests), value.page, value.totalPages); - } - }; + return SERIALIZER; } @Getter diff --git a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendSettingToggledResponseEvent.java b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendSettingToggledResponseEvent.java index a85f0f040..1a189515d 100644 --- a/commons/src/main/java/net/swofty/commons/friend/events/response/FriendSettingToggledResponseEvent.java +++ b/commons/src/main/java/net/swofty/commons/friend/events/response/FriendSettingToggledResponseEvent.java @@ -5,14 +5,17 @@ import lombok.Getter; import net.swofty.commons.friend.FriendResponseEvent; import net.swofty.commons.friend.FriendSettingType; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.List; import java.util.UUID; @Getter -public class FriendSettingToggledResponseEvent extends FriendResponseEvent { +public final class FriendSettingToggledResponseEvent extends FriendResponseEvent { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(FriendSettingToggledResponseEvent.class); + private final UUID player; private final FriendSettingType settingType; private final boolean newValue; @@ -32,30 +35,6 @@ public List getParticipants() { @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(FriendSettingToggledResponseEvent value) { - JSONObject json = new JSONObject(); - json.put("player", value.player.toString()); - json.put("settingType", value.settingType.name()); - json.put("newValue", value.newValue); - return json.toString(); - } - - @Override - public FriendSettingToggledResponseEvent deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new FriendSettingToggledResponseEvent( - UUID.fromString(jsonObject.getString("player")), - FriendSettingType.valueOf(jsonObject.getString("settingType")), - jsonObject.getBoolean("newValue") - ); - } - - @Override - public FriendSettingToggledResponseEvent clone(FriendSettingToggledResponseEvent value) { - return new FriendSettingToggledResponseEvent(value.player, value.settingType, value.newValue); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/impl/ServiceProxyRequest.java b/commons/src/main/java/net/swofty/commons/impl/ServiceProxyRequest.java deleted file mode 100644 index d87a4cc67..000000000 --- a/commons/src/main/java/net/swofty/commons/impl/ServiceProxyRequest.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.swofty.commons.impl; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; -import org.json.JSONObject; - -import java.util.UUID; - -@AllArgsConstructor -@Getter -@Setter -public class ServiceProxyRequest { - private UUID requestId; - private String requestServer; - private String endpoint; - private String message; - - public JSONObject toJSON() { - return new JSONObject() - .put("requestId", requestId.toString()) - .put("requestServer", requestServer) - .put("endpoint", endpoint) - .put("message", message); - } - - public static ServiceProxyRequest fromJSON(JSONObject json) { - return new ServiceProxyRequest( - UUID.fromString(json.getString("requestId")), - json.getString("requestServer"), - json.getString("endpoint"), - json.getString("message") - ); - } -} diff --git a/commons/src/main/java/net/swofty/commons/presence/PresenceInfo.java b/commons/src/main/java/net/swofty/commons/presence/PresenceInfo.java index cacacd1f0..522972cea 100644 --- a/commons/src/main/java/net/swofty/commons/presence/PresenceInfo.java +++ b/commons/src/main/java/net/swofty/commons/presence/PresenceInfo.java @@ -3,13 +3,15 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; +import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import java.util.UUID; @Getter public class PresenceInfo { + private static final Serializer SERIALIZER = new JacksonSerializer<>(PresenceInfo.class); + private final UUID uuid; private final boolean online; private final String serverType; @@ -31,34 +33,6 @@ public PresenceInfo( } public static Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(PresenceInfo value) { - JSONObject json = new JSONObject(); - json.put("uuid", value.uuid.toString()); - json.put("online", value.online); - json.put("serverType", value.serverType != null ? value.serverType : JSONObject.NULL); - json.put("serverId", value.serverId != null ? value.serverId : JSONObject.NULL); - json.put("lastSeen", value.lastSeen); - return json.toString(); - } - - @Override - public PresenceInfo deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new PresenceInfo( - UUID.fromString(jsonObject.getString("uuid")), - jsonObject.getBoolean("online"), - jsonObject.isNull("serverType") ? null : jsonObject.getString("serverType"), - jsonObject.isNull("serverId") ? null : jsonObject.getString("serverId"), - jsonObject.getLong("lastSeen") - ); - } - - @Override - public PresenceInfo clone(PresenceInfo value) { - return new PresenceInfo(value.uuid, value.online, value.serverType, value.serverId, value.lastSeen); - } - }; + return SERIALIZER; } } diff --git a/commons/src/main/java/net/swofty/commons/protocol/ProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/ProtocolObject.java deleted file mode 100644 index b60d56f6b..000000000 --- a/commons/src/main/java/net/swofty/commons/protocol/ProtocolObject.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.swofty.commons.protocol; - -public abstract class ProtocolObject { - public abstract Serializer getSerializer(); - public abstract Serializer getReturnSerializer(); - - public String translateToString(T message) { - return getSerializer().serialize(message); - } - - public String translateReturnToString(R message) { - return getReturnSerializer().serialize(message); - } - - public T translateFromString(String string) { - return getSerializer().deserialize(string); - } - - public R translateReturnFromString(String string) { - return getReturnSerializer().deserialize(string); - } - - public String channel() { - return getClass().getSimpleName(); - } -} diff --git a/commons/src/main/java/net/swofty/commons/protocol/RedisProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/RedisProtocol.java new file mode 100644 index 000000000..b5c760173 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/RedisProtocol.java @@ -0,0 +1,54 @@ +package net.swofty.commons.protocol; + +public abstract class RedisProtocol { + private final Serializer serializer; + private final Serializer returnSerializer; + + protected RedisProtocol() { + this.serializer = null; + this.returnSerializer = null; + } + + protected RedisProtocol(Class requestType, Class responseType) { + this(new JacksonSerializer<>(requestType), new JacksonSerializer<>(responseType)); + } + + protected RedisProtocol(Serializer serializer, Serializer returnSerializer) { + this.serializer = serializer; + this.returnSerializer = returnSerializer; + } + + public Serializer getSerializer() { + if (serializer == null) { + throw new UnsupportedOperationException("Protocol must provide a request serializer"); + } + return serializer; + } + + public Serializer getReturnSerializer() { + if (returnSerializer == null) { + throw new UnsupportedOperationException("Protocol must provide a response serializer"); + } + return returnSerializer; + } + + public String translateToString(T message) { + return getSerializer().serialize(message); + } + + public String translateReturnToString(R message) { + return getReturnSerializer().serialize(message); + } + + public T translateFromString(String string) { + return getSerializer().deserialize(string); + } + + public R translateReturnFromString(String string) { + return getReturnSerializer().deserialize(string); + } + + public String channel() { + return getClass().getSimpleName(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/ServicePushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/ServicePushProtocol.java deleted file mode 100644 index 3cc25f164..000000000 --- a/commons/src/main/java/net/swofty/commons/protocol/ServicePushProtocol.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.swofty.commons.protocol; - -public abstract class ServicePushProtocol extends ProtocolObject { - private final JacksonSerializer requestSerializer; - private final JacksonSerializer responseSerializer; - - protected ServicePushProtocol(Class requestType, Class responseType) { - this.requestSerializer = new JacksonSerializer<>(requestType); - this.responseSerializer = new JacksonSerializer<>(responseType); - } - - @Override - public Serializer getSerializer() { - return requestSerializer; - } - - @Override - public Serializer getReturnSerializer() { - return responseSerializer; - } -} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/PingProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/PingProtocol.java new file mode 100644 index 000000000..1ea376f24 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/PingProtocol.java @@ -0,0 +1,26 @@ +package net.swofty.commons.protocol.objects; + +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.Serializer; + +public class PingProtocol extends RedisProtocol< + PingProtocol.EmptyMessage, + PingProtocol.EmptyMessage> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(EmptyMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(EmptyMessage.class); + + @Override + public Serializer getSerializer() { + return SERIALIZER; + } + + @Override + public Serializer getReturnSerializer() { + return RETURN_SERIALIZER; + } + + public record EmptyMessage() {} +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/PingProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/PingProtocolObject.java deleted file mode 100644 index 59f8645d4..000000000 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/PingProtocolObject.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.swofty.commons.protocol.objects; - -import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.Serializer; - -public class PingProtocolObject extends ProtocolObject< - PingProtocolObject.EmptyMessage, - PingProtocolObject.EmptyMessage> { - - @Override - public Serializer getSerializer() { - return new JacksonSerializer<>(EmptyMessage.class); - } - - @Override - public Serializer getReturnSerializer() { - return new JacksonSerializer<>(EmptyMessage.class); - } - - public record EmptyMessage() {} -} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/api/APIAuthenticateCodeProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/api/APIAuthenticateCodeProtocol.java new file mode 100644 index 000000000..8f06f5a3c --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/api/APIAuthenticateCodeProtocol.java @@ -0,0 +1,36 @@ +package net.swofty.commons.protocol.objects.api; + +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.Serializer; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class APIAuthenticateCodeProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(AuthenticateCodeMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(AuthenticateCodeResponse.class); + + @Override + + public Serializer getSerializer() { + + return SERIALIZER; + + } + + @Override + + public Serializer getReturnSerializer() { + + return RETURN_SERIALIZER; + + } + + public record AuthenticateCodeMessage(String authCode, String playerName, UUID playerUUID) {} + + public record AuthenticateCodeResponse(boolean success, @Nullable String error) {} +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/api/APIAuthenticateCodeProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/api/APIAuthenticateCodeProtocolObject.java deleted file mode 100644 index 8a708541e..000000000 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/api/APIAuthenticateCodeProtocolObject.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.swofty.commons.protocol.objects.api; - -import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.Serializer; -import org.jetbrains.annotations.Nullable; - -import java.util.UUID; - -public class APIAuthenticateCodeProtocolObject extends ProtocolObject - { - - @Override - public Serializer getSerializer() { - return new JacksonSerializer<>(AuthenticateCodeMessage.class); - } - - @Override - public Serializer getReturnSerializer() { - return new JacksonSerializer<>(AuthenticateCodeResponse.class); - } - - public record AuthenticateCodeMessage(String authCode, String playerName, UUID playerUUID) {} - - public record AuthenticateCodeResponse(boolean success, @Nullable String error) {} -} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionAddItemProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionAddItemProtocol.java similarity index 55% rename from commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionAddItemProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionAddItemProtocol.java index 1990ca6c4..6ad26f5d9 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionAddItemProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionAddItemProtocol.java @@ -3,24 +3,34 @@ import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionItem; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class AuctionAddItemProtocolObject extends ProtocolObject - { +public class AuctionAddItemProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(AuctionAddItemMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(AuctionAddItemResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(AuctionAddItemMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(AuctionAddItemResponse.class); + + return RETURN_SERIALIZER; + } public record AuctionAddItemMessage(AuctionItem item, AuctionCategories category) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemProtocol.java similarity index 51% rename from commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemProtocol.java index aee64d73f..3529a3af2 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemProtocol.java @@ -2,24 +2,28 @@ import net.swofty.commons.protocol.JacksonSerializer; import net.swofty.commons.skyblock.auctions.AuctionItem; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class AuctionFetchItemProtocolObject extends ProtocolObject< - AuctionFetchItemProtocolObject.AuctionFetchItemMessage, - AuctionFetchItemProtocolObject.AuctionFetchItemResponse> { +public class AuctionFetchItemProtocol extends RedisProtocol< + AuctionFetchItemProtocol.AuctionFetchItemMessage, + AuctionFetchItemProtocol.AuctionFetchItemResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(AuctionFetchItemMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(AuctionFetchItemResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(AuctionFetchItemMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(AuctionFetchItemResponse.class); + return RETURN_SERIALIZER; } public record AuctionFetchItemMessage(UUID uuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemsProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemsProtocol.java similarity index 62% rename from commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemsProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemsProtocol.java index 4376c6d33..b5b43f18b 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemsProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/auctions/AuctionFetchItemsProtocol.java @@ -4,25 +4,29 @@ import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionsFilter; import net.swofty.commons.skyblock.auctions.AuctionsSorting; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import net.swofty.commons.skyblock.auctions.AuctionItem; import java.util.List; import org.jetbrains.annotations.Nullable; -public class AuctionFetchItemsProtocolObject extends ProtocolObject< - AuctionFetchItemsProtocolObject.AuctionFetchItemsMessage, - AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse> { +public class AuctionFetchItemsProtocol extends RedisProtocol< + AuctionFetchItemsProtocol.AuctionFetchItemsMessage, + AuctionFetchItemsProtocol.AuctionFetchItemsResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(AuctionFetchItemsMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(AuctionFetchItemsResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(AuctionFetchItemsMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(AuctionFetchItemsResponse.class); + return RETURN_SERIALIZER; } public record AuctionFetchItemsMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarBuyProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarBuyProtocol.java similarity index 53% rename from commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarBuyProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarBuyProtocol.java index 6b13837f2..c026fc4d9 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarBuyProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarBuyProtocol.java @@ -1,23 +1,33 @@ package net.swofty.commons.protocol.objects.bazaar; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; import java.util.UUID; -public class BazaarBuyProtocolObject extends ProtocolObject - { +public class BazaarBuyProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(BazaarBuyMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(BazaarBuyResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(BazaarBuyMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(BazaarBuyResponse.class); + + return RETURN_SERIALIZER; + } public record BazaarBuyMessage(String itemName, int amount, double price, UUID playerUUID, UUID profileUUID) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarCancelProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarCancelProtocol.java similarity index 51% rename from commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarCancelProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarCancelProtocol.java index 1f3fe2252..d73cbad6c 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarCancelProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarCancelProtocol.java @@ -1,24 +1,28 @@ package net.swofty.commons.protocol.objects.bazaar; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; import java.util.UUID; -public class BazaarCancelProtocolObject extends ProtocolObject< - BazaarCancelProtocolObject.CancelMessage, - BazaarCancelProtocolObject.CancelResponse> { +public class BazaarCancelProtocol extends RedisProtocol< + BazaarCancelProtocol.CancelMessage, + BazaarCancelProtocol.CancelResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(CancelMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(CancelResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(CancelMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(CancelResponse.class); + return RETURN_SERIALIZER; } public record CancelMessage(UUID orderId, UUID playerUuid, UUID profileUuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetItemProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetItemProtocol.java similarity index 60% rename from commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetItemProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetItemProtocol.java index 6eef19f80..65a38d7b9 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetItemProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetItemProtocol.java @@ -1,25 +1,29 @@ package net.swofty.commons.protocol.objects.bazaar; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class BazaarGetItemProtocolObject extends ProtocolObject< - BazaarGetItemProtocolObject.BazaarGetItemMessage, - BazaarGetItemProtocolObject.BazaarGetItemResponse> { +public class BazaarGetItemProtocol extends RedisProtocol< + BazaarGetItemProtocol.BazaarGetItemMessage, + BazaarGetItemProtocol.BazaarGetItemResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(BazaarGetItemMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(BazaarGetItemResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(BazaarGetItemMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(BazaarGetItemResponse.class); + return RETURN_SERIALIZER; } public record BazaarGetItemMessage(String itemName) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingOrdersProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingOrdersProtocol.java similarity index 56% rename from commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingOrdersProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingOrdersProtocol.java index c3c12b2c7..af4070fbc 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingOrdersProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingOrdersProtocol.java @@ -1,26 +1,30 @@ package net.swofty.commons.protocol.objects.bazaar; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class BazaarGetPendingOrdersProtocolObject - extends ProtocolObject< - BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersMessage, - BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersResponse> { +public class BazaarGetPendingOrdersProtocol + extends RedisProtocol< + BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersMessage, + BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(BazaarGetPendingOrdersMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(BazaarGetPendingOrdersResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(BazaarGetPendingOrdersMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(BazaarGetPendingOrdersResponse.class); + return RETURN_SERIALIZER; } public record BazaarGetPendingOrdersMessage(UUID playerUUID, UUID profileUUID) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingTransactionsProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingTransactionsProtocol.java similarity index 57% rename from commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingTransactionsProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingTransactionsProtocol.java index 4d06f9150..3a39ab1dd 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingTransactionsProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarGetPendingTransactionsProtocol.java @@ -1,7 +1,7 @@ package net.swofty.commons.protocol.objects.bazaar; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.time.Instant; @@ -10,18 +10,22 @@ import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class BazaarGetPendingTransactionsProtocolObject extends ProtocolObject< - BazaarGetPendingTransactionsProtocolObject.BazaarGetPendingTransactionsMessage, - BazaarGetPendingTransactionsProtocolObject.BazaarGetPendingTransactionsResponse> { +public class BazaarGetPendingTransactionsProtocol extends RedisProtocol< + BazaarGetPendingTransactionsProtocol.BazaarGetPendingTransactionsMessage, + BazaarGetPendingTransactionsProtocol.BazaarGetPendingTransactionsResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(BazaarGetPendingTransactionsMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(BazaarGetPendingTransactionsResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(BazaarGetPendingTransactionsMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(BazaarGetPendingTransactionsResponse.class); + return RETURN_SERIALIZER; } public record BazaarGetPendingTransactionsMessage(UUID playerUUID, UUID profileUUID) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarProcessPendingTransactionsProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarProcessPendingTransactionsProtocol.java similarity index 52% rename from commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarProcessPendingTransactionsProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarProcessPendingTransactionsProtocol.java index fc4380784..74a55c440 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarProcessPendingTransactionsProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarProcessPendingTransactionsProtocol.java @@ -1,25 +1,29 @@ package net.swofty.commons.protocol.objects.bazaar; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class BazaarProcessPendingTransactionsProtocolObject extends ProtocolObject< - BazaarProcessPendingTransactionsProtocolObject.BazaarProcessPendingTransactionsMessage, - BazaarProcessPendingTransactionsProtocolObject.BazaarProcessPendingTransactionsResponse> { +public class BazaarProcessPendingTransactionsProtocol extends RedisProtocol< + BazaarProcessPendingTransactionsProtocol.BazaarProcessPendingTransactionsMessage, + BazaarProcessPendingTransactionsProtocol.BazaarProcessPendingTransactionsResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(BazaarProcessPendingTransactionsMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(BazaarProcessPendingTransactionsResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(BazaarProcessPendingTransactionsMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(BazaarProcessPendingTransactionsResponse.class); + return RETURN_SERIALIZER; } public record BazaarProcessPendingTransactionsMessage(UUID playerUUID, UUID profileUUID, List transactionIds) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarSellProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarSellProtocol.java similarity index 52% rename from commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarSellProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarSellProtocol.java index 193f14844..132cb0ed8 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarSellProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarSellProtocol.java @@ -1,24 +1,28 @@ package net.swofty.commons.protocol.objects.bazaar; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; import java.util.UUID; -public class BazaarSellProtocolObject extends ProtocolObject< - BazaarSellProtocolObject.BazaarSellMessage, - BazaarSellProtocolObject.BazaarSellResponse> { +public class BazaarSellProtocol extends RedisProtocol< + BazaarSellProtocol.BazaarSellMessage, + BazaarSellProtocol.BazaarSellResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(BazaarSellMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(BazaarSellResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(BazaarSellMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(BazaarSellResponse.class); + return RETURN_SERIALIZER; } public record BazaarSellMessage(String itemName, UUID playerUUID, UUID profileUUID, Double price, int amount) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarTransactionPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarTransactionPushProtocol.java index 311ba02fb..793f6e1d4 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarTransactionPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/bazaar/BazaarTransactionPushProtocol.java @@ -1,10 +1,10 @@ package net.swofty.commons.protocol.objects.bazaar; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import org.jetbrains.annotations.Nullable; public class BazaarTransactionPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public BazaarTransactionPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventProtocol.java index cbddc1e1d..c8fd72b94 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventProtocol.java @@ -1,17 +1,15 @@ package net.swofty.commons.protocol.objects.darkauction; -import net.swofty.commons.skyblock.auctions.DarkAuctionPhase; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -import org.json.JSONArray; -import org.json.JSONObject; +import net.swofty.commons.skyblock.auctions.DarkAuctionPhase; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; import java.util.UUID; -import org.jetbrains.annotations.Nullable; -public class DarkAuctionEventProtocol extends ProtocolObject< +public class DarkAuctionEventProtocol extends RedisProtocol< DarkAuctionEventProtocol.DarkAuctionMessage, DarkAuctionEventProtocol.DarkAuctionResponse> { @@ -24,105 +22,19 @@ public enum EventType { AUCTION_END // Auction complete, cleanup } + private static final Serializer MESSAGE_SERIALIZER = + new JacksonSerializer<>(DarkAuctionMessage.class); + private static final Serializer RESPONSE_SERIALIZER = + new JacksonSerializer<>(DarkAuctionResponse.class); + @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(DarkAuctionMessage value) { - JSONObject json = new JSONObject(); - json.put("eventType", value.eventType.name()); - json.put("auctionId", value.auctionId.toString()); - json.put("phase", value.phase.name()); - json.put("currentRound", value.currentRound); - json.put("currentItemType", value.currentItemType); - json.put("currentBid", value.currentBid); - json.put("highestBidderId", value.highestBidderId != null ? value.highestBidderId.toString() : null); - json.put("highestBidderName", value.highestBidderName); - json.put("countdown", value.countdown); - - JSONArray itemsArray = new JSONArray(); - for (String item : value.roundItems) { - itemsArray.put(item); - } - json.put("roundItems", itemsArray); - - // Refund info for BID_PLACED events - json.put("refundPlayerId", value.refundPlayerId != null ? value.refundPlayerId.toString() : null); - json.put("refundAmount", value.refundAmount); - - return json.toString(); - } - - @Override - public DarkAuctionMessage deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - - EventType eventType = EventType.valueOf(jsonObject.getString("eventType")); - UUID auctionId = UUID.fromString(jsonObject.getString("auctionId")); - DarkAuctionPhase phase = DarkAuctionPhase.valueOf(jsonObject.getString("phase")); - int currentRound = jsonObject.getInt("currentRound"); - String currentItemType = jsonObject.optString("currentItemType", null); - long currentBid = jsonObject.getLong("currentBid"); - - String bidderIdStr = jsonObject.optString("highestBidderId", null); - UUID highestBidderId = bidderIdStr != null && !bidderIdStr.equals("null") ? UUID.fromString(bidderIdStr) : null; - String highestBidderName = jsonObject.optString("highestBidderName", null); - int countdown = jsonObject.getInt("countdown"); - - List roundItems = new ArrayList<>(); - JSONArray itemsArray = jsonObject.optJSONArray("roundItems"); - if (itemsArray != null) { - for (int i = 0; i < itemsArray.length(); i++) { - roundItems.add(itemsArray.getString(i)); - } - } - - String refundPlayerIdStr = jsonObject.optString("refundPlayerId", null); - UUID refundPlayerId = refundPlayerIdStr != null && !refundPlayerIdStr.equals("null") ? UUID.fromString(refundPlayerIdStr) : null; - long refundAmount = jsonObject.optLong("refundAmount", 0); - - return new DarkAuctionMessage(eventType, auctionId, phase, currentRound, currentItemType, - currentBid, highestBidderId, highestBidderName, countdown, roundItems, - refundPlayerId, refundAmount); - } - - @Override - public DarkAuctionMessage clone(DarkAuctionMessage value) { - return new DarkAuctionMessage(value.eventType, value.auctionId, value.phase, value.currentRound, - value.currentItemType, value.currentBid, value.highestBidderId, - value.highestBidderName, value.countdown, new ArrayList<>(value.roundItems), - value.refundPlayerId, value.refundAmount); - } - }; + return MESSAGE_SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new Serializer<>() { - @Override - public String serialize(DarkAuctionResponse value) { - JSONObject json = new JSONObject(); - json.put("success", value.success); - json.put("playersInAuction", value.playersInAuction); - json.put("error", value.error); - return json.toString(); - } - - @Override - public DarkAuctionResponse deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new DarkAuctionResponse( - jsonObject.getBoolean("success"), - jsonObject.getInt("playersInAuction"), - jsonObject.optString("error", null) - ); - } - - @Override - public DarkAuctionResponse clone(DarkAuctionResponse value) { - return new DarkAuctionResponse(value.success, value.playersInAuction, value.error); - } - }; + return RESPONSE_SERIALIZER; } public record DarkAuctionMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventPushProtocol.java index 620db6b04..85a3d5f79 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/DarkAuctionEventPushProtocol.java @@ -1,12 +1,12 @@ package net.swofty.commons.protocol.objects.darkauction; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.List; import java.util.UUID; public class DarkAuctionEventPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public DarkAuctionEventPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/GetAuctionStateProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/GetAuctionStateProtocol.java index 410055545..4536545e7 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/GetAuctionStateProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/GetAuctionStateProtocol.java @@ -1,109 +1,31 @@ package net.swofty.commons.protocol.objects.darkauction; -import net.swofty.commons.skyblock.auctions.DarkAuctionPhase; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -import org.json.JSONArray; -import org.json.JSONObject; +import net.swofty.commons.skyblock.auctions.DarkAuctionPhase; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; import java.util.UUID; -import org.jetbrains.annotations.Nullable; -public class GetAuctionStateProtocol extends ProtocolObject< +public class GetAuctionStateProtocol extends RedisProtocol< GetAuctionStateProtocol.GetAuctionStateMessage, GetAuctionStateProtocol.GetAuctionStateResponse> { + private static final Serializer MESSAGE_SERIALIZER = + new JacksonSerializer<>(GetAuctionStateMessage.class); + private static final Serializer RESPONSE_SERIALIZER = + new JacksonSerializer<>(GetAuctionStateResponse.class); + @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(GetAuctionStateMessage value) { - return ""; - } - - @Override - public GetAuctionStateMessage deserialize(String json) { - return new GetAuctionStateMessage(); - } - - @Override - public GetAuctionStateMessage clone(GetAuctionStateMessage value) { - return new GetAuctionStateMessage(); - } - }; + return MESSAGE_SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new Serializer<>() { - @Override - public String serialize(GetAuctionStateResponse value) { - JSONObject json = new JSONObject(); - json.put("auctionActive", value.auctionActive); - json.put("success", value.success); - json.put("error", value.error); - if (value.auctionActive) { - json.put("auctionId", value.auctionId.toString()); - json.put("phase", value.phase.toString()); - json.put("currentRound", value.currentRound); - json.put("currentItemType", value.currentItemType); - json.put("currentBid", value.currentBid); - json.put("highestBidderId", value.highestBidderId != null ? value.highestBidderId.toString() : null); - json.put("highestBidderName", value.highestBidderName); - - JSONArray itemsArray = new JSONArray(); - for (String item : value.roundItems) { - itemsArray.put(item); - } - json.put("roundItems", itemsArray); - } - return json.toString(); - } - - @Override - public GetAuctionStateResponse deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - boolean auctionActive = jsonObject.getBoolean("auctionActive"); - boolean success = jsonObject.optBoolean("success", true); - String error = jsonObject.optString("error", null); - if ("null".equals(error)) error = null; - - if (!auctionActive) { - return new GetAuctionStateResponse(false, null, null, 0, null, 0, null, null, List.of(), success, error); - } - - UUID auctionId = UUID.fromString(jsonObject.getString("auctionId")); - String phase = jsonObject.getString("phase"); - int currentRound = jsonObject.getInt("currentRound"); - String currentItemType = jsonObject.optString("currentItemType", null); - long currentBid = jsonObject.getLong("currentBid"); - - String bidderIdStr = jsonObject.optString("highestBidderId", null); - UUID highestBidderId = bidderIdStr != null && !bidderIdStr.equals("null") ? UUID.fromString(bidderIdStr) : null; - String highestBidderName = jsonObject.optString("highestBidderName", null); - - List roundItems = new ArrayList<>(); - JSONArray itemsArray = jsonObject.optJSONArray("roundItems"); - if (itemsArray != null) { - for (int i = 0; i < itemsArray.length(); i++) { - roundItems.add(itemsArray.getString(i)); - } - } - - return new GetAuctionStateResponse(true, auctionId, DarkAuctionPhase.valueOf(phase), currentRound, currentItemType, - currentBid, highestBidderId, highestBidderName, roundItems, success, error); - } - - @Override - public GetAuctionStateResponse clone(GetAuctionStateResponse value) { - return new GetAuctionStateResponse(value.auctionActive, value.auctionId, value.phase, - value.currentRound, value.currentItemType, value.currentBid, - value.highestBidderId, value.highestBidderName, new ArrayList<>(value.roundItems), - value.success, value.error); - } - }; + return RESPONSE_SERIALIZER; } public record GetAuctionStateMessage() {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlaceBidProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlaceBidProtocol.java index d5d3245b2..fc50f7f27 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlaceBidProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlaceBidProtocol.java @@ -1,74 +1,29 @@ package net.swofty.commons.protocol.objects.darkauction; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; +import org.jetbrains.annotations.Nullable; import java.util.UUID; -import org.jetbrains.annotations.Nullable; -public class PlaceBidProtocol extends ProtocolObject< +public class PlaceBidProtocol extends RedisProtocol< PlaceBidProtocol.PlaceBidMessage, PlaceBidProtocol.PlaceBidResponse> { + private static final Serializer MESSAGE_SERIALIZER = + new JacksonSerializer<>(PlaceBidMessage.class); + private static final Serializer RESPONSE_SERIALIZER = + new JacksonSerializer<>(PlaceBidResponse.class); + @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(PlaceBidMessage value) { - JSONObject json = new JSONObject(); - json.put("auctionId", value.auctionId.toString()); - json.put("playerId", value.playerId.toString()); - json.put("playerName", value.playerName); - json.put("bidAmount", value.bidAmount); - return json.toString(); - } - - @Override - public PlaceBidMessage deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new PlaceBidMessage( - UUID.fromString(jsonObject.getString("auctionId")), - UUID.fromString(jsonObject.getString("playerId")), - jsonObject.getString("playerName"), - jsonObject.getLong("bidAmount") - ); - } - - @Override - public PlaceBidMessage clone(PlaceBidMessage value) { - return new PlaceBidMessage(value.auctionId, value.playerId, value.playerName, value.bidAmount); - } - }; + return MESSAGE_SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new Serializer<>() { - @Override - public String serialize(PlaceBidResponse value) { - JSONObject json = new JSONObject(); - json.put("success", value.success); - json.put("message", value.message); - json.put("error", value.error); - return json.toString(); - } - - @Override - public PlaceBidResponse deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new PlaceBidResponse( - jsonObject.getBoolean("success"), - jsonObject.getString("message"), - jsonObject.optString("error", null) - ); - } - - @Override - public PlaceBidResponse clone(PlaceBidResponse value) { - return new PlaceBidResponse(value.success, value.message, value.error); - } - }; + return RESPONSE_SERIALIZER; } public record PlaceBidMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlayerLeftAuctionProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlayerLeftAuctionProtocol.java index c6cb6c604..1eeaaac15 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlayerLeftAuctionProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/PlayerLeftAuctionProtocol.java @@ -1,78 +1,29 @@ package net.swofty.commons.protocol.objects.darkauction; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; +import org.jetbrains.annotations.Nullable; import java.util.UUID; -import org.jetbrains.annotations.Nullable; -public class PlayerLeftAuctionProtocol extends ProtocolObject< +public class PlayerLeftAuctionProtocol extends RedisProtocol< PlayerLeftAuctionProtocol.PlayerLeftMessage, PlayerLeftAuctionProtocol.PlayerLeftResponse> { + private static final Serializer MESSAGE_SERIALIZER = + new JacksonSerializer<>(PlayerLeftMessage.class); + private static final Serializer RESPONSE_SERIALIZER = + new JacksonSerializer<>(PlayerLeftResponse.class); + @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(PlayerLeftMessage value) { - JSONObject json = new JSONObject(); - json.put("playerId", value.playerId.toString()); - json.put("playerName", value.playerName); - if (value.auctionId != null) { - json.put("auctionId", value.auctionId.toString()); - } - return json.toString(); - } - - @Override - public PlayerLeftMessage deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - UUID auctionId = null; - if (jsonObject.has("auctionId") && !jsonObject.isNull("auctionId")) { - auctionId = UUID.fromString(jsonObject.getString("auctionId")); - } - return new PlayerLeftMessage( - UUID.fromString(jsonObject.getString("playerId")), - jsonObject.getString("playerName"), - auctionId - ); - } - - @Override - public PlayerLeftMessage clone(PlayerLeftMessage value) { - return new PlayerLeftMessage(value.playerId, value.playerName, value.auctionId); - } - }; + return MESSAGE_SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new Serializer<>() { - @Override - public String serialize(PlayerLeftResponse value) { - JSONObject json = new JSONObject(); - json.put("success", value.success); - json.put("refundAmount", value.refundAmount); - json.put("error", value.error); - return json.toString(); - } - - @Override - public PlayerLeftResponse deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - return new PlayerLeftResponse( - jsonObject.getBoolean("success"), - jsonObject.getLong("refundAmount"), - jsonObject.optString("error", null) - ); - } - - @Override - public PlayerLeftResponse clone(PlayerLeftResponse value) { - return new PlayerLeftResponse(value.success, value.refundAmount, value.error); - } - }; + return RESPONSE_SERIALIZER; } public record PlayerLeftMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/TriggerDarkAuctionProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/TriggerDarkAuctionProtocol.java index 78abaaee1..92299ef4b 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/TriggerDarkAuctionProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/darkauction/TriggerDarkAuctionProtocol.java @@ -1,67 +1,27 @@ package net.swofty.commons.protocol.objects.darkauction; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -import org.json.JSONObject; import org.jetbrains.annotations.Nullable; -public class TriggerDarkAuctionProtocol extends ProtocolObject< +public class TriggerDarkAuctionProtocol extends RedisProtocol< TriggerDarkAuctionProtocol.TriggerMessage, TriggerDarkAuctionProtocol.TriggerResponse> { + private static final Serializer MESSAGE_SERIALIZER = + new JacksonSerializer<>(TriggerMessage.class); + private static final Serializer RESPONSE_SERIALIZER = + new JacksonSerializer<>(TriggerResponse.class); + @Override public Serializer getSerializer() { - return new Serializer<>() { - @Override - public String serialize(TriggerMessage value) { - JSONObject json = new JSONObject(); - json.put("calendarTime", value.calendarTime); - json.put("forced", value.forced); - return json.toString(); - } - - @Override - public TriggerMessage deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - long calendarTime = jsonObject.optLong("calendarTime", 0); - boolean forced = jsonObject.optBoolean("forced", false); - return new TriggerMessage(calendarTime, forced); - } - - @Override - public TriggerMessage clone(TriggerMessage value) { - return new TriggerMessage(value.calendarTime, value.forced); - } - }; + return MESSAGE_SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new Serializer<>() { - @Override - public String serialize(TriggerResponse value) { - JSONObject json = new JSONObject(); - json.put("success", value.success); - json.put("message", value.message); - json.put("error", value.error); - return json.toString(); - } - - @Override - public TriggerResponse deserialize(String json) { - JSONObject jsonObject = new JSONObject(json); - boolean success = jsonObject.getBoolean("success"); - String message = jsonObject.optString("message", ""); - String error = jsonObject.optString("error", null); - if ("null".equals(error)) error = null; - return new TriggerResponse(success, message, error); - } - - @Override - public TriggerResponse clone(TriggerResponse value) { - return new TriggerResponse(value.success, value.message, value.error); - } - }; + return RESPONSE_SERIALIZER; } public record TriggerMessage(long calendarTime, boolean forced) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/data/GetPlayerDataPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/data/GetPlayerDataPushProtocol.java index 9b6eb3b30..24b8c739e 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/data/GetPlayerDataPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/data/GetPlayerDataPushProtocol.java @@ -1,11 +1,11 @@ package net.swofty.commons.protocol.objects.data; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.UUID; public class GetPlayerDataPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public GetPlayerDataPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/data/LockPlayerDataPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/data/LockPlayerDataPushProtocol.java index a21928e82..02479ab0e 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/data/LockPlayerDataPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/data/LockPlayerDataPushProtocol.java @@ -1,11 +1,11 @@ package net.swofty.commons.protocol.objects.data; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.UUID; public class LockPlayerDataPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public LockPlayerDataPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/data/UnlockPlayerDataPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/data/UnlockPlayerDataPushProtocol.java index 7230fa030..bdc14c9d0 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/data/UnlockPlayerDataPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/data/UnlockPlayerDataPushProtocol.java @@ -1,12 +1,12 @@ package net.swofty.commons.protocol.objects.data; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.UUID; import org.jetbrains.annotations.Nullable; public class UnlockPlayerDataPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public UnlockPlayerDataPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/data/UpdatePlayerDataPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/data/UpdatePlayerDataPushProtocol.java index 88b7f623c..996ce2287 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/data/UpdatePlayerDataPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/data/UpdatePlayerDataPushProtocol.java @@ -1,11 +1,11 @@ package net.swofty.commons.protocol.objects.data; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.UUID; public class UpdatePlayerDataPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public UpdatePlayerDataPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/SynchronizeDataProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/SynchronizeDataProtocol.java similarity index 55% rename from commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/SynchronizeDataProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/SynchronizeDataProtocol.java index 0d335acfd..507f5214c 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/SynchronizeDataProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/SynchronizeDataProtocol.java @@ -1,25 +1,29 @@ package net.swofty.commons.protocol.objects.datamutex; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class SynchronizeDataProtocolObject extends ProtocolObject< - SynchronizeDataProtocolObject.SynchronizeDataRequest, - SynchronizeDataProtocolObject.SynchronizeDataResponse> { +public class SynchronizeDataProtocol extends RedisProtocol< + SynchronizeDataProtocol.SynchronizeDataRequest, + SynchronizeDataProtocol.SynchronizeDataResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(SynchronizeDataRequest.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(SynchronizeDataResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(SynchronizeDataRequest.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(SynchronizeDataResponse.class); + return RETURN_SERIALIZER; } public record SynchronizeDataRequest( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UnlockDataProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UnlockDataProtocol.java similarity index 55% rename from commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UnlockDataProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UnlockDataProtocol.java index c29edf17e..ee4885ebf 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UnlockDataProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UnlockDataProtocol.java @@ -1,25 +1,29 @@ package net.swofty.commons.protocol.objects.datamutex; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class UnlockDataProtocolObject extends ProtocolObject< - UnlockDataProtocolObject.UnlockDataRequest, - UnlockDataProtocolObject.UnlockDataResponse> { +public class UnlockDataProtocol extends RedisProtocol< + UnlockDataProtocol.UnlockDataRequest, + UnlockDataProtocol.UnlockDataResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(UnlockDataRequest.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(UnlockDataResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(UnlockDataRequest.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(UnlockDataResponse.class); + return RETURN_SERIALIZER; } public record UnlockDataRequest( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UpdateSynchronizedDataProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UpdateSynchronizedDataProtocol.java similarity index 55% rename from commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UpdateSynchronizedDataProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UpdateSynchronizedDataProtocol.java index bf5f19c89..c5f63bbc4 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UpdateSynchronizedDataProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/datamutex/UpdateSynchronizedDataProtocol.java @@ -1,25 +1,29 @@ package net.swofty.commons.protocol.objects.datamutex; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class UpdateSynchronizedDataProtocolObject extends ProtocolObject< - UpdateSynchronizedDataProtocolObject.UpdateDataRequest, - UpdateSynchronizedDataProtocolObject.UpdateDataResponse> { +public class UpdateSynchronizedDataProtocol extends RedisProtocol< + UpdateSynchronizedDataProtocol.UpdateDataRequest, + UpdateSynchronizedDataProtocol.UpdateDataResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(UpdateDataRequest.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(UpdateDataResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(UpdateDataRequest.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(UpdateDataResponse.class); + return RETURN_SERIALIZER; } public record UpdateDataRequest( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/election/CastVoteProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/election/CastVoteProtocol.java similarity index 53% rename from commons/src/main/java/net/swofty/commons/protocol/objects/election/CastVoteProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/election/CastVoteProtocol.java index 02446ccd7..140c0d09b 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/election/CastVoteProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/election/CastVoteProtocol.java @@ -1,25 +1,29 @@ package net.swofty.commons.protocol.objects.election; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.Map; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class CastVoteProtocolObject - extends ProtocolObject { +public class CastVoteProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(CastVoteMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(CastVoteResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(CastVoteMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(CastVoteResponse.class); + return RETURN_SERIALIZER; } public record CastVoteMessage(UUID accountId, String candidateName) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetCandidatesProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetCandidatesProtocol.java similarity index 59% rename from commons/src/main/java/net/swofty/commons/protocol/objects/election/GetCandidatesProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/election/GetCandidatesProtocol.java index 4d6857b15..8f586c067 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetCandidatesProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetCandidatesProtocol.java @@ -1,24 +1,28 @@ package net.swofty.commons.protocol.objects.election; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import org.jetbrains.annotations.Nullable; -public class GetCandidatesProtocolObject - extends ProtocolObject { +public class GetCandidatesProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetCandidatesMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetCandidatesResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(GetCandidatesMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetCandidatesResponse.class); + return RETURN_SERIALIZER; } public record GetCandidatesMessage() {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetElectionDataProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetElectionDataProtocol.java similarity index 51% rename from commons/src/main/java/net/swofty/commons/protocol/objects/election/GetElectionDataProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/election/GetElectionDataProtocol.java index c185e54a3..429c321f3 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetElectionDataProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetElectionDataProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.election; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class GetElectionDataProtocolObject - extends ProtocolObject { +public class GetElectionDataProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetElectionDataMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetElectionDataResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(GetElectionDataMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetElectionDataResponse.class); + return RETURN_SERIALIZER; } public record GetElectionDataMessage() {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetPlayerVoteProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetPlayerVoteProtocol.java similarity index 50% rename from commons/src/main/java/net/swofty/commons/protocol/objects/election/GetPlayerVoteProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/election/GetPlayerVoteProtocol.java index a8e8ef013..d5a8d46ad 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetPlayerVoteProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/election/GetPlayerVoteProtocol.java @@ -1,24 +1,28 @@ package net.swofty.commons.protocol.objects.election; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class GetPlayerVoteProtocolObject - extends ProtocolObject { +public class GetPlayerVoteProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetPlayerVoteMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetPlayerVoteResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(GetPlayerVoteMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetPlayerVoteResponse.class); + return RETURN_SERIALIZER; } public record GetPlayerVoteMessage(UUID accountId) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/election/ResolveElectionProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/election/ResolveElectionProtocol.java new file mode 100644 index 000000000..32a779c66 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/election/ResolveElectionProtocol.java @@ -0,0 +1,29 @@ +package net.swofty.commons.protocol.objects.election; + +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.Serializer; +import org.jetbrains.annotations.Nullable; + +public class ResolveElectionProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(ResolveElectionMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(ResolveElectionResponse.class); + + @Override + public Serializer getSerializer() { + return SERIALIZER; + } + + @Override + public Serializer getReturnSerializer() { + return RETURN_SERIALIZER; + } + + public record ResolveElectionMessage(int year) {} + + public record ResolveElectionResponse(boolean resolved, String serializedData, boolean success, @Nullable String error) {} +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/election/ResolveElectionProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/election/ResolveElectionProtocolObject.java deleted file mode 100644 index 03a6bd3a4..000000000 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/election/ResolveElectionProtocolObject.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.swofty.commons.protocol.objects.election; - -import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.Serializer; -import org.jetbrains.annotations.Nullable; - -public class ResolveElectionProtocolObject - extends ProtocolObject { - - @Override - public Serializer getSerializer() { - return new JacksonSerializer<>(ResolveElectionMessage.class); - } - - @Override - public Serializer getReturnSerializer() { - return new JacksonSerializer<>(ResolveElectionResponse.class); - } - - public record ResolveElectionMessage(int year) {} - - public record ResolveElectionResponse(boolean resolved, String serializedData, boolean success, @Nullable String error) {} -} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/election/StartElectionProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/election/StartElectionProtocol.java similarity index 50% rename from commons/src/main/java/net/swofty/commons/protocol/objects/election/StartElectionProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/election/StartElectionProtocol.java index 7df2d2d04..234fcb984 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/election/StartElectionProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/election/StartElectionProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.election; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class StartElectionProtocolObject - extends ProtocolObject { +public class StartElectionProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(StartElectionMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(StartElectionResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(StartElectionMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(StartElectionResponse.class); + return RETURN_SERIALIZER; } public record StartElectionMessage(int year, String candidatesJson) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/AreFriendsProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/AreFriendsProtocol.java similarity index 51% rename from commons/src/main/java/net/swofty/commons/protocol/objects/friend/AreFriendsProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/friend/AreFriendsProtocol.java index 38719dc80..c9c8995eb 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/AreFriendsProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/AreFriendsProtocol.java @@ -1,24 +1,34 @@ package net.swofty.commons.protocol.objects.friend; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class AreFriendsProtocolObject extends ProtocolObject - { +public class AreFriendsProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(AreFriendsMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(AreFriendsResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(AreFriendsMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(AreFriendsResponse.class); + + return RETURN_SERIALIZER; + } public record AreFriendsMessage(UUID player, UUID other) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/FriendEventPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/FriendEventPushProtocol.java index c544e891b..3e3071a20 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/FriendEventPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/FriendEventPushProtocol.java @@ -1,12 +1,12 @@ package net.swofty.commons.protocol.objects.friend; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.List; import java.util.UUID; public class FriendEventPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public FriendEventPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetFriendDataProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetFriendDataProtocol.java similarity index 52% rename from commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetFriendDataProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetFriendDataProtocol.java index a48ad5439..760b65a2d 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetFriendDataProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetFriendDataProtocol.java @@ -2,24 +2,34 @@ import net.swofty.commons.friend.FriendData; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class GetFriendDataProtocolObject extends ProtocolObject - { +public class GetFriendDataProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetFriendDataMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetFriendDataResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(GetFriendDataMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetFriendDataResponse.class); + + return RETURN_SERIALIZER; + } public record GetFriendDataMessage(UUID playerUuid) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetPendingFriendRequestsProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetPendingFriendRequestsProtocol.java similarity index 52% rename from commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetPendingFriendRequestsProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetPendingFriendRequestsProtocol.java index 17a3a77a8..98d06b128 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetPendingFriendRequestsProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/GetPendingFriendRequestsProtocol.java @@ -2,25 +2,35 @@ import net.swofty.commons.friend.PendingFriendRequest; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class GetPendingFriendRequestsProtocolObject extends ProtocolObject - { +public class GetPendingFriendRequestsProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetPendingRequestsMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetPendingRequestsResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(GetPendingRequestsMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetPendingRequestsResponse.class); + + return RETURN_SERIALIZER; + } public record GetPendingRequestsMessage(UUID playerUuid) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/SendFriendEventToServiceProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/SendFriendEventToServiceProtocol.java new file mode 100644 index 000000000..6bb88a7a6 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/SendFriendEventToServiceProtocol.java @@ -0,0 +1,38 @@ +package net.swofty.commons.protocol.objects.friend; + +import net.swofty.commons.friend.FriendEvent; +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.Serializer; +import org.jetbrains.annotations.Nullable; + +public class SendFriendEventToServiceProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(SendFriendEventToServiceMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(SendFriendEventToServiceResponse.class); + + @Override + + public Serializer getSerializer() { + + return SERIALIZER; + + } + + @Override + + public Serializer getReturnSerializer() { + + return RETURN_SERIALIZER; + + } + + public record SendFriendEventToServiceMessage(FriendEvent event) { + } + + public record SendFriendEventToServiceResponse(boolean success, @Nullable String error) { + } +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/SendFriendEventToServiceProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/friend/SendFriendEventToServiceProtocolObject.java deleted file mode 100644 index 0d8ccb924..000000000 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/friend/SendFriendEventToServiceProtocolObject.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.swofty.commons.protocol.objects.friend; - -import net.swofty.commons.friend.FriendEvent; -import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.Serializer; -import org.jetbrains.annotations.Nullable; - -public class SendFriendEventToServiceProtocolObject extends ProtocolObject - { - - @Override - public Serializer getSerializer() { - return new JacksonSerializer<>(SendFriendEventToServiceMessage.class); - } - - @Override - public Serializer getReturnSerializer() { - return new JacksonSerializer<>(SendFriendEventToServiceResponse.class); - } - - public record SendFriendEventToServiceMessage(FriendEvent event) { - } - - public record SendFriendEventToServiceResponse(boolean success, @Nullable String error) { - } -} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/game/GameInformationPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/game/GameInformationPushProtocol.java index 0eeff3986..0d2904931 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/game/GameInformationPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/game/GameInformationPushProtocol.java @@ -1,11 +1,11 @@ package net.swofty.commons.protocol.objects.game; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.UUID; public class GameInformationPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public GameInformationPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/game/InstantiateGamePushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/game/InstantiateGamePushProtocol.java index 356b11048..e4b02f157 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/game/InstantiateGamePushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/game/InstantiateGamePushProtocol.java @@ -1,9 +1,9 @@ package net.swofty.commons.protocol.objects.game; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; public class InstantiateGamePushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public InstantiateGamePushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/gui/KickFromGUIPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/gui/KickFromGUIPushProtocol.java index be143e9d9..967857f3f 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/gui/KickFromGUIPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/gui/KickFromGUIPushProtocol.java @@ -1,13 +1,13 @@ package net.swofty.commons.protocol.objects.gui; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; public class KickFromGUIPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public KickFromGUIPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemRetrieveProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemRetrieveProtocol.java similarity index 55% rename from commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemRetrieveProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemRetrieveProtocol.java index 38a01f0f8..76558e242 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemRetrieveProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemRetrieveProtocol.java @@ -2,24 +2,34 @@ import net.swofty.commons.TrackedItem; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class TrackedItemRetrieveProtocolObject extends ProtocolObject - { +public class TrackedItemRetrieveProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(TrackedItemRetrieveMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(TrackedItemResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(TrackedItemRetrieveMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(TrackedItemResponse.class); + + return RETURN_SERIALIZER; + } public record TrackedItemRetrieveMessage(UUID itemUUID) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemUpdateProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemUpdateProtocol.java similarity index 50% rename from commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemUpdateProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemUpdateProtocol.java index 2068bed1f..9c159a483 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemUpdateProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/itemtracker/TrackedItemUpdateProtocol.java @@ -1,23 +1,27 @@ package net.swofty.commons.protocol.objects.itemtracker; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; -public class TrackedItemUpdateProtocolObject extends ProtocolObject< - TrackedItemUpdateProtocolObject.TrackedItemUpdateMessage, - TrackedItemUpdateProtocolObject.TrackedItemUpdateResponse> { +public class TrackedItemUpdateProtocol extends RedisProtocol< + TrackedItemUpdateProtocol.TrackedItemUpdateMessage, + TrackedItemUpdateProtocol.TrackedItemUpdateResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(TrackedItemUpdateMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(TrackedItemUpdateResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(TrackedItemUpdateMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(TrackedItemUpdateResponse.class); + return RETURN_SERIALIZER; } public record TrackedItemUpdateMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/messaging/SendMessagePushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/messaging/SendMessagePushProtocol.java index ca89b6c66..816c3f931 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/messaging/SendMessagePushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/messaging/SendMessagePushProtocol.java @@ -1,12 +1,12 @@ package net.swofty.commons.protocol.objects.messaging; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.UUID; import org.jetbrains.annotations.Nullable; public class SendMessagePushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public SendMessagePushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/ChooseGameProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/ChooseGameProtocol.java similarity index 54% rename from commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/ChooseGameProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/ChooseGameProtocol.java index 9dfb17b31..db9553353 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/ChooseGameProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/ChooseGameProtocol.java @@ -2,24 +2,34 @@ import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class ChooseGameProtocolObject extends ProtocolObject - { +public class ChooseGameProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(ChooseGameMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(ChooseGameResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(ChooseGameMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(ChooseGameResponse.class); + + return RETURN_SERIALIZER; + } public record ChooseGameMessage(UUID player, UnderstandableProxyServer server, String gameId) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GameHeartbeatProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GameHeartbeatProtocol.java similarity index 56% rename from commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GameHeartbeatProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GameHeartbeatProtocol.java index ac9519f78..4268edd36 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GameHeartbeatProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GameHeartbeatProtocol.java @@ -3,25 +3,35 @@ import net.swofty.commons.ServerType; import net.swofty.commons.game.Game; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class GameHeartbeatProtocolObject extends ProtocolObject - { +public class GameHeartbeatProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(HeartbeatMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(HeartbeatResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(HeartbeatMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(HeartbeatResponse.class); + + return RETURN_SERIALIZER; + } public record HeartbeatMessage(UUID uuid, String shortName, ServerType type, int maxPlayers, int onlinePlayers, List games) { } diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetGameCountsProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetGameCountsProtocol.java similarity index 52% rename from commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetGameCountsProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetGameCountsProtocol.java index 2a608bb73..05799c63b 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetGameCountsProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetGameCountsProtocol.java @@ -2,22 +2,32 @@ import net.swofty.commons.ServerType; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class GetGameCountsProtocolObject extends ProtocolObject - { +public class GetGameCountsProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetGameCountsMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetGameCountsResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(GetGameCountsMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetGameCountsResponse.class); + + return RETURN_SERIALIZER; + } public record GetGameCountsMessage(ServerType type, String gameTypeName, String mapName) { } diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetMapsProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetMapsProtocol.java similarity index 53% rename from commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetMapsProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetMapsProtocol.java index 6bc7f4232..6586fc792 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetMapsProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetMapsProtocol.java @@ -2,24 +2,34 @@ import net.swofty.commons.ServerType; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import org.jetbrains.annotations.Nullable; -public class GetMapsProtocolObject extends ProtocolObject - { +public class GetMapsProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetMapsMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetMapsResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(GetMapsMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetMapsResponse.class); + + return RETURN_SERIALIZER; + } public record GetMapsMessage(ServerType type, String mode) { } diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetServerForMapProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetServerForMapProtocol.java similarity index 55% rename from commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetServerForMapProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetServerForMapProtocol.java index 2c338eb00..9bfeafcbb 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetServerForMapProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/GetServerForMapProtocol.java @@ -3,22 +3,32 @@ import net.swofty.commons.ServerType; import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class GetServerForMapProtocolObject extends ProtocolObject - { +public class GetServerForMapProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetServerForMapMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetServerForMapResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(GetServerForMapMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetServerForMapResponse.class); + + return RETURN_SERIALIZER; + } public record GetServerForMapMessage(ServerType type, @Nullable String map, String mode, int neededSlots) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/RejoinGameProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/RejoinGameProtocol.java similarity index 62% rename from commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/RejoinGameProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/RejoinGameProtocol.java index 5ce367f73..89baad8f1 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/RejoinGameProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/orchestrator/RejoinGameProtocol.java @@ -2,24 +2,28 @@ import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; import java.util.UUID; -public class RejoinGameProtocolObject extends ProtocolObject< - RejoinGameProtocolObject.RejoinGameRequest, - RejoinGameProtocolObject.RejoinGameResponse> { +public class RejoinGameProtocol extends RedisProtocol< + RejoinGameProtocol.RejoinGameRequest, + RejoinGameProtocol.RejoinGameResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(RejoinGameRequest.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(RejoinGameResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(RejoinGameRequest.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(RejoinGameResponse.class); + return RETURN_SERIALIZER; } public record RejoinGameRequest(UUID playerUuid) { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/party/GetPartyProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/party/GetPartyProtocol.java similarity index 52% rename from commons/src/main/java/net/swofty/commons/protocol/objects/party/GetPartyProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/party/GetPartyProtocol.java index 77f769413..f70172bde 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/party/GetPartyProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/party/GetPartyProtocol.java @@ -2,24 +2,34 @@ import net.swofty.commons.party.Party; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class GetPartyProtocolObject extends ProtocolObject - { +public class GetPartyProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetPartyMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetPartyResponse.class); @Override + public Serializer getSerializer() { - return new JacksonSerializer<>(GetPartyMessage.class); + + return SERIALIZER; + } @Override + public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetPartyResponse.class); + + return RETURN_SERIALIZER; + } public record GetPartyMessage(UUID memberUuid) { } diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/party/IsPlayerInPartyProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/party/IsPlayerInPartyProtocol.java new file mode 100644 index 000000000..65c691464 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/party/IsPlayerInPartyProtocol.java @@ -0,0 +1,39 @@ +package net.swofty.commons.protocol.objects.party; + +import net.swofty.commons.protocol.JacksonSerializer; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.Serializer; + +import java.util.UUID; +import org.jetbrains.annotations.Nullable; + +public class IsPlayerInPartyProtocol extends RedisProtocol + { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(IsPlayerInPartyMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(IsPlayerInPartyResponse.class); + + @Override + + public Serializer getSerializer() { + + return SERIALIZER; + + } + + @Override + + public Serializer getReturnSerializer() { + + return RETURN_SERIALIZER; + + } + + public record IsPlayerInPartyMessage(UUID playerUUID) { + } + + public record IsPlayerInPartyResponse(boolean isInParty, boolean success, @Nullable String error) { + } +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/party/IsPlayerInPartyProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/party/IsPlayerInPartyProtocolObject.java deleted file mode 100644 index e0b8f7efa..000000000 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/party/IsPlayerInPartyProtocolObject.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.commons.protocol.objects.party; - -import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.Serializer; - -import java.util.UUID; -import org.jetbrains.annotations.Nullable; - -public class IsPlayerInPartyProtocolObject extends ProtocolObject - { - - @Override - public Serializer getSerializer() { - return new JacksonSerializer<>(IsPlayerInPartyMessage.class); - } - - @Override - public Serializer getReturnSerializer() { - return new JacksonSerializer<>(IsPlayerInPartyResponse.class); - } - - public record IsPlayerInPartyMessage(UUID playerUUID) { - } - - public record IsPlayerInPartyResponse(boolean isInParty, boolean success, @Nullable String error) { - } -} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/party/PartyBroadcastPushProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/party/PartyBroadcastPushProtocol.java index 80be1efb3..c6f8ea0cd 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/party/PartyBroadcastPushProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/party/PartyBroadcastPushProtocol.java @@ -1,14 +1,14 @@ package net.swofty.commons.protocol.objects.party; import net.swofty.commons.party.PartyBroadcast; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import java.util.List; import java.util.Map; import java.util.UUID; public class PartyBroadcastPushProtocol - extends ServicePushProtocol { + extends RedisProtocol { public PartyBroadcastPushProtocol() { super(Request.class, Response.class); diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/party/SendPartyActionProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/party/SendPartyActionProtocol.java similarity index 59% rename from commons/src/main/java/net/swofty/commons/protocol/objects/party/SendPartyActionProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/party/SendPartyActionProtocol.java index e5ba6aa84..cbce1045b 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/party/SendPartyActionProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/party/SendPartyActionProtocol.java @@ -2,22 +2,26 @@ import net.swofty.commons.party.PartyAction; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class SendPartyActionProtocolObject extends ProtocolObject< - SendPartyActionProtocolObject.Request, - SendPartyActionProtocolObject.Response> { +public class SendPartyActionProtocol extends RedisProtocol< + SendPartyActionProtocol.Request, + SendPartyActionProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(PartyAction action) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/presence/GetPresenceBulkProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/presence/GetPresenceBulkProtocol.java similarity index 53% rename from commons/src/main/java/net/swofty/commons/protocol/objects/presence/GetPresenceBulkProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/presence/GetPresenceBulkProtocol.java index 9bc062307..376cca867 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/presence/GetPresenceBulkProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/presence/GetPresenceBulkProtocol.java @@ -2,25 +2,29 @@ import net.swofty.commons.presence.PresenceInfo; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -public class GetPresenceBulkProtocolObject extends ProtocolObject< - GetPresenceBulkProtocolObject.GetPresenceBulkMessage, - GetPresenceBulkProtocolObject.GetPresenceBulkResponse> { +public class GetPresenceBulkProtocol extends RedisProtocol< + GetPresenceBulkProtocol.GetPresenceBulkMessage, + GetPresenceBulkProtocol.GetPresenceBulkResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetPresenceBulkMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetPresenceBulkResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(GetPresenceBulkMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetPresenceBulkResponse.class); + return RETURN_SERIALIZER; } public record GetPresenceBulkMessage(List uuids) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/presence/UpdatePresenceProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/presence/UpdatePresenceProtocol.java similarity index 50% rename from commons/src/main/java/net/swofty/commons/protocol/objects/presence/UpdatePresenceProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/presence/UpdatePresenceProtocol.java index 2b7191cb7..2b0dee5a8 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/presence/UpdatePresenceProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/presence/UpdatePresenceProtocol.java @@ -2,22 +2,26 @@ import net.swofty.commons.presence.PresenceInfo; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class UpdatePresenceProtocolObject extends ProtocolObject< - UpdatePresenceProtocolObject.UpdatePresenceMessage, - UpdatePresenceProtocolObject.UpdatePresenceResponse> { +public class UpdatePresenceProtocol extends RedisProtocol< + UpdatePresenceProtocol.UpdatePresenceMessage, + UpdatePresenceProtocol.UpdatePresenceResponse> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(UpdatePresenceMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(UpdatePresenceResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(UpdatePresenceMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(UpdatePresenceResponse.class); + return RETURN_SERIALIZER; } public record UpdatePresenceMessage(PresenceInfo presence) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/BroadcastStaffChatProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/BroadcastStaffChatProtocol.java index effcbfd0a..0fff58285 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/BroadcastStaffChatProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/BroadcastStaffChatProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class BroadcastStaffChatProtocol extends ProtocolObject< +public class BroadcastStaffChatProtocol extends RedisProtocol< BroadcastStaffChatProtocol.Request, BroadcastStaffChatProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String type, String formattedMessage, String uuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/DoesServerHaveIslandProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/DoesServerHaveIslandProtocol.java index 152e90a17..c1def2cd2 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/DoesServerHaveIslandProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/DoesServerHaveIslandProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class DoesServerHaveIslandProtocol extends ProtocolObject< +public class DoesServerHaveIslandProtocol extends RedisProtocol< DoesServerHaveIslandProtocol.Request, DoesServerHaveIslandProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String islandUuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/GivePlayersOriginTypeProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/GivePlayersOriginTypeProtocol.java index 59f4cce0c..b86ccf856 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/GivePlayersOriginTypeProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/GivePlayersOriginTypeProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class GivePlayersOriginTypeProtocol extends ProtocolObject< +public class GivePlayersOriginTypeProtocol extends RedisProtocol< GivePlayersOriginTypeProtocol.Request, GivePlayersOriginTypeProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String uuid, String originType) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PingServerProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PingServerProtocol.java index 13aa9b350..588f859f3 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PingServerProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PingServerProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class PingServerProtocol extends ProtocolObject< +public class PingServerProtocol extends RedisProtocol< PingServerProtocol.Request, PingServerProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request() {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PlayerSwitchedProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PlayerSwitchedProtocol.java index e29f00e49..330eecb50 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PlayerSwitchedProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/PlayerSwitchedProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class PlayerSwitchedProtocol extends ProtocolObject< +public class PlayerSwitchedProtocol extends RedisProtocol< PlayerSwitchedProtocol.Request, PlayerSwitchedProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String uuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RefreshCoopDataProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RefreshCoopDataProtocol.java index eb682642c..99544e3c3 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RefreshCoopDataProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RefreshCoopDataProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class RefreshCoopDataProtocol extends ProtocolObject< +public class RefreshCoopDataProtocol extends RedisProtocol< RefreshCoopDataProtocol.Request, RefreshCoopDataProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String uuid, String datapoint) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RunEventProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RunEventProtocol.java index 2554f4545..1e8d807d8 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RunEventProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/RunEventProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class RunEventProtocol extends ProtocolObject< +public class RunEventProtocol extends RedisProtocol< RunEventProtocol.Request, RunEventProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String uuid, String event, String data) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/TeleportProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/TeleportProtocol.java index df9fcbff9..edb5bc107 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/TeleportProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/from/TeleportProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.from; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class TeleportProtocol extends ProtocolObject< +public class TeleportProtocol extends RedisProtocol< TeleportProtocol.Request, TeleportProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String uuid, double x, double y, double z, float yaw, float pitch) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/FinishedWithPlayerProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/FinishedWithPlayerProtocol.java index 006291036..157107cb0 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/FinishedWithPlayerProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/FinishedWithPlayerProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class FinishedWithPlayerProtocol extends ProtocolObject< +public class FinishedWithPlayerProtocol extends RedisProtocol< FinishedWithPlayerProtocol.Request, FinishedWithPlayerProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String uuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerCountProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerCountProtocol.java index faed156c8..87cfdb0f7 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerCountProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerCountProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class PlayerCountProtocol extends ProtocolObject< +public class PlayerCountProtocol extends RedisProtocol< PlayerCountProtocol.Request, PlayerCountProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public enum LookupType { ALL, TYPE, UUID } diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerHandlerProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerHandlerProtocol.java index e23cab32c..3905af367 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerHandlerProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PlayerHandlerProtocol.java @@ -1,24 +1,28 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.Map; import org.jetbrains.annotations.Nullable; -public class PlayerHandlerProtocol extends ProtocolObject< +public class PlayerHandlerProtocol extends RedisProtocol< PlayerHandlerProtocol.Request, PlayerHandlerProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public enum Action { diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/ProxyIsOnlineProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/ProxyIsOnlineProtocol.java index 555a5ccc4..140f5f37d 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/ProxyIsOnlineProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/ProxyIsOnlineProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class ProxyIsOnlineProtocol extends ProtocolObject< +public class ProxyIsOnlineProtocol extends RedisProtocol< ProxyIsOnlineProtocol.Request, ProxyIsOnlineProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request() {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PunishPlayerProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PunishPlayerProtocol.java index 3025880f4..a2d85c110 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PunishPlayerProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/PunishPlayerProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class PunishPlayerProtocol extends ProtocolObject< +public class PunishPlayerProtocol extends RedisProtocol< PunishPlayerProtocol.Request, PunishPlayerProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String target, String type, String id, long expiresAt, diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterServerProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterServerProtocol.java index bf26b1b80..f06ffb34b 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterServerProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterServerProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class RegisterServerProtocol extends ProtocolObject< +public class RegisterServerProtocol extends RedisProtocol< RegisterServerProtocol.Request, RegisterServerProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String type, int maxPlayers, String host, Integer port, diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterTestFlowProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterTestFlowProtocol.java index 6892a6cb6..fd586dfec 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterTestFlowProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RegisterTestFlowProtocol.java @@ -1,24 +1,28 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import java.util.List; import java.util.Map; -public class RegisterTestFlowProtocol extends ProtocolObject< +public class RegisterTestFlowProtocol extends RedisProtocol< RegisterTestFlowProtocol.Request, RegisterTestFlowProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String testFlowName, String handler, List players, diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServerNameProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServerNameProtocol.java index 13aaef2f1..b6696005c 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServerNameProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServerNameProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class RequestServerNameProtocol extends ProtocolObject< +public class RequestServerNameProtocol extends RedisProtocol< RequestServerNameProtocol.Request, RequestServerNameProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request() {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServersProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServersProtocol.java index 2537efa32..13ad3aa31 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServersProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/RequestServersProtocol.java @@ -1,22 +1,26 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.Nullable; -public class RequestServersProtocol extends ProtocolObject< +public class RequestServersProtocol extends RedisProtocol< RequestServersProtocol.Request, RequestServersProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String requestType, String type, String uuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/StaffChatProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/StaffChatProtocol.java index a066c0c9a..158403783 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/StaffChatProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/StaffChatProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class StaffChatProtocol extends ProtocolObject< +public class StaffChatProtocol extends RedisProtocol< StaffChatProtocol.Request, StaffChatProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String type, String formattedMessage, String uuid) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/TestFlowServerReadyProtocol.java b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/TestFlowServerReadyProtocol.java index 8d4e10242..74d253946 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/TestFlowServerReadyProtocol.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/proxy/to/TestFlowServerReadyProtocol.java @@ -1,21 +1,25 @@ package net.swofty.commons.protocol.objects.proxy.to; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; -public class TestFlowServerReadyProtocol extends ProtocolObject< +public class TestFlowServerReadyProtocol extends RedisProtocol< TestFlowServerReadyProtocol.Request, TestFlowServerReadyProtocol.Response> { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(Request.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(Response.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(Request.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(Response.class); + return RETURN_SERIALIZER; } public record Request(String testFlowName, String serverType, int serverIndex) {} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/GetActivePunishmentProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/GetActivePunishmentProtocol.java similarity index 63% rename from commons/src/main/java/net/swofty/commons/protocol/objects/punishment/GetActivePunishmentProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/punishment/GetActivePunishmentProtocol.java index f380d478b..124a01ee4 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/GetActivePunishmentProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/GetActivePunishmentProtocol.java @@ -1,7 +1,7 @@ package net.swofty.commons.protocol.objects.punishment; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import net.swofty.commons.punishment.PunishmentReason; import net.swofty.commons.punishment.PunishmentTag; @@ -11,18 +11,22 @@ import java.util.List; import java.util.UUID; -public class GetActivePunishmentProtocolObject - extends ProtocolObject { +public class GetActivePunishmentProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(GetActivePunishmentMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(GetActivePunishmentResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(GetActivePunishmentMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(GetActivePunishmentResponse.class); + return RETURN_SERIALIZER; } public record GetActivePunishmentMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/PunishPlayerProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/PunishPlayerServiceProtocol.java similarity index 68% rename from commons/src/main/java/net/swofty/commons/protocol/objects/punishment/PunishPlayerProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/punishment/PunishPlayerServiceProtocol.java index 6f22625ab..334e9acf1 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/PunishPlayerProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/PunishPlayerServiceProtocol.java @@ -1,7 +1,7 @@ package net.swofty.commons.protocol.objects.punishment; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import net.swofty.commons.punishment.PunishmentReason; import net.swofty.commons.punishment.PunishmentTag; @@ -11,18 +11,22 @@ import java.util.List; import java.util.UUID; -public class PunishPlayerProtocolObject - extends ProtocolObject { +public class PunishPlayerServiceProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(PunishPlayerMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(PunishPlayerResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(PunishPlayerMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(PunishPlayerResponse.class); + return RETURN_SERIALIZER; } public record PunishPlayerMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/UnpunishPlayerProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/UnpunishPlayerProtocol.java similarity index 55% rename from commons/src/main/java/net/swofty/commons/protocol/objects/punishment/UnpunishPlayerProtocolObject.java rename to commons/src/main/java/net/swofty/commons/protocol/objects/punishment/UnpunishPlayerProtocol.java index d8007bc21..e50c273ee 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/UnpunishPlayerProtocolObject.java +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/punishment/UnpunishPlayerProtocol.java @@ -1,25 +1,29 @@ package net.swofty.commons.protocol.objects.punishment; import net.swofty.commons.protocol.JacksonSerializer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.Serializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.UUID; -public class UnpunishPlayerProtocolObject - extends ProtocolObject { +public class UnpunishPlayerProtocol + extends RedisProtocol { + private static final Serializer SERIALIZER = + new JacksonSerializer<>(UnpunishPlayerMessage.class); + private static final Serializer RETURN_SERIALIZER = + new JacksonSerializer<>(UnpunishPlayerResponse.class); @Override public Serializer getSerializer() { - return new JacksonSerializer<>(UnpunishPlayerMessage.class); + return SERIALIZER; } @Override public Serializer getReturnSerializer() { - return new JacksonSerializer<>(UnpunishPlayerResponse.class); + return RETURN_SERIALIZER; } public record UnpunishPlayerMessage( diff --git a/commons/src/main/java/net/swofty/commons/protocol/serializers/UnderstandableSkyBlockItemSerializer.java b/commons/src/main/java/net/swofty/commons/protocol/serializers/UnderstandableSkyBlockItemSerializer.java index 0307f32fb..84b84b0f0 100644 --- a/commons/src/main/java/net/swofty/commons/protocol/serializers/UnderstandableSkyBlockItemSerializer.java +++ b/commons/src/main/java/net/swofty/commons/protocol/serializers/UnderstandableSkyBlockItemSerializer.java @@ -6,6 +6,7 @@ import net.swofty.commons.skyblock.item.attribute.ItemAttribute; import net.swofty.commons.protocol.Serializer; import org.json.JSONObject; +import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; @@ -37,8 +38,7 @@ public UnderstandableSkyBlockItem deserialize(String json) { try { itemKey = ItemType.valueOf(jsonObject.getString("itemKey")); } catch (IllegalArgumentException e) { - // Handle invalid itemKey - System.err.println("Invalid itemKey: " + jsonObject.getString("itemKey")); + Logger.warn("Invalid itemKey: {}", jsonObject.getString("itemKey")); } } diff --git a/commons/src/main/java/net/swofty/commons/punishment/PunishmentRedis.java b/commons/src/main/java/net/swofty/commons/punishment/PunishmentRedis.java index b71c84e1d..d4e5f8746 100644 --- a/commons/src/main/java/net/swofty/commons/punishment/PunishmentRedis.java +++ b/commons/src/main/java/net/swofty/commons/punishment/PunishmentRedis.java @@ -1,13 +1,11 @@ package net.swofty.commons.punishment; import com.google.gson.Gson; +import net.swofty.commons.redis.RedisConnectionPool; import org.tinylog.Logger; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; -import java.net.URI; -import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -31,22 +29,7 @@ private static synchronized void connectSync(String redisUri) { connecting = true; try { - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMaxTotal(20); - poolConfig.setMaxIdle(5); - poolConfig.setMinIdle(1); - poolConfig.setMaxWait(Duration.ofSeconds(2)); - poolConfig.setTestOnBorrow(true); - poolConfig.setTestWhileIdle(true); - poolConfig.setBlockWhenExhausted(false); - - URI uri = URI.create(redisUri); - jedisPool = new JedisPool(poolConfig, uri); - - try (Jedis jedis = jedisPool.getResource()) { - jedis.ping(); - } - + jedisPool = RedisConnectionPool.connect(redisUri, RedisConnectionPool.Settings.standard()); initialized = true; Logger.info("PunishmentService: connected to Redis"); } catch (Exception e) { @@ -88,7 +71,7 @@ public static void saveActivePunishment(UUID playerId, String type, String id, if (expiresAt > 0) { long ttlSeconds = (expiresAt - System.currentTimeMillis()) / 1000; if (ttlSeconds > 0) { - jedis.expire(redisKey, (int) ttlSeconds); + jedis.expire(redisKey, ttlSeconds); } } else { jedis.persist(redisKey); diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisChannels.java b/commons/src/main/java/net/swofty/commons/redis/RedisChannels.java new file mode 100644 index 000000000..434a7a059 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisChannels.java @@ -0,0 +1,26 @@ +package net.swofty.commons.redis; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.commons.protocol.RedisProtocol; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RedisChannels { + public static final String PROXY_RESPONSE = "proxy"; + public static final String SERVICE_RESPONSE = "service_response"; + public static final String SERVICE_BROADCAST_RESPONSE = "service_broadcast_response"; + public static final String ALL_SERVERS = "all"; + + public static String protocol(RedisProtocol protocol) { + return protocol.channel(); + } + + public static String serviceRequest(RedisProtocol protocol) { + return "service_" + protocol.channel(); + } + + public static String serviceBroadcast(RedisProtocol protocol) { + return "service_broadcast_" + protocol.channel(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisClient.java b/commons/src/main/java/net/swofty/commons/redis/RedisClient.java new file mode 100644 index 000000000..2489302a8 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisClient.java @@ -0,0 +1,178 @@ +package net.swofty.commons.redis; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.commons.ServiceType; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.PingProtocol; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RedisClient { + private static final Map> protocolsByRequest = new ConcurrentHashMap<>(); + private static volatile RedisEndpoint localEndpoint; + + public static void identify(RedisEndpoint endpoint) { + localEndpoint = endpoint; + } + + public static RedisEndpoint localEndpoint() { + if (localEndpoint == null) { + throw new IllegalStateException("RedisClient local endpoint has not been identified"); + } + return localEndpoint; + } + + public static void registerResponseProtocol(RedisProtocol protocol) { + protocolsByRequest.put(requestTypeName(protocol), protocol); + RedisMessageBus.registerResponseChannel(RedisChannels.protocol(protocol)); + } + + public static void registerResponseChannel(String channel) { + RedisMessageBus.registerResponseChannel(channel); + } + + public static void registerResponseProtocols(Iterable> protocols) { + protocols.forEach(RedisClient::registerResponseProtocol); + } + + public static CompletableFuture requestProxy(RedisProtocol protocol, T message) { + return request(RedisEndpoint.proxy().id(), RedisChannels.protocol(protocol), RedisChannels.protocol(protocol), protocol, message); + } + + public static CompletableFuture requestServer(UUID server, RedisProtocol protocol, T message) { + return request(server.toString(), RedisChannels.protocol(protocol), RedisChannels.protocol(protocol), protocol, message); + } + + public static CompletableFuture requestService(ServiceType service, RedisProtocol protocol, T message) { + return request(service.name(), RedisChannels.protocol(protocol), RedisChannels.protocol(protocol), protocol, message); + } + + public static CompletableFuture requestService(ServiceType service, T message) { + RedisProtocol protocol = protocolFor(message); + return requestService(service, protocol, message); + } + + public static CompletableFuture requestServiceFromServer(ServiceType service, RedisProtocol protocol, T message) { + return requestService(service, protocol, message); + } + + public static void publishService(ServiceType service, RedisProtocol protocol, T message) { + RedisMessageBus.publish(localEndpoint(), service.name(), RedisChannels.protocol(protocol), protocol, message); + } + + public static void publishAllServices(RedisProtocol protocol, T message) { + for (ServiceType serviceType : ServiceType.values()) { + publishService(serviceType, protocol, message); + } + } + + public static CompletableFuture requestServerFromService(UUID server, + RedisProtocol protocol, + T message) { + return RedisMessageBus.request( + localEndpoint(), + server.toString(), + RedisChannels.serviceRequest(protocol), + RedisChannels.SERVICE_RESPONSE, + protocol, + message + ); + } + + public static CompletableFuture> requestAllServersFromService(RedisProtocol protocol, + T message, + int timeoutMs) { + return RedisMessageBus.requestBroadcast( + localEndpoint(), + RedisChannels.ALL_SERVERS, + RedisChannels.serviceBroadcast(protocol), + RedisChannels.SERVICE_BROADCAST_RESPONSE, + protocol, + message, + timeoutMs + ); + } + + public static CompletableFuture> requestServersFromService(Iterable servers, + RedisProtocol protocol, + T message) { + Map> futures = new ConcurrentHashMap<>(); + for (UUID server : servers) { + futures.put(server, requestServerFromService(server, protocol, message)); + } + + return CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0])) + .thenApply(ignored -> { + Map responses = new ConcurrentHashMap<>(); + futures.forEach((server, future) -> { + try { + responses.put(server, future.get()); + } catch (Exception ignoredException) { + } + }); + return responses; + }); + } + + public static CompletableFuture isServiceOnline(ServiceType service) { + CompletableFuture future = new CompletableFuture<>(); + AtomicBoolean responded = new AtomicBoolean(false); + + requestService(service, new PingProtocol(), new PingProtocol.EmptyMessage()).thenAccept(response -> { + responded.set(true); + future.complete(true); + }); + + CompletableFuture.delayedExecutor(150, TimeUnit.MILLISECONDS).execute(() -> { + if (!responded.get()) { + future.complete(false); + } + }); + + return future; + } + + @SuppressWarnings("unchecked") + public static RedisProtocol protocolFor(T request) { + RedisProtocol protocol = protocolsByRequest.get(request.getClass().getSimpleName()); + if (protocol == null) { + throw new IllegalArgumentException("No Redis protocol registered for " + request.getClass().getSimpleName()); + } + return (RedisProtocol) protocol; + } + + private static CompletableFuture request(String target, + String requestChannel, + String responseChannel, + RedisProtocol protocol, + T message) { + return RedisMessageBus.request(localEndpoint(), target, requestChannel, responseChannel, protocol, message); + } + + private static String requestTypeName(RedisProtocol protocol) { + Type genericSuperclass = protocol.getClass().getGenericSuperclass(); + + if (genericSuperclass instanceof ParameterizedType paramType) { + Type[] typeArguments = paramType.getActualTypeArguments(); + if (typeArguments.length > 0) { + Type firstTypeArg = typeArguments[0]; + if (firstTypeArg instanceof Class) { + return ((Class) firstTypeArg).getSimpleName(); + } + return firstTypeArg.getTypeName(); + } + } + + throw new IllegalArgumentException("Could not determine request type for " + protocol.getClass().getName()); + } +} diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisConnectionPool.java b/commons/src/main/java/net/swofty/commons/redis/RedisConnectionPool.java new file mode 100644 index 000000000..07517a083 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisConnectionPool.java @@ -0,0 +1,38 @@ +package net.swofty.commons.redis; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; + +import java.net.URI; +import java.time.Duration; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RedisConnectionPool { + + public static JedisPool connect(String redisUri, Settings settings) { + JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxTotal(settings.maxTotal()); + poolConfig.setMaxIdle(settings.maxIdle()); + poolConfig.setMinIdle(settings.minIdle()); + poolConfig.setMaxWait(settings.maxWait()); + poolConfig.setTestOnBorrow(true); + poolConfig.setTestWhileIdle(true); + poolConfig.setBlockWhenExhausted(false); + + JedisPool pool = new JedisPool(poolConfig, URI.create(redisUri)); + try (Jedis jedis = pool.getResource()) { + jedis.ping(); + } + return pool; + } + + public record Settings(int maxTotal, int maxIdle, int minIdle, Duration maxWait) { + public static Settings standard() { + return new Settings(20, 5, 1, Duration.ofSeconds(2)); + } + } +} diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisEndpoint.java b/commons/src/main/java/net/swofty/commons/redis/RedisEndpoint.java new file mode 100644 index 000000000..e55956a63 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisEndpoint.java @@ -0,0 +1,27 @@ +package net.swofty.commons.redis; + +import net.swofty.commons.ServiceType; + +import java.util.UUID; + +public record RedisEndpoint(RedisEndpointType type, String id) { + public static RedisEndpoint proxy() { + return new RedisEndpoint(RedisEndpointType.PROXY, "proxy"); + } + + public static RedisEndpoint service(ServiceType type) { + return new RedisEndpoint(RedisEndpointType.SERVICE, type.name()); + } + + public static RedisEndpoint service(String id) { + return new RedisEndpoint(RedisEndpointType.SERVICE, id); + } + + public static RedisEndpoint server(UUID uuid) { + return new RedisEndpoint(RedisEndpointType.SERVER, uuid.toString()); + } + + public static RedisEndpoint server(String uuid) { + return new RedisEndpoint(RedisEndpointType.SERVER, uuid); + } +} diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisEndpointType.java b/commons/src/main/java/net/swofty/commons/redis/RedisEndpointType.java new file mode 100644 index 000000000..594b6f1a6 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisEndpointType.java @@ -0,0 +1,7 @@ +package net.swofty.commons.redis; + +public enum RedisEndpointType { + PROXY, + SERVER, + SERVICE +} diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisMessageBus.java b/commons/src/main/java/net/swofty/commons/redis/RedisMessageBus.java new file mode 100644 index 000000000..62d85f834 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisMessageBus.java @@ -0,0 +1,214 @@ +package net.swofty.commons.redis; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.redisapi.api.ChannelRegistry; +import net.swofty.redisapi.api.RedisAPI; +import org.tinylog.Logger; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RedisMessageBus { + private static final Map>> handlers = new ConcurrentHashMap<>(); + private static final Map> pendingResponses = new ConcurrentHashMap<>(); + private static final Map pendingBroadcasts = new ConcurrentHashMap<>(); + private static final Map registeredChannels = new ConcurrentHashMap<>(); + private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread thread = new Thread(r, "redis-message-bus-timeouts"); + thread.setDaemon(true); + return thread; + }); + + public static void registerHandler(RedisEndpoint localEndpoint, + String channel, + RedisMessageHandler handler, + ContextFactory contextFactory, + Function responseTarget, + Function responseChannel) { + handlers.computeIfAbsent(channel, ignored -> new CopyOnWriteArrayList<>()) + .add(new RegisteredHandler<>(localEndpoint, handler, contextFactory, responseTarget, responseChannel)); + ensureChannelRegistered(channel); + } + + public static void registerResponseChannel(String channel) { + ensureChannelRegistered(channel); + } + + public static CompletableFuture request(RedisEndpoint origin, + String target, + String requestChannel, + String responseChannel, + RedisProtocol protocol, + T message) { + return requestRaw(origin, target, requestChannel, responseChannel, protocol, message) + .thenApply(protocol::translateReturnFromString); + } + + public static CompletableFuture requestRaw(RedisEndpoint origin, + String target, + String requestChannel, + String responseChannel, + RedisProtocol protocol, + Object message) { + UUID requestId = UUID.randomUUID(); + CompletableFuture future = new CompletableFuture<>(); + + ensureChannelRegistered(responseChannel); + pendingResponses.put(requestId, future); + future.orTimeout(10, TimeUnit.SECONDS) + .whenComplete((ignored, throwable) -> pendingResponses.remove(requestId)); + + publishRaw(requestId, origin, target, requestChannel, protocol.translateToString(message)); + return future; + } + + public static void publish(RedisEndpoint origin, + String target, + String channel, + RedisProtocol protocol, + Object message) { + publishRaw(UUID.randomUUID(), origin, target, channel, protocol.translateToString(message)); + } + + public static CompletableFuture> requestBroadcast(RedisEndpoint origin, + String target, + String requestChannel, + String responseChannel, + RedisProtocol protocol, + T message, + int timeoutMs) { + UUID requestId = UUID.randomUUID(); + BroadcastCollector collector = new BroadcastCollector(); + pendingBroadcasts.put(requestId, collector); + ensureChannelRegistered(responseChannel); + + publishRaw(requestId, origin, target, requestChannel, protocol.translateToString(message)); + + scheduler.schedule(() -> { + BroadcastCollector removed = pendingBroadcasts.remove(requestId); + if (removed != null) { + removed.complete(); + } + }, timeoutMs, TimeUnit.MILLISECONDS); + + return collector.future().thenApply(rawResponses -> { + Map typedResponses = new ConcurrentHashMap<>(); + rawResponses.forEach((uuid, payload) -> { + try { + typedResponses.put(uuid, protocol.translateReturnFromString(payload)); + } catch (Exception exception) { + Logger.error(exception, "Failed to deserialize Redis broadcast response from {}", uuid); + } + }); + return typedResponses; + }); + } + + public static void publishRaw(UUID requestId, + RedisEndpoint origin, + String target, + String channel, + String payload) { + RedisAPI.getInstance().publishMessage( + target, + ChannelRegistry.getFromName(channel), + new RedisEnvelope(requestId.toString(), origin.id(), payload).serialize() + ); + } + + private static void ensureChannelRegistered(String channel) { + if (registeredChannels.putIfAbsent(channel, true) != null) return; + + RedisAPI.getInstance().registerChannel(channel, event -> { + RedisEnvelope envelope = unwrap(event.message); + UUID requestId = UUID.fromString(envelope.id()); + + CompletableFuture pendingResponse = pendingResponses.remove(requestId); + if (pendingResponse != null) { + pendingResponse.complete(envelope.payload()); + return; + } + + BroadcastCollector collector = pendingBroadcasts.get(requestId); + if (collector != null) { + collector.add(UUID.fromString(envelope.from()), envelope.payload()); + return; + } + + List> channelHandlers = handlers.get(event.channel); + if (channelHandlers == null) return; + + channelHandlers.forEach(handler -> Thread.startVirtualThread(() -> handler.handle(envelope, event.channel))); + }); + } + + private static RedisEnvelope unwrap(String message) { + int split = message.indexOf(";"); + return RedisEnvelope.deserialize(split == -1 ? message : message.substring(split + 1)); + } + + @FunctionalInterface + public interface ContextFactory { + RedisMessageContext create(RedisEnvelope envelope, String channel); + } + + private record RegisteredHandler( + RedisEndpoint localEndpoint, + RedisMessageHandler handler, + ContextFactory contextFactory, + Function responseTarget, + Function responseChannel + ) { + private void handle(RedisEnvelope envelope, String channel) { + RedisProtocol protocol = handler.protocol(); + + try { + T message = protocol.translateFromString(envelope.payload()); + RedisMessageContext context = contextFactory.create(envelope, channel); + R response = handler.handle(message, context); + if (response == null) return; + + publishRaw( + UUID.fromString(envelope.id()), + localEndpoint, + responseTarget.apply(envelope), + responseChannel.apply(envelope), + protocol.translateReturnToString(response) + ); + } catch (Exception exception) { + Logger.error(exception, "Failed to handle Redis message on channel {}", channel); + } + } + } + + private static final class BroadcastCollector { + private final CompletableFuture> future = new CompletableFuture<>(); + private final Map responses = new ConcurrentHashMap<>(); + + private void add(UUID endpoint, String payload) { + if (!future.isDone()) { + responses.put(endpoint, payload); + } + } + + private void complete() { + future.complete(Map.copyOf(responses)); + } + + private CompletableFuture> future() { + return future; + } + } +} diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisMessageContext.java b/commons/src/main/java/net/swofty/commons/redis/RedisMessageContext.java new file mode 100644 index 000000000..031e09be1 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisMessageContext.java @@ -0,0 +1,62 @@ +package net.swofty.commons.redis; + +import java.util.UUID; + +public record RedisMessageContext( + UUID requestId, + RedisEndpoint origin, + RedisEndpoint destination, + String channel, + boolean broadcast +) { + public static RedisMessageContext between(UUID requestId, + RedisEndpoint origin, + RedisEndpoint destination, + String channel) { + return new RedisMessageContext(requestId, origin, destination, channel, false); + } + + public static RedisMessageContext proxyToServer(UUID requestId, String proxyId, String serverId, String channel) { + return new RedisMessageContext( + requestId, + RedisEndpoint.proxy(), + RedisEndpoint.server(serverId), + channel, + false + ); + } + + public static RedisMessageContext serverToProxy(UUID requestId, String serverId, String channel) { + return new RedisMessageContext( + requestId, + RedisEndpoint.server(serverId), + RedisEndpoint.proxy(), + channel, + false + ); + } + + public static RedisMessageContext serverToService(UUID requestId, String serverId, String serviceId, String channel) { + return new RedisMessageContext( + requestId, + RedisEndpoint.server(serverId), + RedisEndpoint.service(serviceId), + channel, + false + ); + } + + public static RedisMessageContext serviceToServer(UUID requestId, String serviceId, String serverId, String channel) { + return new RedisMessageContext( + requestId, + RedisEndpoint.service(serviceId), + RedisEndpoint.server(serverId), + channel, + false + ); + } + + public RedisMessageContext asBroadcast() { + return new RedisMessageContext(requestId, origin, destination, channel, true); + } +} diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisMessageHandler.java b/commons/src/main/java/net/swofty/commons/redis/RedisMessageHandler.java new file mode 100644 index 000000000..91f1c8ec8 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/redis/RedisMessageHandler.java @@ -0,0 +1,9 @@ +package net.swofty.commons.redis; + +import net.swofty.commons.protocol.RedisProtocol; + +public interface RedisMessageHandler { + RedisProtocol protocol(); + + R handle(T message, RedisMessageContext context); +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/SkyBlockPlayerProfiles.java b/commons/src/main/java/net/swofty/commons/skyblock/SkyBlockPlayerProfiles.java index 85fcc7701..72d51eeba 100644 --- a/commons/src/main/java/net/swofty/commons/skyblock/SkyBlockPlayerProfiles.java +++ b/commons/src/main/java/net/swofty/commons/skyblock/SkyBlockPlayerProfiles.java @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -62,7 +61,7 @@ public static SkyBlockPlayerProfiles deserialize(Map map) { } public static String getRandomName() { - return PROFILE_NAMES[new Random().nextInt(PROFILE_NAMES.length)]; + return PROFILE_NAMES[java.util.concurrent.ThreadLocalRandom.current().nextInt(PROFILE_NAMES.length)]; } public static SkyBlockPlayerProfiles get(UUID uuid) { diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingExpertiseKills.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingExpertiseKills.java new file mode 100644 index 000000000..1eb86bfcb --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingExpertiseKills.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingExpertiseKills extends ItemAttribute { + @Override + public String getKey() { + return "fishing_expertise_kills"; + } + + @Override + public Long getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return 0L; + } + + @Override + public Long loadFromString(String string) { + return Long.parseLong(string); + } + + @Override + public String saveIntoString() { + return String.valueOf(getValue()); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingHook.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingHook.java new file mode 100644 index 000000000..704b574c7 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingHook.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingHook extends ItemAttribute { + @Override + public String getKey() { + return "fishing_hook"; + } + + @Override + public String getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return "none"; + } + + @Override + public String loadFromString(String string) { + return string == null || string.isBlank() ? "none" : string; + } + + @Override + public String saveIntoString() { + return getValue() == null || getValue().isBlank() ? "none" : getValue(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingLine.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingLine.java new file mode 100644 index 000000000..bf6ca37ba --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingLine.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingLine extends ItemAttribute { + @Override + public String getKey() { + return "fishing_line"; + } + + @Override + public String getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return "none"; + } + + @Override + public String loadFromString(String string) { + return string == null || string.isBlank() ? "none" : string; + } + + @Override + public String saveIntoString() { + return getValue() == null || getValue().isBlank() ? "none" : getValue(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingSinker.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingSinker.java new file mode 100644 index 000000000..daa12ee81 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingSinker.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingSinker extends ItemAttribute { + @Override + public String getKey() { + return "fishing_sinker"; + } + + @Override + public String getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return "none"; + } + + @Override + public String loadFromString(String string) { + return string == null || string.isBlank() ? "none" : string; + } + + @Override + public String saveIntoString() { + return getValue() == null || getValue().isBlank() ? "none" : getValue(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeReforge.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeReforge.java index 7bcd08999..4a42f7695 100644 --- a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeReforge.java +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeReforge.java @@ -4,6 +4,7 @@ import net.swofty.commons.skyblock.item.reforge.ReforgeLoader; import net.swofty.commons.skyblock.statistics.ItemStatistics; import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; public class ItemAttributeReforge extends ItemAttribute { @Override @@ -26,7 +27,7 @@ public String loadFromString(String string) { return string; } - System.err.println("Unknown reforge: " + string); + Logger.warn("Unknown reforge: {}", string); return null; } diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeExpressionEvaluator.java b/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeExpressionEvaluator.java index 312f3472b..17b58680e 100644 --- a/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeExpressionEvaluator.java +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeExpressionEvaluator.java @@ -34,7 +34,7 @@ private static String replaceVariables(String expression, Map va if (value != null) { matcher.appendReplacement(result, value.toString()); } else { - System.err.println("Variable not found: " + varName); + Logger.warn("Variable not found: {}", varName); matcher.appendReplacement(result, "0"); } } diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeLoader.java b/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeLoader.java index 40f377c12..79ce87419 100644 --- a/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeLoader.java +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/reforge/ReforgeLoader.java @@ -52,7 +52,7 @@ public static void loadAllReforges() { File[] reforgeFiles = REFORGES_DIR.listFiles((dir, name) -> name.toLowerCase().endsWith(".yml")); if (reforgeFiles == null) { - System.out.println("No reforge files found in " + REFORGES_DIR.getPath()); + Logger.info("No reforge files found in {}", REFORGES_DIR.getPath()); return; } @@ -77,7 +77,7 @@ private static Reforge loadFromFile(File file) { ReforgeConfig config = yaml.loadAs(new FileReader(file), ReforgeConfig.class); if (config == null) { - System.err.println("Failed to parse reforge config from: " + file.getName()); + Logger.error("Failed to parse reforge config from: {}", file.getName()); return null; } @@ -97,7 +97,7 @@ private static Reforge parseReforge(ReforgeConfig config) { ReforgeType type = ReforgeType.valueOf(typeStr.toUpperCase()); applicableTypes.add(type); } catch (IllegalArgumentException e) { - System.err.println("Unknown reforge type: " + typeStr + " for reforge: " + config.name); + Logger.warn("Unknown reforge type: {} for reforge: {}", typeStr, config.name); } } } @@ -123,7 +123,7 @@ private static BiFunction createCalcula double value = calculateStatisticValue(data, level); result = result.addBase(statistic, value); } catch (IllegalArgumentException e) { - System.err.println("Unknown statistic: " + entry.getKey()); + Logger.warn("Unknown statistic: {}", entry.getKey()); } } } @@ -227,7 +227,7 @@ public static boolean isReforgeApplicable(String reforgeName, ReforgeType type) // Utility method to reload all reforges public static void reloadReforges() { - System.out.println("Reloading all reforges..."); + Logger.info("Reloading all reforges..."); loadAllReforges(); } } \ No newline at end of file diff --git a/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java b/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java index 2c9e75300..bf2f12a24 100644 --- a/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java +++ b/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java @@ -80,6 +80,9 @@ public enum ItemStatistic { PET_LUCK("Pet Luck", "§a", "§d", false, "♣"), SEA_CREATURE_CHANCE("Sea Creature Chance", "§c", "§9", true, "α", 2D, 1D), FISHING_SPEED("Fishing Speed", "§a", "§b", false, "☂"), + TREASURE_CHANCE("Treasure Chance", "§a", "§6", true, "⛃"), + TROPHY_FISH_CHANCE("Trophy Fish Chance", "§a", "§6", true, "♔"), + DOUBLE_HOOK_CHANCE("Double Hook Chance", "§a", "§3", true, "⚓"), BONUS_PEST_CHANCE("Bonus Pest Chance", "§a", "§2", true, "ൠ"), HEAT_RESISTANCE("Heat Resistance","§a","§c",false,"♨"), COLD_RESISTANCE("Cold Resistance", "§a", "§b", false, "❄"), diff --git a/commons/src/main/java/net/swofty/commons/skywars/SkywarsLevelUtil.java b/commons/src/main/java/net/swofty/commons/skywars/SkywarsLevelUtil.java index 0987ffaaa..9cdfb954f 100644 --- a/commons/src/main/java/net/swofty/commons/skywars/SkywarsLevelUtil.java +++ b/commons/src/main/java/net/swofty/commons/skywars/SkywarsLevelUtil.java @@ -1,8 +1,12 @@ package net.swofty.commons.skywars; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import java.text.DecimalFormat; -public class SkywarsLevelUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SkywarsLevelUtil { private static final DecimalFormat FORMAT = new DecimalFormat("#,###.#"); diff --git a/commons/src/test/java/net/swofty/commons/ChatUtilityTest.java b/commons/src/test/java/net/swofty/commons/ChatUtilityTest.java new file mode 100644 index 000000000..973091ecd --- /dev/null +++ b/commons/src/test/java/net/swofty/commons/ChatUtilityTest.java @@ -0,0 +1,83 @@ +package net.swofty.commons; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ChatUtilityTest { + + @Test + void stripTokensRemovesColorCodes() { + assertEquals("Hello", ChatUtility.FontInfo.stripTokens("§aHello")); + assertEquals("Plain", ChatUtility.FontInfo.stripTokens("Plain")); + assertEquals("Mixed text", ChatUtility.FontInfo.stripTokens("§cMixed §btext")); + assertEquals("", ChatUtility.FontInfo.stripTokens("§a§b§c")); + } + + @Test + void getDefaultFontInfoFindsKnownChars() { + assertEquals(ChatUtility.FontInfo.A, ChatUtility.FontInfo.getDefaultFontInfo('A')); + assertEquals(ChatUtility.FontInfo.i, ChatUtility.FontInfo.getDefaultFontInfo('i')); + assertEquals(ChatUtility.FontInfo.SPACE, ChatUtility.FontInfo.getDefaultFontInfo(' ')); + assertEquals(ChatUtility.FontInfo.NUM_5, ChatUtility.FontInfo.getDefaultFontInfo('5')); + } + + @Test + void getDefaultFontInfoFallsBackForUnknown() { + // Characters that aren't in the table return DEFAULT + assertEquals(ChatUtility.FontInfo.DEFAULT, ChatUtility.FontInfo.getDefaultFontInfo('Ω')); + assertEquals(ChatUtility.FontInfo.DEFAULT, ChatUtility.FontInfo.getDefaultFontInfo('€')); + } + + @Test + void getLengthEmptyStringIsZero() { + assertEquals(0, ChatUtility.FontInfo.getLength("")); + } + + @Test + void getLengthIgnoresColorCodes() { + // Color codes don't contribute width + int plain = ChatUtility.FontInfo.getLength("Hello"); + int colored = ChatUtility.FontInfo.getLength("§aHello"); + int doubleColored = ChatUtility.FontInfo.getLength("§c§oHello"); + assertEquals(plain, colored); + assertEquals(plain, doubleColored); + } + + @Test + void getLengthCountsEachCharacter() { + // Each letter adds its declared length + 1 spacing pixel. + // 'H','e','l','l','o' -> 5+1 + 5+1 + 1+1 + 1+1 + 5+1 = 22 + assertEquals(22, ChatUtility.FontInfo.getLength("Hello")); + } + + @Test + void centerLinesPadsEachLine() { + List input = List.of("Short", "A longer line"); + List output = ChatUtility.FontInfo.centerLines(input); + assertEquals(input.size(), output.size()); + // Each output line ends with the input line + for (int i = 0; i < input.size(); i++) { + assertTrue(output.get(i).endsWith(input.get(i)), + "Output line should end with input: " + output.get(i)); + } + } + + @Test + void centerEmptyStringYieldsEmptyPad() { + // Implementation returns "" for null or empty + assertEquals("", ChatUtility.FontInfo.getCenterSpaces("")); + assertEquals("", ChatUtility.FontInfo.getCenterSpaces(null)); + } + + @Test + void fontInfoCharacterAndLengthMatch() { + // Spot-check a few entries to lock down the data + assertEquals('A', ChatUtility.FontInfo.A.getCharacter()); + assertEquals(5, ChatUtility.FontInfo.A.getLength()); + assertEquals(1, ChatUtility.FontInfo.i.getLength()); + assertEquals(3, ChatUtility.FontInfo.SPACE.getLength()); + } +} diff --git a/commons/src/test/java/net/swofty/commons/ResultTest.java b/commons/src/test/java/net/swofty/commons/ResultTest.java new file mode 100644 index 000000000..7bdd381fb --- /dev/null +++ b/commons/src/test/java/net/swofty/commons/ResultTest.java @@ -0,0 +1,122 @@ +package net.swofty.commons; + +import org.junit.jupiter.api.Test; + +import java.util.NoSuchElementException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.*; + +class ResultTest { + + @Test + void okHoldsValue() { + Result r = Result.ok(42); + assertTrue(r.isOk()); + assertFalse(r.isErr()); + assertEquals(42, r.unwrap()); + assertEquals(42, r.orElse(0)); + assertEquals(42, r.ok().orElseThrow()); + assertTrue(r.err().isEmpty()); + } + + @Test + void errHoldsError() { + Result r = Result.err("boom"); + assertTrue(r.isErr()); + assertFalse(r.isOk()); + assertEquals("boom", r.unwrapErr()); + assertEquals(99, r.orElse(99)); + assertEquals("boom", r.err().orElseThrow()); + assertTrue(r.ok().isEmpty()); + } + + @Test + void unwrapOnErrThrows() { + Result r = Result.err("nope"); + assertThrows(NoSuchElementException.class, r::unwrap); + } + + @Test + void unwrapErrOnOkThrows() { + Result r = Result.ok(1); + assertThrows(NoSuchElementException.class, r::unwrapErr); + } + + @Test + void mapTransformsSuccess() { + Result r = Result.ok(3).map(x -> x * x); + assertEquals(9, r.unwrap()); + } + + @Test + void mapPassesThroughError() { + Result r = Result.err("e").map(x -> x * x); + assertEquals("e", r.unwrapErr()); + } + + @Test + void mapErrTransformsError() { + Result r = Result.err("bad").mapErr(String::length); + assertEquals(3, r.unwrapErr()); + } + + @Test + void flatMapChainsResults() { + Result r = Result.ok(2) + .flatMap(x -> Result.ok(x + 10)); + assertEquals(12, r.unwrap()); + + Result failed = Result.ok(2) + .flatMap(x -> Result.err("downstream")); + assertEquals("downstream", failed.unwrapErr()); + } + + @Test + void ifOkAndIfErrRunOnlyOnMatchingVariant() { + AtomicReference seen = new AtomicReference<>(); + AtomicInteger errCounter = new AtomicInteger(0); + + Result.ok(7) + .ifOk(seen::set) + .ifErr(e -> errCounter.incrementAndGet()); + + assertEquals(7, seen.get()); + assertEquals(0, errCounter.get()); + + seen.set(null); + Result.err("x") + .ifOk(seen::set) + .ifErr(e -> errCounter.incrementAndGet()); + + assertNull(seen.get()); + assertEquals(1, errCounter.get()); + } + + @Test + void attemptCapturesException() { + Result ok = Result.attempt(() -> 5); + assertEquals(5, ok.unwrap()); + + Result err = Result.attempt(() -> { throw new IllegalStateException("oh no"); }); + assertTrue(err.isErr()); + assertInstanceOf(IllegalStateException.class, err.unwrapErr()); + } + + @Test + void switchPatternMatchingIsExhaustive() { + Result r = Result.ok(1); + String msg = switch (r) { + case Result.Ok ok -> "ok: " + ok.value(); + case Result.Err err -> "err: " + err.error(); + }; + assertEquals("ok: 1", msg); + } + + @Test + void nullsRejected() { + assertThrows(NullPointerException.class, () -> Result.ok(null)); + assertThrows(NullPointerException.class, () -> Result.err(null)); + } +} diff --git a/commons/src/test/java/net/swofty/commons/StringUtilityTest.java b/commons/src/test/java/net/swofty/commons/StringUtilityTest.java new file mode 100644 index 000000000..c5e06338a --- /dev/null +++ b/commons/src/test/java/net/swofty/commons/StringUtilityTest.java @@ -0,0 +1,94 @@ +package net.swofty.commons; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +class StringUtilityTest { + + @Test + void romanNumeralZeroIsEmpty() { + assertEquals("", StringUtility.getAsRomanNumeral(0)); + } + + @Test + void romanNumeralSingleDigits() { + assertEquals("I", StringUtility.getAsRomanNumeral(1)); + assertEquals("IV", StringUtility.getAsRomanNumeral(4)); + assertEquals("V", StringUtility.getAsRomanNumeral(5)); + assertEquals("IX", StringUtility.getAsRomanNumeral(9)); + } + + @Test + void romanNumeralCompound() { + assertEquals("XLII", StringUtility.getAsRomanNumeral(42)); + assertEquals("MCMXCIX", StringUtility.getAsRomanNumeral(1999)); + assertEquals("MMXXVI", StringUtility.getAsRomanNumeral(2026)); + } + + @Test + void capitalizeNormalCase() { + assertEquals("Hello", StringUtility.capitalize("hello")); + assertEquals("World", StringUtility.capitalize("WORLD")); + } + + @Test + void capitalizeEdgeCases() { + assertEquals("", StringUtility.capitalize("")); + assertNull(StringUtility.capitalize(null)); + assertEquals("A", StringUtility.capitalize("a")); + assertEquals("A", StringUtility.capitalize("A")); + } + + @Test + void shortenNumberSmallValues() { + assertEquals("0", StringUtility.shortenNumber(0)); + assertEquals("999", StringUtility.shortenNumber(999)); + } + + @Test + void shortenNumberThousands() { + assertEquals("1.0K", StringUtility.shortenNumber(1000)); + assertEquals("1.5K", StringUtility.shortenNumber(1500)); + assertEquals("999.9K", StringUtility.shortenNumber(999_900)); + } + + @Test + void shortenNumberMillionsAndBillions() { + assertEquals("1.0M", StringUtility.shortenNumber(1_000_000)); + assertEquals("2.5M", StringUtility.shortenNumber(2_500_000)); + assertEquals("1.0B", StringUtility.shortenNumber(1_000_000_000)); + } + + @Test + void commaifyAddsThousandsSeparators() { + assertEquals("1,234", StringUtility.commaify(1234)); + assertEquals("1,000,000", StringUtility.commaify(1_000_000)); + assertEquals("0", StringUtility.commaify(0)); + } + + @Test + void roundToPrecision() { + assertEquals(3.14, StringUtility.roundTo(3.14159, 2), 1e-9); + assertEquals(3.142, StringUtility.roundTo(3.14159, 3), 1e-9); + assertEquals(3.0, StringUtility.roundTo(3.14159, 0), 1e-9); + } + + @Test + void formatTimeLeftBoundaries() { + assertEquals("0s", StringUtility.formatTimeLeft(0)); + assertEquals("59s", StringUtility.formatTimeLeft(59_000)); + assertEquals("1m", StringUtility.formatTimeLeft(60_000)); + assertEquals("1m 30s", StringUtility.formatTimeLeft(90_000)); + assertEquals("1h", StringUtility.formatTimeLeft(3_600_000)); + assertEquals("1d", StringUtility.formatTimeLeft(86_400_000)); + } + + @Test + void stripColorRemovesSectionCodes() { + assertEquals("Hello", StringUtility.stripColor("§aHello")); + assertEquals("Plain", StringUtility.stripColor("Plain")); + assertEquals("Mixed text", StringUtility.stripColor("§cMixed §btext")); + } +} diff --git a/commons/src/test/java/net/swofty/commons/protocol/ServicePushProtocolTest.java b/commons/src/test/java/net/swofty/commons/protocol/ServicePushProtocolTest.java deleted file mode 100644 index a6d4e8828..000000000 --- a/commons/src/test/java/net/swofty/commons/protocol/ServicePushProtocolTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.swofty.commons.protocol; - -import org.junit.jupiter.api.Test; -import java.util.UUID; -import static org.junit.jupiter.api.Assertions.*; - -class ServicePushProtocolTest { - - public record TestPushRequest(UUID playerId, String item, int amount) {} - public record TestPushResponse(boolean handled) {} - - static class TestPush extends ServicePushProtocol { - public TestPush() { - super(TestPushRequest.class, TestPushResponse.class); - } - } - - @Test - void channelNameDerivedFromClassName() { - var protocol = new TestPush(); - assertEquals("TestPush", protocol.channel()); - } - - @Test - void serializesRequestRoundTrip() { - var protocol = new TestPush(); - UUID id = UUID.randomUUID(); - var original = new TestPushRequest(id, "diamond", 5); - String json = protocol.translateToString(original); - TestPushRequest result = protocol.translateFromString(json); - assertEquals(id, result.playerId()); - assertEquals("diamond", result.item()); - assertEquals(5, result.amount()); - } - - @Test - void serializesResponseRoundTrip() { - var protocol = new TestPush(); - var original = new TestPushResponse(true); - String json = protocol.translateReturnToString(original); - TestPushResponse result = protocol.translateReturnFromString(json); - assertTrue(result.handled()); - } -} diff --git a/configuration/skyblock/fishing/hotspots.yml b/configuration/skyblock/fishing/hotspots.yml new file mode 100644 index 000000000..c266f0dc0 --- /dev/null +++ b/configuration/skyblock/fishing/hotspots.yml @@ -0,0 +1,19 @@ +hotspots: + - id: BAYOU_WATER_1 + medium: WATER + regions: + - BACKWATER_BAYOU + serverType: BACKWATER_BAYOU + durationSeconds: 120 + maxActive: 2 + buffs: + FISHING_SPEED: 15 + SEA_CREATURE_CHANCE: 5 + DOUBLE_HOOK_CHANCE: 2 + TROPHY_FISH_CHANCE: 5 + TREASURE_CHANCE: 1 + spawnPoints: + - serverType: BACKWATER_BAYOU + x: 100 + y: 50 + z: 100 diff --git a/configuration/skyblock/fishing/sea_creatures.yml b/configuration/skyblock/fishing/sea_creatures.yml new file mode 100644 index 000000000..8b96f3547 --- /dev/null +++ b/configuration/skyblock/fishing/sea_creatures.yml @@ -0,0 +1,88 @@ +seaCreatures: + # ---------- water ---------- + - id: SQUID + requiredFishingLevel: 1 + skillXp: 20 + tags: [WATER, COMMON] + - id: SEA_WALKER + requiredFishingLevel: 4 + skillXp: 40 + tags: [WATER, COMMON] + - id: NIGHT_SQUID + requiredFishingLevel: 6 + skillXp: 80 + tags: [WATER, NIGHT, UNCOMMON] + - id: SEA_GUARDIAN + requiredFishingLevel: 8 + skillXp: 120 + tags: [WATER, UNCOMMON] + - id: SEA_WITCH + requiredFishingLevel: 10 + skillXp: 150 + tags: [WATER, UNCOMMON] + - id: SEA_ARCHER + requiredFishingLevel: 15 + skillXp: 200 + tags: [WATER, RARE] + - id: MONSTER_OF_THE_DEEP + requiredFishingLevel: 20 + skillXp: 300 + tags: [WATER, RARE] + - id: CATFISH + requiredFishingLevel: 24 + skillXp: 400 + tags: [WATER, RAINING, RARE] + - id: CARROT_KING + requiredFishingLevel: 26 + skillXp: 500 + tags: [WATER, RARE] + - id: SEA_LEECH + requiredFishingLevel: 30 + skillXp: 650 + tags: [WATER, EPIC] + - id: GUARDIAN_DEFENDER + requiredFishingLevel: 35 + skillXp: 900 + tags: [WATER, EPIC] + - id: WATER_HYDRA + requiredFishingLevel: 60 + skillXp: 7500 + tags: [WATER, LEGENDARY] + - id: THE_SEA_EMPEROR + requiredFishingLevel: 80 + skillXp: 20000 + tags: [WATER, MYTHIC] + + # ---------- lava (Crimson Isle) ---------- + - id: MAGMA_SLUG + requiredFishingLevel: 21 + skillXp: 450 + tags: [LAVA, CRIMSON, COMMON] + - id: MOOGMA + requiredFishingLevel: 22 + skillXp: 500 + tags: [LAVA, CRIMSON, COMMON] + - id: LAVA_LEECH + requiredFishingLevel: 24 + skillXp: 550 + tags: [LAVA, CRIMSON, COMMON] + - id: PYROCLASTIC_WORM + requiredFishingLevel: 28 + skillXp: 800 + tags: [LAVA, CRIMSON, UNCOMMON] + - id: FIRE_EEL + requiredFishingLevel: 28 + skillXp: 800 + tags: [LAVA, CRIMSON, UNCOMMON] + - id: LAVA_BLAZE + requiredFishingLevel: 30 + skillXp: 1000 + tags: [LAVA, CRIMSON, RARE] + - id: TAURUS + requiredFishingLevel: 36 + skillXp: 2500 + tags: [LAVA, CRIMSON, EPIC] + - id: LORD_JAWBUS + requiredFishingLevel: 45 + skillXp: 15000 + tags: [LAVA, CRIMSON, LEGENDARY] diff --git a/configuration/skyblock/fishing/tables.yml b/configuration/skyblock/fishing/tables.yml new file mode 100644 index 000000000..a429e3b80 --- /dev/null +++ b/configuration/skyblock/fishing/tables.yml @@ -0,0 +1,206 @@ +tables: + - id: DEFAULT_WATER + regions: [ ] + mediums: + - WATER + items: + - itemId: RAW_FISH + chance: 36 + amount: 1 + skillXp: 5 + - itemId: RAW_SALMON + chance: 22 + amount: 1 + skillXp: 6 + - itemId: PUFFERFISH + chance: 10 + amount: 1 + skillXp: 7 + - itemId: INK_SAC + chance: 8 + amount: 1 + skillXp: 5 + - itemId: LILY_PAD + chance: 8 + amount: 1 + skillXp: 5 + - itemId: CLAY_BALL + chance: 6 + amount: 1 + skillXp: 5 + - itemId: PRISMARINE_CRYSTALS + chance: 4 + amount: 1 + skillXp: 6 + - itemId: PRISMARINE_SHARD + chance: 3 + amount: 1 + skillXp: 6 + - itemId: TROPICAL_FISH + chance: 2 + amount: 1 + skillXp: 8 + - itemId: SPONGE + chance: 1 + amount: 1 + skillXp: 10 + treasures: + - itemId: PRISMARINE_CRYSTALS + chance: 50 + amount: 2 + skillXp: 10 + - itemId: PRISMARINE_SHARD + chance: 35 + amount: 2 + skillXp: 10 + - itemId: SPONGE + chance: 15 + amount: 1 + skillXp: 12 + junk: [ ] + seaCreatures: + - seaCreatureId: SQUID + chance: 6 + - seaCreatureId: SEA_WALKER + chance: 4 + - seaCreatureId: NIGHT_SQUID + chance: 2 + - id: DEFAULT_LAVA + regions: [ ] + mediums: + - LAVA + items: + - itemId: MAGMAFISH + chance: 100 + amount: 1 + skillXp: 10 + treasures: + - itemId: MAGMAFISH + chance: 100 + amount: 2 + skillXp: 15 + junk: [ ] + seaCreatures: + - seaCreatureId: LAVA_BLAZE + chance: 5 + - id: BAYOU_WATERS + regions: + - BACKWATER_BAYOU + mediums: + - WATER + items: + - itemId: RAW_FISH + chance: 30 + amount: 1 + skillXp: 5 + - itemId: RAW_SALMON + chance: 20 + amount: 1 + skillXp: 6 + - itemId: PUFFERFISH + chance: 10 + amount: 1 + skillXp: 7 + - itemId: INK_SAC + chance: 8 + amount: 1 + skillXp: 5 + - itemId: LILY_PAD + chance: 8 + amount: 1 + skillXp: 5 + - itemId: CLAY_BALL + chance: 8 + amount: 1 + skillXp: 5 + - itemId: PRISMARINE_CRYSTALS + chance: 5 + amount: 1 + skillXp: 6 + - itemId: PRISMARINE_SHARD + chance: 4 + amount: 1 + skillXp: 6 + - itemId: TROPICAL_FISH + chance: 5 + amount: 1 + skillXp: 8 + - itemId: SPONGE + chance: 2 + amount: 1 + skillXp: 10 + treasures: + - itemId: PRISMARINE_CRYSTALS + chance: 40 + amount: 2 + skillXp: 10 + - itemId: PRISMARINE_SHARD + chance: 30 + amount: 2 + skillXp: 10 + - itemId: SPONGE + chance: 20 + amount: 1 + skillXp: 12 + - itemId: CLAY_BALL + chance: 10 + amount: 4 + skillXp: 8 + junk: + - itemId: RUSTY_COIN + chance: 50 + amount: 1 + skillXp: 2 + - itemId: BUSTED_BELT_BUCKLE + chance: 30 + amount: 1 + skillXp: 2 + - itemId: OLD_LEATHER_BOOT + chance: 20 + amount: 1 + skillXp: 2 + seaCreatures: + - seaCreatureId: ALLIGATOR + chance: 5 + - seaCreatureId: BANSHEE + chance: 3 + - seaCreatureId: BAYOU_SLUDGE + chance: 3 + - seaCreatureId: DUMPSTER_DIVER + chance: 2 + - seaCreatureId: TITANOBOA + chance: 1 + - seaCreatureId: TRASH_GOBBLER + chance: 1 + - id: CRIMSON_ISLE_LAVA + regions: + - CRIMSON_ISLE + - BLAZING_VOLCANO + mediums: + - LAVA + items: + - itemId: MAGMAFISH + chance: 100 + amount: 1 + skillXp: 10 + treasures: + - itemId: MAGMAFISH + chance: 75 + amount: 2 + skillXp: 15 + - itemId: SULPHUR + chance: 25 + amount: 2 + skillXp: 15 + junk: [ ] + seaCreatures: + - seaCreatureId: LAVA_BLAZE + chance: 3 + - seaCreatureId: FRIED_CHICKEN + chance: 2 + - seaCreatureId: FIREPROOF_WITCH + chance: 2 + - seaCreatureId: FIERY_SCUTTLER + chance: 1 + - seaCreatureId: RAGNAROK + chance: 1 diff --git a/configuration/skyblock/fishing/trophy_fish.yml b/configuration/skyblock/fishing/trophy_fish.yml new file mode 100644 index 000000000..221ff93b0 --- /dev/null +++ b/configuration/skyblock/fishing/trophy_fish.yml @@ -0,0 +1,171 @@ +trophyFish: + - id: SULPHUR_SKITTER + displayName: Sulphur Skitter + catchChance: 30 + regions: [BLAZING_VOLCANO] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_SULPHUR_SKITTER + silverItemId: SILVER_SULPHUR_SKITTER + goldItemId: GOLD_SULPHUR_SKITTER + diamondItemId: DIAMOND_SULPHUR_SKITTER + - id: BLOBFISH + displayName: Blobfish + catchChance: 25 + regions: [ ] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_BLOBFISH + silverItemId: SILVER_BLOBFISH + goldItemId: GOLD_BLOBFISH + diamondItemId: DIAMOND_BLOBFISH + - id: OBFUSCATED_1 + displayName: Obfuscated 1 + catchChance: 25 + regions: [ ] + requiredFishingLevel: 0 + requiredBaitId: CORRUPTED_BAIT + bronzeItemId: BRONZE_OBFUSCATED_1 + silverItemId: SILVER_OBFUSCATED_1 + goldItemId: GOLD_OBFUSCATED_1 + diamondItemId: DIAMOND_OBFUSCATED_1 + - id: STEAMING_HOT_FLOUNDER + displayName: Steaming-Hot Flounder + catchChance: 20 + regions: [BLAZING_VOLCANO] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_STEAMING_HOT_FLOUNDER + silverItemId: SILVER_STEAMING_HOT_FLOUNDER + goldItemId: GOLD_STEAMING_HOT_FLOUNDER + diamondItemId: DIAMOND_STEAMING_HOT_FLOUNDER + - id: GUSHER + displayName: Gusher + catchChance: 20 + regions: [BLAZING_VOLCANO] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_GUSHER + silverItemId: SILVER_GUSHER + goldItemId: GOLD_GUSHER + diamondItemId: DIAMOND_GUSHER + - id: OBFUSCATED_2 + displayName: Obfuscated 2 + catchChance: 20 + regions: [ ] + requiredFishingLevel: 0 + requiredBaitId: BRONZE_OBFUSCATED_1 + bronzeItemId: BRONZE_OBFUSCATED_2 + silverItemId: SILVER_OBFUSCATED_2 + goldItemId: GOLD_OBFUSCATED_2 + diamondItemId: DIAMOND_OBFUSCATED_2 + - id: SLUGFISH + displayName: Slugfish + catchChance: 15 + regions: [ ] + requiredFishingLevel: 0 + minimumCastTimeMs: 20000 + bronzeItemId: BRONZE_SLUGFISH + silverItemId: SILVER_SLUGFISH + goldItemId: GOLD_SLUGFISH + diamondItemId: DIAMOND_SLUGFISH + - id: OBFUSCATED_3 + displayName: Obfuscated 3 + catchChance: 10 + regions: [ ] + requiredFishingLevel: 0 + requiredBaitId: BRONZE_OBFUSCATED_2 + bronzeItemId: BRONZE_OBFUSCATED_3 + silverItemId: SILVER_OBFUSCATED_3 + goldItemId: GOLD_OBFUSCATED_3 + diamondItemId: DIAMOND_OBFUSCATED_3 + - id: FLYFISH + displayName: Flyfish + catchChance: 8 + regions: [BLAZING_VOLCANO] + requiredFishingLevel: 0 + minimumBobberDepth: 8 + bronzeItemId: BRONZE_FLYFISH + silverItemId: SILVER_FLYFISH + goldItemId: GOLD_FLYFISH + diamondItemId: DIAMOND_FLYFISH + - id: VANILLE + displayName: Vanille + catchChance: 8 + regions: [ ] + requiredFishingLevel: 0 + requiresStarterRodWithoutEnchantments: true + bronzeItemId: BRONZE_VANILLE + silverItemId: SILVER_VANILLE + goldItemId: GOLD_VANILLE + diamondItemId: DIAMOND_VANILLE + - id: LAVAHORSE + displayName: Lavahorse + catchChance: 4 + regions: [ ] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_LAVAHORSE + silverItemId: SILVER_LAVAHORSE + goldItemId: GOLD_LAVAHORSE + diamondItemId: DIAMOND_LAVAHORSE + - id: MANA_RAY + displayName: Mana Ray + catchChance: 0 + regions: [ ] + requiredFishingLevel: 0 + minimumMana: 1200 + bronzeItemId: BRONZE_MANA_RAY + silverItemId: SILVER_MANA_RAY + goldItemId: GOLD_MANA_RAY + diamondItemId: DIAMOND_MANA_RAY + - id: VOLCANIC_STONEFISH + displayName: Volcanic Stonefish + catchChance: 3 + regions: [BLAZING_VOLCANO] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_VOLCANIC_STONEFISH + silverItemId: SILVER_VOLCANIC_STONEFISH + goldItemId: GOLD_VOLCANIC_STONEFISH + diamondItemId: DIAMOND_VOLCANIC_STONEFISH + - id: SKELETON_FISH + displayName: Skeleton Fish + catchChance: 2 + regions: [BURNING_DESERT] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_SKELETON_FISH + silverItemId: SILVER_SKELETON_FISH + goldItemId: GOLD_SKELETON_FISH + diamondItemId: DIAMOND_SKELETON_FISH + - id: MOLDFIN + displayName: Moldfin + catchChance: 2 + regions: [MYSTIC_MARSH] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_MOLDFIN + silverItemId: SILVER_MOLDFIN + goldItemId: GOLD_MOLDFIN + diamondItemId: DIAMOND_MOLDFIN + - id: SOUL_FISH + displayName: Soul Fish + catchChance: 2 + regions: [STRONGHOLD] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_SOUL_FISH + silverItemId: SILVER_SOUL_FISH + goldItemId: GOLD_SOUL_FISH + diamondItemId: DIAMOND_SOUL_FISH + - id: KARATE_FISH + displayName: Karate Fish + catchChance: 2 + regions: [DOJO] + requiredFishingLevel: 0 + bronzeItemId: BRONZE_KARATE_FISH + silverItemId: SILVER_KARATE_FISH + goldItemId: GOLD_KARATE_FISH + diamondItemId: DIAMOND_KARATE_FISH + - id: GOLDEN_FISH + displayName: Golden Fish + catchChance: 0 + regions: [ ] + requiredFishingLevel: 0 + specialGoldenFish: true + bronzeItemId: BRONZE_GOLDEN_FISH + silverItemId: SILVER_GOLDEN_FISH + goldItemId: GOLD_GOLDEN_FISH + diamondItemId: DIAMOND_GOLDEN_FISH diff --git a/configuration/skyblock/items/fishing/baits.yml b/configuration/skyblock/items/fishing/baits.yml new file mode 100644 index 000000000..cbc70be98 --- /dev/null +++ b/configuration/skyblock/items/fishing/baits.yml @@ -0,0 +1,171 @@ +items: + - id: MINNOW_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 25 + components: + - id: FISHING_BAIT + texture: b8e749ba141c054bb0c125320b17677bdcb3a7e9807a57527c0877b94548a2e + + - id: FISH_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 45 + components: + - id: FISHING_BAIT + texture: 49e8dc9fdc9f00e1d17666a4787d34cca7cc6dc030f0dc686195546f81c6f22 + + - id: LIGHT_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: e3bcc16f402342b4acd29aecac72d1d5a116e0abb478bb4960e734fd70686ba + + - id: DARK_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: 7281618a5c8239078fd43fef8eae14ea00665f635bd56d4451cccd5d0fa11821 + + - id: SPIKED_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + SEA_CREATURE_CHANCE: 6 + components: + - id: FISHING_BAIT + texture: e42c436c6580fad217323b9f045daa23a9f88219ac26506637669eff20901f74 + + - id: SPOOKY_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 25 + components: + - id: FISHING_BAIT + tag_bonuses: + SPOOKY: 15 + texture: 977eab558e6a90f7cedd72c2416c891f47d71eb4e7bdcc299a6335286f5cba98 + + - id: CARROT_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: 4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b + + - id: CORRUPTED_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: 4bbcddd45cd347865bceab3e3dc5d382723463963f85ecce81cdd61b53db14e4 + + - id: BLESSED_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + treasure_quality_bonus: 50 + texture: c2b910b5897cdb86b21ebfcba544afa470ae6d228bee3494427c9c7e8f33502b + + - id: ICE_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + tag_bonuses: + WINTER: 20 + texture: 609e161bdc325c71572a548a79bb15481c924d63e4fb821379d5dd6c8929f39f + + - id: SHARK_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + tag_bonuses: + SHARK: 20 + texture: edff904124efe486b3a54261dbb8072b0a4e11615ad8d7394d814e0e8c8ef9eb + + - id: GLOWY_CHUM_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 25 + SEA_CREATURE_CHANCE: 3 + components: + - id: FISHING_BAIT + texture: dfdc1eed684dd805eae96d132e3da53d64267d7361388d5e2c67f5969871e71d + + - id: HOT_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + trophy_fish_chance_bonus: 5 + texture: 213c6899d97109c6cacbbcdd01e8900abaf46432f197595baa15ad137d5fb9ba + + - id: WORM_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 60 + components: + - id: FISHING_BAIT + texture: df03ad96092f3f789902436709cdf69de6b727c121b3c2daef9ffa1ccaed186c + + - id: FROZEN_BAIT + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_BAIT + tag_bonuses: + WINTER: 35 + texture: 38dc68a97cefe92c8cdaa7cb1a7a4de8f16c161da736edf54f79b74beecd6513 + + - id: GOLDEN_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + treasure_chance_bonus: 4 + texture: 72e2908dbb112dcd0b367df43fafcc41a56d9cf803e90a367834b4911f84f391 + + - id: TREASURE_BAIT + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 10 + components: + - id: FISHING_BAIT + treasure_chance_bonus: 2 + texture: c1695c80854447b5db5a0ee6d57ef0a7d91d815bd7e6318c516a39d12fe0639e + + - id: WOODEN_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + texture: 5b236a39e51a39dff9bced39333a73413984bc74db37c1318bfc4a4459f035d2 + + - id: HOTSPOT_BAIT + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_BAIT + tag_bonuses: + HOTSPOT: 50 + texture: de9b17db5c4cadef737e2fefb42a0123c32cbeaa1ca8932579eb2f05018612cd + + - id: WHALE_BAIT + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 30 + components: + - id: FISHING_BAIT + texture: 5b4fb49ae77cfcf0b8f62df9c69cc96b27096ad2737d6d0aa450b50664fb2303 diff --git a/configuration/skyblock/items/fishing/parts.yml b/configuration/skyblock/items/fishing/parts.yml new file mode 100644 index 000000000..5433e2fb1 --- /dev/null +++ b/configuration/skyblock/items/fishing/parts.yml @@ -0,0 +1,191 @@ +items: + - id: COMMON_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 5 + tag_bonuses: + COMMON: 25 + texture: d235388f091b7fd13397151fca580fdf9a41c2a0a297f887838710f629aa3fd6 + + - id: HOTSPOT_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 20 + tag_bonuses: + HOTSPOT: 100 + texture: 17415df9f4c8cdabdacd442da80826188e46a3d166f56fd1509bba26faac76dd + + - id: PHANTOM_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 21 + tag_bonuses: + SPOOKY: 100 + texture: c95eff1654366d5245238ddbfb65a7a7128468a9ce343861fe239e87c14c3f6d + + - id: TREASURE_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 25 + treasure_only: true + texture: 9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e + + - id: SPEEDY_LINE + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 10 + components: + - id: FISHING_ROD_PART + category: LINE + required_fishing_level: 5 + texture: 5cbac3c84e21e65ec88007604c4eba1da391e185544b90252fc16ca695c59b4b + + - id: SHREDDED_LINE + material: PLAYER_HEAD + rarity: RARE + default_statistics: + DAMAGE: 250 + FEROCITY: 50 + components: + - id: FISHING_ROD_PART + category: LINE + required_fishing_level: 20 + texture: f5424291868be6ae16512641666c5286a740f936e42f96e34987fb6f43d16e6e + + - id: TITAN_LINE + material: PLAYER_HEAD + rarity: RARE + default_statistics: + DOUBLE_HOOK_CHANCE: 2 + components: + - id: FISHING_ROD_PART + category: LINE + required_fishing_level: 35 + texture: 9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9 + + - id: JUNK_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + bayou_treasure_to_junk: true + texture: d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500 + + - id: PRISMARINE_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_item_id: PRISMARINE_SHARD + texture: b9d2d0fe4c93fbc21309e93d985df37e1133d2ece58d2f96b6be5cffba53c181 + + - id: SPONGE_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_item_id: SPONGE + texture: 8b24369807fcf3bd852e6da87ddeca9d38a04f32c78599f4c5823b9522278259 + + - id: CHUM_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_item_id: CHUM + texture: d02b855b4acc508086248ff468aaaaba0c0d8deaa2adc0321ed0809e416736ef + + - id: FESTIVE_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_chance: 0.05 + texture: 6f5840e5b76a2ed0de1c2280ae8be0edd90d83e5f8408af9f1e92f2db92e0383 + + - id: ICY_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + tag_bonuses: + WINTER: 200 + materialized_item_id: ICE + texture: 41dfb1861aa0dd49f7bd8a4ecb14fbda35055fbe9b06b4d7be5cdde0fc7cc60e + + - id: STINGY_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + bait_preservation_chance: 10.0 + texture: e886d5cac32bd32fc07938908c552b7b27965d92065b3157dfc7ef849281ee9d + + - id: HOTSPOT_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 20 + hotspot_buff_multiplier: 2.0 + texture: 88891d33b55dd1572814527b9c027ec724909c26281a197d0309fbfa925cbce4 + + - id: RUSTY_SHIP_ENGINE + material: PLAYER_HEAD + rarity: SPECIAL + components: + - id: FISHING_SHIP_PART + slot: ENGINE + texture: 53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c + + - id: BRONZE_SHIP_ENGINE + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + slot: ENGINE + texture: 9172c1e729e0ca00193ab5d43e893fabedf5a80fc647258176e8502432885925 + + - id: BRONZE_SHIP_HELM + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + slot: HELM + texture: 646c5393c3c57742c992c56a7b7a8b98d267538de947c1096fe76341431008f2 + + - id: BRONZE_SHIP_HULL + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + slot: HULL + texture: a4a7254f1ad8448097d83ddfc790c9f02bc889acbd304b414cee5a13ceadc1e diff --git a/configuration/skyblock/items/fishing/rods.yml b/configuration/skyblock/items/fishing/rods.yml new file mode 100644 index 000000000..0129732bc --- /dev/null +++ b/configuration/skyblock/items/fishing/rods.yml @@ -0,0 +1,292 @@ +items: + - id: CHALLENGE_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 75 + STRENGTH: 75 + FISHING_SPEED: 35 + SEA_CREATURE_CHANCE: 2 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 10 + + - id: CHAMP_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 90 + STRENGTH: 80 + FISHING_SPEED: 90 + SEA_CREATURE_CHANCE: 4 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 15 + + - id: LEGEND_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 130 + STRENGTH: 120 + FISHING_SPEED: 105 + SEA_CREATURE_CHANCE: 6 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 20 + + - id: ROD_OF_THE_SEA + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 150 + STRENGTH: 150 + FISHING_SPEED: 80 + SEA_CREATURE_CHANCE: 8 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 24 + + - id: GIANT_FISHING_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 20 + STRENGTH: 10 + FISHING_SPEED: 20 + DOUBLE_HOOK_CHANCE: 10 + components: + - id: FISHING_ROD_METADATA + medium: WATER + + - id: DIRT_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 20 + components: + - id: FISHING_ROD_METADATA + medium: WATER + rod_parts_enabled: false + + - id: STARTER_LAVA_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 50 + STRENGTH: 50 + FISHING_SPEED: 10 + TROPHY_FISH_CHANCE: 5 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 10 + + - id: POLISHED_TOPAZ_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 100 + STRENGTH: 100 + FISHING_SPEED: 50 + SEA_CREATURE_CHANCE: 2 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 19 + extra_requirements: + - "❣ Requires Heart of the Mountain Tier 5." + + - id: MAGMA_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 150 + STRENGTH: 120 + FISHING_SPEED: 40 + SEA_CREATURE_CHANCE: 6 + TROPHY_FISH_CHANCE: 10 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 27 + + - id: INFERNO_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 210 + STRENGTH: 150 + FISHING_SPEED: 60 + SEA_CREATURE_CHANCE: 10 + TROPHY_FISH_CHANCE: 15 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 30 + + - id: HELLFIRE_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 225 + STRENGTH: 225 + FISHING_SPEED: 60 + SEA_CREATURE_CHANCE: 14 + TROPHY_FISH_CHANCE: 20 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 35 + + - id: CHUM_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 55 + STRENGTH: 40 + FISHING_SPEED: 70 + SEA_CREATURE_CHANCE: 2 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 5 + legacy_conversion_target: CHALLENGE_ROD + + - id: PRISMARINE_ROD + material: FISHING_ROD + rarity: COMMON + default_statistics: + DAMAGE: 15 + STRENGTH: 10 + FISHING_SPEED: 15 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 3 + legacy_conversion_target: CHALLENGE_ROD + + - id: SPONGE_ROD + material: FISHING_ROD + rarity: COMMON + default_statistics: + DAMAGE: 20 + STRENGTH: 15 + FISHING_SPEED: 30 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 5 + legacy_conversion_target: CHALLENGE_ROD + + - id: SPEEDSTER_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 30 + STRENGTH: 15 + FISHING_SPEED: 45 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 6 + legacy_conversion_target: CHALLENGE_ROD + + - id: FARMER_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 50 + STRENGTH: 20 + FISHING_SPEED: 60 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 8 + legacy_conversion_target: CHALLENGE_ROD + + - id: ICE_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 30 + FISHING_SPEED: 15 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 3 + legacy_conversion_target: CHALLENGE_ROD + + - id: WINTER_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 50 + STRENGTH: 50 + FISHING_SPEED: 75 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 10 + legacy_conversion_target: CHALLENGE_ROD + + - id: YETI_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 150 + STRENGTH: 130 + FISHING_SPEED: 75 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 25 + legacy_conversion_target: CHALLENGE_ROD + + - id: THE_SHREDDER + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 120 + FEROCITY: 50 + FISHING_SPEED: 115 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 20 + legacy_conversion_target: CHALLENGE_ROD + + - id: PHANTOM_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 200 + STRENGTH: 125 + FISHING_SPEED: 100 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 21 + legacy_conversion_target: CHALLENGE_ROD + + - id: AUGER_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 135 + STRENGTH: 90 + FISHING_SPEED: 110 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 25 + legacy_conversion_target: ROD_OF_THE_SEA diff --git a/configuration/skyblock/items/fishing/trophy_fish.yml b/configuration/skyblock/items/fishing/trophy_fish.yml new file mode 100644 index 000000000..1ec3e5aa4 --- /dev/null +++ b/configuration/skyblock/items/fishing/trophy_fish.yml @@ -0,0 +1,223 @@ +items: + - id: BRONZE_SULPHUR_SKITTER + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_SULPHUR_SKITTER + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_SULPHUR_SKITTER + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_SULPHUR_SKITTER + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_BLOBFISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_BLOBFISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_BLOBFISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_BLOBFISH + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_OBFUSCATED_1 + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + mediums: [LAVA] + - id: SILVER_OBFUSCATED_1 + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_OBFUSCATED_1 + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_OBFUSCATED_1 + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_STEAMING_HOT_FLOUNDER + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_STEAMING_HOT_FLOUNDER + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_STEAMING_HOT_FLOUNDER + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_STEAMING_HOT_FLOUNDER + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_GUSHER + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_GUSHER + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_GUSHER + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_GUSHER + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_OBFUSCATED_2 + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + mediums: [LAVA] + - id: SILVER_OBFUSCATED_2 + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_OBFUSCATED_2 + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_OBFUSCATED_2 + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_SLUGFISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_SLUGFISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_SLUGFISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_SLUGFISH + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_OBFUSCATED_3 + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_OBFUSCATED_3 + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_OBFUSCATED_3 + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_OBFUSCATED_3 + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_FLYFISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_FLYFISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_FLYFISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_FLYFISH + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_VANILLE + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_VANILLE + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_VANILLE + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_VANILLE + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_LAVAHORSE + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_LAVAHORSE + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_LAVAHORSE + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_LAVAHORSE + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_MANA_RAY + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_MANA_RAY + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_MANA_RAY + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_MANA_RAY + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_VOLCANIC_STONEFISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_VOLCANIC_STONEFISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_VOLCANIC_STONEFISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_VOLCANIC_STONEFISH + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_SKELETON_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_SKELETON_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_SKELETON_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_SKELETON_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_MOLDFIN + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_MOLDFIN + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_MOLDFIN + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_MOLDFIN + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_SOUL_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_SOUL_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_SOUL_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_SOUL_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_KARATE_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_KARATE_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_KARATE_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_KARATE_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: BRONZE_GOLDEN_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: SILVER_GOLDEN_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: GOLD_GOLDEN_FISH + material: PLAYER_HEAD + rarity: COMMON + - id: DIAMOND_GOLDEN_FISH + material: PLAYER_HEAD + rarity: COMMON diff --git a/configuration/skyblock/items/vanillaItems.yml b/configuration/skyblock/items/vanillaItems.yml index 11451d222..d0e55dec2 100644 --- a/configuration/skyblock/items/vanillaItems.yml +++ b/configuration/skyblock/items/vanillaItems.yml @@ -186,6 +186,11 @@ items: material: FISHING_ROD rarity: COMMON components: + - id: FISHING_ROD + - id: FISHING_ROD_METADATA + display_name: Fishing Rod + medium: WATER + rod_parts_enabled: true - id: DEFAULT_CRAFTABLE recipes: - type: SHAPED @@ -926,4 +931,3 @@ items: type: JUKEBOX amount: 1 - diff --git a/configuration/skyblock/slayers.yml b/configuration/skyblock/slayers.yml new file mode 100644 index 000000000..9ba6c7f26 --- /dev/null +++ b/configuration/skyblock/slayers.yml @@ -0,0 +1,113 @@ +slayers: + - id: REVENANT_HORROR + enabled: true + targetMobTypes: [UNDEAD] + levels: + - { level: 1, requiredXp: 5, title: Noob } + - { level: 2, requiredXp: 15, title: Novice } + - { level: 3, requiredXp: 200, title: Skilled } + - { level: 4, requiredXp: 1000, title: Destroyer } + - { level: 5, requiredXp: 5000, title: Bulldozer } + - { level: 6, requiredXp: 20000, title: Savage } + - { level: 7, requiredXp: 100000, title: Deathripper } + - { level: 8, requiredXp: 400000, title: Necromancer } + - { level: 9, requiredXp: 1000000, title: Grim Reaper } + tiers: + - { tier: I, cost: 2000, requiredCombatXp: 150, slayerXp: 5, bossLevel: 1, bossHealth: 500, bossDamage: 15, bossSpeed: 100, tokenItem: REVENANT_FLESH, tokenDrops: 1 } + - { tier: II, cost: 7500, requiredCombatXp: 1440, slayerXp: 25, bossLevel: 2, bossHealth: 20000, bossDamage: 50, bossSpeed: 110, tokenItem: REVENANT_FLESH, tokenDrops: 8 } + - { tier: III, cost: 20000, requiredCombatXp: 2400, slayerXp: 100, bossLevel: 3, bossHealth: 400000, bossDamage: 120, bossSpeed: 120, tokenItem: REVENANT_FLESH, tokenDrops: 32 } + - { tier: IV, cost: 50000, requiredCombatXp: 4800, slayerXp: 500, bossLevel: 4, bossHealth: 1500000, bossDamage: 400, bossSpeed: 130, tokenItem: REVENANT_FLESH, tokenDrops: 64 } + - { tier: V, cost: 100000, requiredCombatXp: 6000, slayerXp: 1500, bossLevel: 5, bossHealth: 10000000, bossDamage: 2400, bossSpeed: 135, tokenItem: REVENANT_FLESH, tokenDrops: 128 } + + - id: TARANTULA_BROODFATHER + enabled: true + unlock: { type: REVENANT_HORROR, tier: II } + targetMobTypes: [ARTHROPOD] + levels: + - { level: 1, requiredXp: 5, title: Noob } + - { level: 2, requiredXp: 25, title: Novice } + - { level: 3, requiredXp: 200, title: Skilled } + - { level: 4, requiredXp: 1000, title: Destroyer } + - { level: 5, requiredXp: 5000, title: Bulldozer } + - { level: 6, requiredXp: 20000, title: Savage } + - { level: 7, requiredXp: 100000, title: Pest Control Genius } + - { level: 8, requiredXp: 400000, title: Tarantula Exterminator } + - { level: 9, requiredXp: 1000000, title: Spider Annihilator } + tiers: + - { tier: I, cost: 2000, requiredCombatXp: 225, slayerXp: 5, bossLevel: 1, bossHealth: 750, bossDamage: 35, bossSpeed: 120, tokenItem: TARANTULA_WEB, tokenDrops: 1 } + - { tier: II, cost: 7500, requiredCombatXp: 540, slayerXp: 25, bossLevel: 2, bossHealth: 30000, bossDamage: 110, bossSpeed: 125, tokenItem: TARANTULA_WEB, tokenDrops: 8 } + - { tier: III, cost: 20000, requiredCombatXp: 1320, slayerXp: 100, bossLevel: 3, bossHealth: 900000, bossDamage: 525, bossSpeed: 135, tokenItem: TARANTULA_WEB, tokenDrops: 32 } + - { tier: IV, cost: 50000, requiredCombatXp: 2000, slayerXp: 500, bossLevel: 4, bossHealth: 2400000, bossDamage: 1325, bossSpeed: 145, tokenItem: TARANTULA_WEB, tokenDrops: 64 } + - { tier: V, cost: 100000, requiredCombatXp: 10000, slayerXp: 1500, bossLevel: 5, bossHealth: 10000000, bossDamage: 3500, bossSpeed: 150, tokenItem: TARANTULA_WEB, tokenDrops: 128 } + + - id: SVEN_PACKMASTER + enabled: true + unlock: { type: TARANTULA_BROODFATHER, tier: II } + targetMobTypes: [WOODLAND] + levels: + - { level: 1, requiredXp: 10, title: Noob } + - { level: 2, requiredXp: 30, title: Novice } + - { level: 3, requiredXp: 250, title: Skilled } + - { level: 4, requiredXp: 1500, title: Destroyer } + - { level: 5, requiredXp: 5000, title: Bulldozer } + - { level: 6, requiredXp: 20000, title: Savage } + - { level: 7, requiredXp: 100000, title: King Hunter } + - { level: 8, requiredXp: 400000, title: Pack Leader } + - { level: 9, requiredXp: 1000000, title: Alpha Wolf } + tiers: + - { tier: I, cost: 2000, requiredCombatXp: 270, slayerXp: 5, bossLevel: 1, bossHealth: 2000, bossDamage: 60, bossSpeed: 130, tokenItem: WOLF_TOOTH, tokenDrops: 1 } + - { tier: II, cost: 7500, requiredCombatXp: 648, slayerXp: 25, bossLevel: 2, bossHealth: 40000, bossDamage: 200, bossSpeed: 135, tokenItem: WOLF_TOOTH, tokenDrops: 4 } + - { tier: III, cost: 20000, requiredCombatXp: 1584, slayerXp: 100, bossLevel: 3, bossHealth: 750000, bossDamage: 450, bossSpeed: 145, tokenItem: WOLF_TOOTH, tokenDrops: 16 } + - { tier: IV, cost: 50000, requiredCombatXp: 3168, slayerXp: 500, bossLevel: 4, bossHealth: 2000000, bossDamage: 1100, bossSpeed: 155, tokenItem: WOLF_TOOTH, tokenDrops: 64 } + + - id: VOIDGLOOM_SERAPH + enabled: true + unlock: { type: SVEN_PACKMASTER, tier: IV } + targetMobTypes: [ENDER] + levels: + - { level: 1, requiredXp: 10, title: Noob } + - { level: 2, requiredXp: 30, title: Novice } + - { level: 3, requiredXp: 250, title: Skilled } + - { level: 4, requiredXp: 1500, title: Destroyer } + - { level: 5, requiredXp: 5000, title: Bulldozer } + - { level: 6, requiredXp: 20000, title: Savage } + - { level: 7, requiredXp: 100000, title: Voidwracker } + - { level: 8, requiredXp: 400000, title: Tall Purple Hater } + - { level: 9, requiredXp: 1000000, title: Definition of End } + tiers: + - { tier: I, cost: 2000, requiredCombatXp: 2750, slayerXp: 5, bossLevel: 1, bossHealth: 300000, bossDamage: 1200, bossSpeed: 140, tokenItem: NULL_SPHERE, tokenDrops: 1 } + - { tier: II, cost: 7500, requiredCombatXp: 6600, slayerXp: 25, bossLevel: 2, bossHealth: 15000000, bossDamage: 5000, bossSpeed: 145, tokenItem: NULL_SPHERE, tokenDrops: 2 } + - { tier: III, cost: 20000, requiredCombatXp: 11000, slayerXp: 100, bossLevel: 3, bossHealth: 66000000, bossDamage: 12000, bossSpeed: 150, tokenItem: NULL_SPHERE, tokenDrops: 3 } + - { tier: IV, cost: 50000, requiredCombatXp: 22000, slayerXp: 500, bossLevel: 4, bossHealth: 300000000, bossDamage: 21000, bossSpeed: 160, tokenItem: NULL_SPHERE, tokenDrops: 4 } + + - id: RIFTSTALKER_BLOODFIEND + enabled: false + unlock: { type: SVEN_PACKMASTER, tier: II } + targetMobTypes: [UNDEAD] + levels: + - { level: 1, requiredXp: 20, title: Noob } + - { level: 2, requiredXp: 75, title: Novice } + - { level: 3, requiredXp: 240, title: Alum } + - { level: 4, requiredXp: 840, title: Heartpiercer } + - { level: 5, requiredXp: 2400, title: Lord of Night } + tiers: [] + + - id: INFERNO_DEMONLORD + enabled: true + unlock: { type: VOIDGLOOM_SERAPH, tier: III } + targetMobTypes: [INFERNAL, MAGMATIC] + levels: + - { level: 1, requiredXp: 10, title: Noob } + - { level: 2, requiredXp: 30, title: Novice } + - { level: 3, requiredXp: 250, title: Skilled } + - { level: 4, requiredXp: 1500, title: Destroyer } + - { level: 5, requiredXp: 5000, title: Bulldozer } + - { level: 6, requiredXp: 20000, title: Savage } + - { level: 7, requiredXp: 100000, title: Hellsplitter } + - { level: 8, requiredXp: 400000, title: Demon Eater } + - { level: 9, requiredXp: 1000000, title: Gabagool King } + tiers: + - { tier: I, cost: 10000, requiredCombatXp: 6000, slayerXp: 5, bossLevel: 1, bossHealth: 2500000, bossDamage: 1500, bossSpeed: 130, tokenItem: DERELICT_ASHE, tokenDrops: 1 } + - { tier: II, cost: 25000, requiredCombatXp: 14400, slayerXp: 25, bossLevel: 2, bossHealth: 12000000, bossDamage: 3600, bossSpeed: 135, tokenItem: DERELICT_ASHE, tokenDrops: 2 } + - { tier: III, cost: 60000, requiredCombatXp: 18000, slayerXp: 100, bossLevel: 3, bossHealth: 60000000, bossDamage: 7200, bossSpeed: 145, tokenItem: DERELICT_ASHE, tokenDrops: 3 } + - { tier: IV, cost: 150000, requiredCombatXp: 36000, slayerXp: 500, bossLevel: 4, bossHealth: 150000000, bossDamage: 15000, bossSpeed: 150, tokenItem: DERELICT_ASHE, tokenDrops: 4 } diff --git a/dungeons/src/main/java/net/swofty/dungeons/DungeonRoomType.java b/dungeons/src/main/java/net/swofty/dungeons/DungeonRoomType.java index 1a0b8afe1..075d4a3b8 100644 --- a/dungeons/src/main/java/net/swofty/dungeons/DungeonRoomType.java +++ b/dungeons/src/main/java/net/swofty/dungeons/DungeonRoomType.java @@ -9,6 +9,8 @@ public enum DungeonRoomType { FAIRY(true, false), PUZZLE(true), MINI_BOSS(true), + TRAP(), + BLOOD(), EXIT(), ; diff --git a/dungeons/src/main/java/net/swofty/dungeons/DungeonUtilities.java b/dungeons/src/main/java/net/swofty/dungeons/DungeonUtilities.java index 32021af2f..fdda17b26 100644 --- a/dungeons/src/main/java/net/swofty/dungeons/DungeonUtilities.java +++ b/dungeons/src/main/java/net/swofty/dungeons/DungeonUtilities.java @@ -1,9 +1,14 @@ package net.swofty.dungeons; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import java.util.*; import java.util.stream.Stream; -public class DungeonUtilities { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class DungeonUtilities { + public static Stream> loopOverDungeonRooms(DungeonsData data) { return Stream.iterate(0, i -> i < data.getWidth() * data.getHeight(), i -> i + 1) .map(i -> Map.entry(i % data.getWidth(), i / data.getHeight())); diff --git a/dungeons/src/main/java/net/swofty/dungeons/SkyBlockDungeon.java b/dungeons/src/main/java/net/swofty/dungeons/SkyBlockDungeon.java index e959d36e3..e5b84ae01 100644 --- a/dungeons/src/main/java/net/swofty/dungeons/SkyBlockDungeon.java +++ b/dungeons/src/main/java/net/swofty/dungeons/SkyBlockDungeon.java @@ -22,6 +22,14 @@ public DungeonRoom getRoom(int x, int y) { return rooms.get(Map.entry(x, y)); } + public Map, DungeonRoom> getRooms() { + return Map.copyOf(rooms); + } + + public List getDoorConnections() { + return List.copyOf(doors); + } + public boolean isConnected(int x1, int y1, int x2, int y2) { return doors.stream().anyMatch(door -> (door.x1() == x1 && door.y1() == y1 && door.x2() == x2 && door.y2() == y2) || (door.x1() == x2 && door.y1() == y2 && door.x2() == x1 && door.y2() == y1)); } diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsAPI.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsAPI.java new file mode 100644 index 000000000..638445115 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsAPI.java @@ -0,0 +1,95 @@ +package net.swofty.dungeons.catacombs; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.swofty.dungeons.GeneratorService; +import net.swofty.dungeons.SkyBlockDungeon; +import net.swofty.dungeons.catacombs.classes.DungeonClassDefinition; +import net.swofty.dungeons.catacombs.classes.DungeonClassRegistry; +import net.swofty.dungeons.catacombs.classes.DungeonClassType; +import net.swofty.dungeons.catacombs.generation.CatacombsGenerator; +import net.swofty.dungeons.catacombs.instance.CatacombsInstanceService; +import net.swofty.dungeons.catacombs.item.DungeonOrbProfile; +import net.swofty.dungeons.catacombs.kit.DungeonClassKit; +import net.swofty.dungeons.catacombs.kit.DungeonKitRegistry; +import net.swofty.dungeons.catacombs.map.DungeonMapRenderResult; +import net.swofty.dungeons.catacombs.map.DungeonMapRenderer; +import net.swofty.dungeons.catacombs.mob.DungeonMobDefinition; +import net.swofty.dungeons.catacombs.mob.DungeonMobRegistry; +import net.swofty.dungeons.catacombs.mob.DungeonMobRole; +import net.swofty.dungeons.catacombs.party.PartyFinderService; +import net.swofty.dungeons.catacombs.puzzle.CatacombsPuzzle; +import net.swofty.dungeons.catacombs.puzzle.CatacombsPuzzleFactory; +import net.swofty.dungeons.catacombs.puzzle.PuzzleController; +import net.swofty.dungeons.catacombs.run.CatacombsRunConfig; +import net.swofty.dungeons.catacombs.run.CatacombsRunState; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class CatacombsAPI { + private static final DungeonClassRegistry CLASS_REGISTRY = DungeonClassRegistry.defaults(); + private static final CatacombsRegistry CATACOMBS_REGISTRY = CatacombsRegistry.defaults(); + private static final DungeonMobRegistry MOB_REGISTRY = DungeonMobRegistry.defaults(); + private static final DungeonKitRegistry KIT_REGISTRY = DungeonKitRegistry.defaults(); + private static final DungeonMapRenderer MAP_RENDERER = new DungeonMapRenderer(); + + public static CatacombsFloorDefinition floor(CatacombsFloor floor, CatacombsMode mode) { + return CATACOMBS_REGISTRY.floor(floor, mode); + } + + public static DungeonClassDefinition dungeonClass(DungeonClassType type) { + return CLASS_REGISTRY.definition(type); + } + + public static Map classes() { + return CLASS_REGISTRY.definitions(); + } + + public static DungeonOrbProfile dungeonOrb(DungeonClassType type) { + return DungeonOrbProfile.forClass(dungeonClass(type)); + } + + public static List kits(DungeonClassType type) { + return KIT_REGISTRY.kits(type); + } + + public static DungeonClassKit kit(String id) { + return KIT_REGISTRY.kit(id); + } + + public static PartyFinderService partyFinder() { + return new PartyFinderService(); + } + + public static CatacombsInstanceService instances() { + return new CatacombsInstanceService(); + } + + public static List mobs(CatacombsFloor floor, DungeonMobRole role) { + return MOB_REGISTRY.spawnable(floor, role); + } + + public static DungeonMobDefinition mob(String id) { + return MOB_REGISTRY.mob(id); + } + + public static PuzzleController puzzle(CatacombsPuzzle puzzle) { + return CatacombsPuzzleFactory.create(puzzle); + } + + public static GeneratorService generator(CatacombsFloorDefinition definition) { + return CatacombsGenerator.generator(definition); + } + + public static DungeonMapRenderResult renderMap(SkyBlockDungeon dungeon, Path outputPath) throws IOException { + return MAP_RENDERER.renderPng(dungeon, outputPath); + } + + public static CatacombsRunState startRun(CatacombsRunConfig config) { + return CatacombsRunState.start(config); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsDungeonSize.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsDungeonSize.java new file mode 100644 index 000000000..723e59218 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsDungeonSize.java @@ -0,0 +1,25 @@ +package net.swofty.dungeons.catacombs; + +public enum CatacombsDungeonSize { + TINY(4, 4), + SMALL(5, 5), + MEDIUM_TALL(5, 6), + MEDIUM(6, 6), + LARGE(6, 6); + + private final int width; + private final int height; + + CatacombsDungeonSize(int width, int height) { + this.width = width; + this.height = height; + } + + public int width() { + return width; + } + + public int height() { + return height; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsFloor.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsFloor.java new file mode 100644 index 000000000..02509a07f --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsFloor.java @@ -0,0 +1,67 @@ +package net.swofty.dungeons.catacombs; + +import java.util.Arrays; + +public enum CatacombsFloor { + ENTRANCE("Entrance", "The Watcher", CatacombsDungeonSize.TINY, 0, -1), + FLOOR_ONE("Floor I", "Bonzo", CatacombsDungeonSize.TINY, 1, 24), + FLOOR_TWO("Floor II", "Scarf", CatacombsDungeonSize.SMALL, 3, 26), + FLOOR_THREE("Floor III", "The Professor", CatacombsDungeonSize.SMALL, 5, 28), + FLOOR_FOUR("Floor IV", "Thorn", CatacombsDungeonSize.SMALL, 9, 30), + FLOOR_FIVE("Floor V", "Livid", CatacombsDungeonSize.MEDIUM_TALL, 14, 32), + FLOOR_SIX("Floor VI", "Sadan", CatacombsDungeonSize.MEDIUM, 19, 34), + FLOOR_SEVEN("Floor VII", "The Wither Lords", CatacombsDungeonSize.LARGE, 24, 36); + + private final String displayName; + private final String bossName; + private final CatacombsDungeonSize dungeonSize; + private final int normalRequirement; + private final int masterRequirement; + + CatacombsFloor(String displayName, String bossName, CatacombsDungeonSize dungeonSize, + int normalRequirement, int masterRequirement) { + this.displayName = displayName; + this.bossName = bossName; + this.dungeonSize = dungeonSize; + this.normalRequirement = normalRequirement; + this.masterRequirement = masterRequirement; + } + + public String displayName() { + return displayName; + } + + public String bossName() { + return bossName; + } + + public CatacombsDungeonSize dungeonSize() { + return dungeonSize; + } + + public int normalRequirement() { + return normalRequirement; + } + + public int masterRequirement() { + return masterRequirement; + } + + public boolean supports(CatacombsMode mode) { + return mode == CatacombsMode.NORMAL || masterRequirement >= 0; + } + + public int requirement(CatacombsMode mode) { + if (mode == CatacombsMode.MASTER && masterRequirement < 0) { + throw new IllegalArgumentException(displayName + " does not support Master Mode"); + } + return mode == CatacombsMode.MASTER ? masterRequirement : normalRequirement; + } + + public static CatacombsFloor byNumber(int floor) { + return Arrays.stream(values()) + .filter(value -> value.ordinal() == floor) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unknown Catacombs floor " + floor)); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsFloorDefinition.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsFloorDefinition.java new file mode 100644 index 000000000..3557bde03 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsFloorDefinition.java @@ -0,0 +1,25 @@ +package net.swofty.dungeons.catacombs; + +import net.swofty.dungeons.catacombs.boss.CatacombsBossEncounter; +import net.swofty.dungeons.catacombs.puzzle.CatacombsPuzzle; +import net.swofty.dungeons.catacombs.run.DungeonRunRules; + +import java.util.Set; + +public record CatacombsFloorDefinition( + CatacombsFloor floor, + CatacombsMode mode, + CatacombsBossEncounter boss, + DungeonRunRules rules, + int puzzleRooms, + int minibossRooms, + int trapRooms, + Set possiblePuzzles +) { + public CatacombsFloorDefinition { + possiblePuzzles = Set.copyOf(possiblePuzzles); + if (!floor.supports(mode)) { + throw new IllegalArgumentException(floor.displayName() + " does not support " + mode); + } + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsMode.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsMode.java new file mode 100644 index 000000000..0f46b8ed3 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsMode.java @@ -0,0 +1,6 @@ +package net.swofty.dungeons.catacombs; + +public enum CatacombsMode { + NORMAL, + MASTER +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsRegistry.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsRegistry.java new file mode 100644 index 000000000..6ae8a530c --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsRegistry.java @@ -0,0 +1,94 @@ +package net.swofty.dungeons.catacombs; + +import net.swofty.dungeons.catacombs.boss.CatacombsBosses; +import net.swofty.dungeons.catacombs.puzzle.CatacombsPuzzle; +import net.swofty.dungeons.catacombs.run.DungeonRunRules; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public record CatacombsRegistry(Map> floors) { + public CatacombsRegistry { + floors = Map.copyOf(floors); + } + + public CatacombsFloorDefinition floor(CatacombsFloor floor, CatacombsMode mode) { + Map byFloor = floors.get(mode); + if (byFloor == null || !byFloor.containsKey(floor)) { + throw new IllegalArgumentException("No Catacombs definition for " + mode + " " + floor.displayName()); + } + return byFloor.get(floor); + } + + public static CatacombsRegistry defaults() { + Map> floors = new EnumMap<>(CatacombsMode.class); + floors.put(CatacombsMode.NORMAL, normalFloors()); + floors.put(CatacombsMode.MASTER, masterFloors()); + return new CatacombsRegistry(floors); + } + + private static Map normalFloors() { + Map floors = new EnumMap<>(CatacombsFloor.class); + floors.put(CatacombsFloor.ENTRANCE, definition(CatacombsFloor.ENTRANCE, CatacombsMode.NORMAL, + CatacombsBosses.watcher(), 1, 0, 0, 600, true)); + floors.put(CatacombsFloor.FLOOR_ONE, definition(CatacombsFloor.FLOOR_ONE, CatacombsMode.NORMAL, + CatacombsBosses.bonzo(), 2, 1, 0, 600, true)); + floors.put(CatacombsFloor.FLOOR_TWO, definition(CatacombsFloor.FLOOR_TWO, CatacombsMode.NORMAL, + CatacombsBosses.scarf(), 2, 1, 0, 600, true)); + floors.put(CatacombsFloor.FLOOR_THREE, definition(CatacombsFloor.FLOOR_THREE, CatacombsMode.NORMAL, + CatacombsBosses.professor(), 2, 1, 1, 600, false)); + floors.put(CatacombsFloor.FLOOR_FOUR, definition(CatacombsFloor.FLOOR_FOUR, CatacombsMode.NORMAL, + CatacombsBosses.thorn(), 2, 1, 1, 720, false)); + floors.put(CatacombsFloor.FLOOR_FIVE, definition(CatacombsFloor.FLOOR_FIVE, CatacombsMode.NORMAL, + CatacombsBosses.livid(), 3, 2, 1, 720, false)); + floors.put(CatacombsFloor.FLOOR_SIX, definition(CatacombsFloor.FLOOR_SIX, CatacombsMode.NORMAL, + CatacombsBosses.sadan(), 3, 2, 1, 840, false)); + floors.put(CatacombsFloor.FLOOR_SEVEN, definition(CatacombsFloor.FLOOR_SEVEN, CatacombsMode.NORMAL, + CatacombsBosses.witherLords(false), 3, 2, 1, 840, false)); + return floors; + } + + private static Map masterFloors() { + Map floors = new EnumMap<>(CatacombsFloor.class); + floors.put(CatacombsFloor.FLOOR_ONE, master(CatacombsFloor.FLOOR_ONE, CatacombsBosses.bonzo(), 2, 1, 0, 540)); + floors.put(CatacombsFloor.FLOOR_TWO, master(CatacombsFloor.FLOOR_TWO, CatacombsBosses.scarf(), 2, 1, 0, 540)); + floors.put(CatacombsFloor.FLOOR_THREE, master(CatacombsFloor.FLOOR_THREE, CatacombsBosses.professor(), 2, 1, 1, 540)); + floors.put(CatacombsFloor.FLOOR_FOUR, master(CatacombsFloor.FLOOR_FOUR, CatacombsBosses.thorn(), 2, 1, 1, 660)); + floors.put(CatacombsFloor.FLOOR_FIVE, master(CatacombsFloor.FLOOR_FIVE, CatacombsBosses.livid(), 3, 2, 1, 660)); + floors.put(CatacombsFloor.FLOOR_SIX, master(CatacombsFloor.FLOOR_SIX, CatacombsBosses.sadan(), 3, 2, 1, 780)); + floors.put(CatacombsFloor.FLOOR_SEVEN, master(CatacombsFloor.FLOOR_SEVEN, CatacombsBosses.witherLords(true), 3, 2, 1, 780)); + return floors; + } + + private static CatacombsFloorDefinition master(CatacombsFloor floor, + net.swofty.dungeons.catacombs.boss.CatacombsBossEncounter boss, + int puzzleRooms, int minibossRooms, int trapRooms, + int speedScoreSeconds) { + return definition(floor, CatacombsMode.MASTER, boss, puzzleRooms, minibossRooms, trapRooms, + speedScoreSeconds, false); + } + + private static CatacombsFloorDefinition definition(CatacombsFloor floor, CatacombsMode mode, + net.swofty.dungeons.catacombs.boss.CatacombsBossEncounter boss, + int puzzleRooms, int minibossRooms, int trapRooms, + int speedScoreSeconds, boolean automaticGhostRevive) { + return new CatacombsFloorDefinition( + floor, + mode, + boss, + new DungeonRunRules(speedScoreSeconds, 4200, 2, 5, 17, automaticGhostRevive, trapRooms > 0), + puzzleRooms, + minibossRooms, + trapRooms, + puzzlesFor(floor)); + } + + private static Set puzzlesFor(CatacombsFloor floor) { + return Arrays.stream(CatacombsPuzzle.values()) + .filter(puzzle -> puzzle.canGenerate(floor)) + .collect(Collectors.toUnmodifiableSet()); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingEffect.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingEffect.java new file mode 100644 index 000000000..4f1712b12 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingEffect.java @@ -0,0 +1,11 @@ +package net.swofty.dungeons.catacombs.blessing; + +public record BlessingEffect(BlessingStat stat, double percentPerLevel, double flatPerLevel) { + public double percent(int level) { + return percentPerLevel * level; + } + + public double flat(int level) { + return flatPerLevel * level; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingSet.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingSet.java new file mode 100644 index 000000000..884803728 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingSet.java @@ -0,0 +1,33 @@ +package net.swofty.dungeons.catacombs.blessing; + +import java.util.EnumMap; +import java.util.Map; + +public final class BlessingSet { + private final Map levels = new EnumMap<>(BlessingType.class); + + public void add(BlessingType type, int level) { + levels.merge(type, level, Integer::sum); + } + + public int level(BlessingType type) { + return levels.getOrDefault(type, 0); + } + + public Map levels() { + return Map.copyOf(levels); + } + + public Map appliedStats(double effectivenessMultiplier) { + Map applied = new EnumMap<>(BlessingStat.class); + levels.forEach((type, level) -> type.effects().forEach(effect -> { + AppliedBlessingStat current = applied.getOrDefault(effect.stat(), new AppliedBlessingStat(0, 0)); + applied.put(effect.stat(), new AppliedBlessingStat( + current.percent() + effect.percent(level) * effectivenessMultiplier, + current.flat() + effect.flat(level) * effectivenessMultiplier)); + })); + return Map.copyOf(applied); + } + + public record AppliedBlessingStat(double percent, double flat) {} +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingStat.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingStat.java new file mode 100644 index 000000000..d5d7be259 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingStat.java @@ -0,0 +1,12 @@ +package net.swofty.dungeons.catacombs.blessing; + +public enum BlessingStat { + HEALTH, + HEALTH_REGEN, + STRENGTH, + CRIT_DAMAGE, + DEFENSE, + DAMAGE, + INTELLIGENCE, + SPEED +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingType.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingType.java new file mode 100644 index 000000000..709423d1d --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/blessing/BlessingType.java @@ -0,0 +1,39 @@ +package net.swofty.dungeons.catacombs.blessing; + +import java.util.List; + +public enum BlessingType { + LIFE("Blessing of Life", List.of( + new BlessingEffect(BlessingStat.HEALTH, 3, 0), + new BlessingEffect(BlessingStat.HEALTH_REGEN, 3, 0))), + POWER("Blessing of Power", List.of( + new BlessingEffect(BlessingStat.STRENGTH, 2, 4), + new BlessingEffect(BlessingStat.CRIT_DAMAGE, 2, 4))), + STONE("Blessing of Stone", List.of( + new BlessingEffect(BlessingStat.DEFENSE, 2, 4), + new BlessingEffect(BlessingStat.DAMAGE, 0, 6))), + WISDOM("Blessing of Wisdom", List.of( + new BlessingEffect(BlessingStat.INTELLIGENCE, 2, 4), + new BlessingEffect(BlessingStat.SPEED, 0, 0))), + TIME("Blessing of Time", List.of( + new BlessingEffect(BlessingStat.HEALTH, 2, 4), + new BlessingEffect(BlessingStat.INTELLIGENCE, 2, 4), + new BlessingEffect(BlessingStat.STRENGTH, 2, 4), + new BlessingEffect(BlessingStat.DEFENSE, 2, 4))); + + private final String displayName; + private final List effects; + + BlessingType(String displayName, List effects) { + this.displayName = displayName; + this.effects = effects; + } + + public String displayName() { + return displayName; + } + + public List effects() { + return effects; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/BossPhaseTrigger.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/BossPhaseTrigger.java new file mode 100644 index 000000000..0ac144b20 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/BossPhaseTrigger.java @@ -0,0 +1,10 @@ +package net.swofty.dungeons.catacombs.boss; + +public enum BossPhaseTrigger { + ENTER_BOSS_ROOM, + BOSS_HEALTH_THRESHOLD, + ADDS_DEFEATED, + PLAYER_OBJECTIVE, + TIMER, + PHASE_COMPLETE +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBossEncounter.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBossEncounter.java new file mode 100644 index 000000000..a8e978d7b --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBossEncounter.java @@ -0,0 +1,14 @@ +package net.swofty.dungeons.catacombs.boss; + +import java.util.List; + +public record CatacombsBossEncounter( + String id, + String displayName, + String status, + List phases +) { + public CatacombsBossEncounter { + phases = List.copyOf(phases); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBossPhase.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBossPhase.java new file mode 100644 index 000000000..5df2ae808 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBossPhase.java @@ -0,0 +1,15 @@ +package net.swofty.dungeons.catacombs.boss; + +import java.util.Set; + +public record CatacombsBossPhase( + String id, + String displayName, + BossPhaseTrigger trigger, + int triggerValue, + Set mechanics +) { + public CatacombsBossPhase { + mechanics = Set.copyOf(mechanics); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBosses.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBosses.java new file mode 100644 index 000000000..2a27f23e6 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/CatacombsBosses.java @@ -0,0 +1,117 @@ +package net.swofty.dungeons.catacombs.boss; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class CatacombsBosses { + public static CatacombsBossEncounter watcher() { + return encounter("WATCHER", "The Watcher", "Stalker", + phase("WATCHER_SUMMONS", "Undead Collection", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Summons waves of undead enemies", + "Opens the blood portal once every summoned enemy is defeated")); + } + + public static CatacombsBossEncounter bonzo() { + return encounter("BONZO", "Bonzo", "New Necromancer", + phase("BONZO_SHOWTIME", "Showtime", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Throws balloons", + "Summons undead performers"), + phase("BONZO_UNDEAD", "Undead Finale", BossPhaseTrigger.BOSS_HEALTH_THRESHOLD, 0, + "Revives after the first defeat", + "Uses stronger balloon barrages")); + } + + public static CatacombsBossEncounter scarf() { + return encounter("SCARF", "Scarf", "Apprentice Necromancer", + phase("SCARF_STUDENTS", "Undead Students", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Warrior, Priest, Mage, Archer, and Scarf must be fought as a group"), + phase("SCARF_REVIVE", "Second Lesson", BossPhaseTrigger.ADDS_DEFEATED, 0, + "Revives defeated students", + "Ends when Scarf is defeated after the revive")); + } + + public static CatacombsBossEncounter professor() { + return encounter("PROFESSOR", "The Professor", "Professor", + phase("PROFESSOR_GUARDIANS", "Guardian Experiment", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Four guardians protect the professor", + "Guardians must be defeated close together"), + phase("PROFESSOR_GIANT", "Frenzy", BossPhaseTrigger.ADDS_DEFEATED, 0, + "Professor enters a giant guardian body", + "Arena floods during the final phase")); + } + + public static CatacombsBossEncounter thorn() { + return encounter("THORN", "Thorn", "Shaman Necromancer", + phase("THORN_SPIRITS", "Spirit Animals", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Animal waves fill the arena", + "Spirit Bears drop Spirit Bows"), + phase("THORN_SHOT", "Spirit Shot", BossPhaseTrigger.PLAYER_OBJECTIVE, 4, + "Players damage Thorn by shooting him with Spirit Bow charges")); + } + + public static CatacombsBossEncounter livid() { + return encounter("LIVID", "Livid", "Master Necromancer", + phase("LIVID_CLONES", "Clone Ambush", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Multiple Livid clones spawn", + "Only the correct Livid must be killed to finish the fight")); + } + + public static CatacombsBossEncounter sadan() { + return encounter("SADAN", "Sadan", "Necromancer Lord", + phase("SADAN_TERRACOTTAS", "Terracotta Army", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Survive the terracotta army"), + phase("SADAN_GIANTS", "Giant Reanimation", BossPhaseTrigger.TIMER, 0, + "Ancient Giants awaken one by one"), + phase("SADAN_FINAL", "Necromancer Lord", BossPhaseTrigger.ADDS_DEFEATED, 0, + "Sadan enters the arena after the giants fall")); + } + + public static CatacombsBossEncounter witherLords(boolean masterMode) { + CatacombsBossEncounter encounter = encounter("WITHER_LORDS", "The Wither Lords", "The Wither Lords", + phase("MAXOR", "Maxor", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Complete crystal objectives", + "Damage Maxor after he is stunned"), + phase("STORM", "Storm", BossPhaseTrigger.PHASE_COMPLETE, 0, + "Shelter from lightning", + "Use crusher objectives to expose Storm"), + phase("GOLDOR", "Goldor", BossPhaseTrigger.PHASE_COMPLETE, 0, + "Advance through terminal sections", + "Complete devices while Goldor approaches"), + phase("NECRON", "Necron", BossPhaseTrigger.PHASE_COMPLETE, 0, + "Final arena against Necron", + "Defeat Necron to complete normal Floor VII")); + + if (!masterMode) { + return encounter; + } + + return encounter("MASTER_WITHER_LORDS", "The Wither Lords", "The Wither Lords", + phase("MAXOR", "Maxor", BossPhaseTrigger.ENTER_BOSS_ROOM, 0, + "Complete crystal objectives", + "Damage Maxor after he is stunned"), + phase("STORM", "Storm", BossPhaseTrigger.PHASE_COMPLETE, 0, + "Shelter from lightning", + "Use crusher objectives to expose Storm"), + phase("GOLDOR", "Goldor", BossPhaseTrigger.PHASE_COMPLETE, 0, + "Advance through terminal sections", + "Complete devices while Goldor approaches"), + phase("NECRON", "Necron", BossPhaseTrigger.PHASE_COMPLETE, 0, + "Final arena against Necron"), + phase("WITHER_KING", "Wither King", BossPhaseTrigger.PHASE_COMPLETE, 0, + "Master Mode adds the Wither King after Necron")); + } + + private static CatacombsBossEncounter encounter(String id, String displayName, String status, + CatacombsBossPhase... phases) { + return new CatacombsBossEncounter(id, displayName, status, List.of(phases)); + } + + private static CatacombsBossPhase phase(String id, String displayName, BossPhaseTrigger trigger, + int triggerValue, String... mechanics) { + return new CatacombsBossPhase(id, displayName, trigger, triggerValue, Set.of(mechanics)); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightController.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightController.java new file mode 100644 index 000000000..83788fa12 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightController.java @@ -0,0 +1,95 @@ +package net.swofty.dungeons.catacombs.boss.state; + +import net.swofty.dungeons.catacombs.boss.BossPhaseTrigger; +import net.swofty.dungeons.catacombs.boss.CatacombsBossEncounter; +import net.swofty.dungeons.catacombs.boss.CatacombsBossPhase; + +import java.util.ArrayList; +import java.util.List; + +public final class BossFightController { + private final CatacombsBossEncounter encounter; + private final List traces = new ArrayList<>(); + private BossFightState state = BossFightState.NOT_STARTED; + private int phaseIndex; + private int objectiveProgress; + + public BossFightController(CatacombsBossEncounter encounter) { + this.encounter = encounter; + } + + public CatacombsBossEncounter encounter() { + return encounter; + } + + public BossFightState state() { + return state; + } + + public CatacombsBossPhase currentPhase() { + return encounter.phases().get(Math.min(phaseIndex, encounter.phases().size() - 1)); + } + + public List traces() { + return List.copyOf(traces); + } + + public void start() { + state = BossFightState.ACTIVE; + traces.add(BossFightTrace.of(currentPhase().id(), BossFightEvent.START, currentPhase().displayName())); + } + + public void accept(BossFightEvent event, int value) { + if (state == BossFightState.COMPLETED || state == BossFightState.FAILED) { + return; + } + if (event == BossFightEvent.PLAYER_WIPED) { + state = BossFightState.FAILED; + traces.add(BossFightTrace.of(currentPhase().id(), event, "Party wiped")); + return; + } + if (event == BossFightEvent.FORCE_COMPLETE) { + completePhase(); + return; + } + + CatacombsBossPhase phase = currentPhase(); + traces.add(BossFightTrace.of(phase.id(), event, String.valueOf(value))); + if (matches(phase, event, value)) { + completePhase(); + } + } + + private boolean matches(CatacombsBossPhase phase, BossFightEvent event, int value) { + if (phase.trigger() == BossPhaseTrigger.ENTER_BOSS_ROOM && event == BossFightEvent.START) { + return true; + } + if (phase.trigger() == BossPhaseTrigger.BOSS_HEALTH_THRESHOLD && event == BossFightEvent.BOSS_DAMAGED) { + return value <= phase.triggerValue(); + } + if (phase.trigger() == BossPhaseTrigger.ADDS_DEFEATED && event == BossFightEvent.ADD_DEFEATED) { + objectiveProgress += value; + return phase.triggerValue() <= 0 || objectiveProgress >= phase.triggerValue(); + } + if (phase.trigger() == BossPhaseTrigger.PLAYER_OBJECTIVE && event == BossFightEvent.OBJECTIVE_COMPLETED) { + objectiveProgress += value; + return objectiveProgress >= phase.triggerValue(); + } + if (phase.trigger() == BossPhaseTrigger.TIMER && event == BossFightEvent.TIMER_EXPIRED) { + return true; + } + return phase.trigger() == BossPhaseTrigger.PHASE_COMPLETE && event == BossFightEvent.OBJECTIVE_COMPLETED; + } + + private void completePhase() { + traces.add(BossFightTrace.of(currentPhase().id(), BossFightEvent.FORCE_COMPLETE, "Phase complete")); + objectiveProgress = 0; + phaseIndex++; + if (phaseIndex >= encounter.phases().size()) { + state = BossFightState.COMPLETED; + } else { + state = BossFightState.PHASE_TRANSITION; + state = BossFightState.ACTIVE; + } + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightEvent.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightEvent.java new file mode 100644 index 000000000..bc0b4c5db --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightEvent.java @@ -0,0 +1,11 @@ +package net.swofty.dungeons.catacombs.boss.state; + +public enum BossFightEvent { + START, + BOSS_DAMAGED, + ADD_DEFEATED, + OBJECTIVE_COMPLETED, + TIMER_EXPIRED, + PLAYER_WIPED, + FORCE_COMPLETE +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightState.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightState.java new file mode 100644 index 000000000..66781d0e6 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightState.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.boss.state; + +public enum BossFightState { + NOT_STARTED, + ACTIVE, + PHASE_TRANSITION, + COMPLETED, + FAILED +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightTrace.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightTrace.java new file mode 100644 index 000000000..1210108a4 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/boss/state/BossFightTrace.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.boss.state; + +import java.time.Instant; + +public record BossFightTrace(String phaseId, BossFightEvent event, Instant happenedAt, String detail) { + public static BossFightTrace of(String phaseId, BossFightEvent event, String detail) { + return new BossFightTrace(phaseId, event, Instant.now(), detail); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassAbility.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassAbility.java new file mode 100644 index 000000000..b496d4173 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassAbility.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.classes; + +public record DungeonClassAbility( + String id, + String displayName, + DungeonClassAbilityType type, + int cooldownSeconds, + String description +) {} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassAbilityType.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassAbilityType.java new file mode 100644 index 000000000..2289b0c5d --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassAbilityType.java @@ -0,0 +1,8 @@ +package net.swofty.dungeons.catacombs.classes; + +public enum DungeonClassAbilityType { + PASSIVE, + ORB, + ULTIMATE, + GHOST +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassDefinition.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassDefinition.java new file mode 100644 index 000000000..b377158c7 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassDefinition.java @@ -0,0 +1,19 @@ +package net.swofty.dungeons.catacombs.classes; + +import java.util.List; + +public record DungeonClassDefinition( + DungeonClassType type, + String role, + List abilities +) { + public DungeonClassDefinition { + abilities = List.copyOf(abilities); + } + + public List abilities(DungeonClassAbilityType type) { + return abilities.stream() + .filter(ability -> ability.type() == type) + .toList(); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassRegistry.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassRegistry.java new file mode 100644 index 000000000..a57c2f94b --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassRegistry.java @@ -0,0 +1,79 @@ +package net.swofty.dungeons.catacombs.classes; + +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +public record DungeonClassRegistry(Map definitions) { + public DungeonClassRegistry { + definitions = Map.copyOf(definitions); + } + + public DungeonClassDefinition definition(DungeonClassType type) { + DungeonClassDefinition definition = definitions.get(type); + if (definition == null) { + throw new IllegalArgumentException("No dungeon class registered for " + type); + } + return definition; + } + + public static DungeonClassRegistry defaults() { + Map definitions = new EnumMap<>(DungeonClassType.class); + definitions.put(DungeonClassType.HEALER, new DungeonClassDefinition(DungeonClassType.HEALER, + "Healing and revive support", + abilities( + passive("HEALING_AURA", "Healing Aura", "Periodically heals nearby teammates"), + ultimate("WISH", "Wish", 120, "Heals all teammates and grants absorption"), + orb("HEALING_CIRCLE", "Healing Circle", 2, "Creates a healing circle at the caster"), + ghost("REVIVE", "Revive", 60, "Revives a dead teammate")))); + definitions.put(DungeonClassType.MAGE, new DungeonClassDefinition(DungeonClassType.MAGE, + "Magic damage", + abilities( + passive("MAGE_STAFF", "Mage Staff", "Left click beam attack while holding a dungeon item"), + ultimate("THUNDERSTORM", "Thunderstorm", 120, "Strikes nearby enemies with lightning"), + orb("GUIDED_SHEEP", "Guided Sheep", 30, "Launches an explosive sheep"), + ghost("WALL", "Wall", 60, "Creates a temporary wall")))); + definitions.put(DungeonClassType.BERSERK, new DungeonClassDefinition(DungeonClassType.BERSERK, + "Melee damage", + abilities( + passive("BLOODLUST", "Bloodlust", "Kills increase outgoing melee damage briefly"), + ultimate("RAGNAROK", "Ragnarok", 120, "Summons allied zombies"), + orb("THROWING_AXE", "Throwing Axe", 10, "Throws an axe at a target"), + ghost("VENGEFUL_SPIRIT", "Vengeful Spirit", 30, "Damages enemies while dead")))); + definitions.put(DungeonClassType.ARCHER, new DungeonClassDefinition(DungeonClassType.ARCHER, + "Ranged damage", + abilities( + passive("DOUBLE_SHOT", "Double Shot", "Arrows have a chance to fire twice"), + orb("EXPLOSIVE_SHOT", "Explosive Shot", 40, "Fires an explosive arrow"), + ultimate("RAPID_FIRE", "Rapid Fire", 120, "Rapidly fires arrows in the targeted direction"), + ghost("STUN_BOW", "Stun Bow", 15, "Stuns a target while dead")))); + definitions.put(DungeonClassType.TANK, new DungeonClassDefinition(DungeonClassType.TANK, + "Damage mitigation and enemy control", + abilities( + passive("DIVERSION", "Diversion", "Redirects a portion of teammate damage to the Tank"), + orb("SEISMIC_WAVE", "Seismic Wave", 15, "Sends a damaging wave forward"), + ultimate("CASTLE_OF_STONE", "Castle of Stone", 120, "Greatly reduces incoming damage"), + ghost("ABSORPTION", "Absorption", 60, "Grants teammates absorption while dead")))); + return new DungeonClassRegistry(definitions); + } + + private static DungeonClassAbility passive(String id, String displayName, String description) { + return new DungeonClassAbility(id, displayName, DungeonClassAbilityType.PASSIVE, 0, description); + } + + private static DungeonClassAbility orb(String id, String displayName, int cooldownSeconds, String description) { + return new DungeonClassAbility(id, displayName, DungeonClassAbilityType.ORB, cooldownSeconds, description); + } + + private static DungeonClassAbility ultimate(String id, String displayName, int cooldownSeconds, String description) { + return new DungeonClassAbility(id, displayName, DungeonClassAbilityType.ULTIMATE, cooldownSeconds, description); + } + + private static DungeonClassAbility ghost(String id, String displayName, int cooldownSeconds, String description) { + return new DungeonClassAbility(id, displayName, DungeonClassAbilityType.GHOST, cooldownSeconds, description); + } + + private static List abilities(DungeonClassAbility... abilities) { + return List.of(abilities); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassType.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassType.java new file mode 100644 index 000000000..69b2fcee1 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/classes/DungeonClassType.java @@ -0,0 +1,19 @@ +package net.swofty.dungeons.catacombs.classes; + +public enum DungeonClassType { + HEALER("Healer"), + MAGE("Mage"), + BERSERK("Berserk"), + ARCHER("Archer"), + TANK("Tank"); + + private final String displayName; + + DungeonClassType(String displayName) { + this.displayName = displayName; + } + + public String displayName() { + return displayName; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinSession.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinSession.java new file mode 100644 index 000000000..3e999ef3a --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinSession.java @@ -0,0 +1,109 @@ +package net.swofty.dungeons.catacombs.flow; + +import net.swofty.dungeons.catacombs.CatacombsFloor; +import net.swofty.dungeons.catacombs.CatacombsFloorDefinition; +import net.swofty.dungeons.catacombs.CatacombsMode; +import net.swofty.dungeons.catacombs.classes.DungeonClassType; +import net.swofty.dungeons.catacombs.party.PartyFinderListing; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public final class CatacombsJoinSession { + private final UUID playerId; + private final List traces = new ArrayList<>(); + private CatacombsMode mode; + private CatacombsFloor floor; + private DungeonClassType selectedClass; + private String selectedKitId; + private PartyFinderListing listing; + + private CatacombsJoinSession(UUID playerId) { + this.playerId = playerId; + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.CLICK_MORT, "Mort opened Catacombs menu")); + } + + public static CatacombsJoinSession clickedMort(UUID playerId) { + return new CatacombsJoinSession(playerId); + } + + public UUID playerId() { + return playerId; + } + + public CatacombsMode mode() { + return mode; + } + + public CatacombsFloor floor() { + return floor; + } + + public DungeonClassType selectedClass() { + return selectedClass; + } + + public String selectedKitId() { + return selectedKitId; + } + + public PartyFinderListing listing() { + return listing; + } + + public List traces() { + return List.copyOf(traces); + } + + public CatacombsJoinSession selectMode(CatacombsMode mode) { + this.mode = mode; + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.SELECT_MODE, mode.name())); + return this; + } + + public CatacombsJoinSession selectFloor(CatacombsFloorDefinition definition) { + this.floor = definition.floor(); + this.mode = definition.mode(); + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.SELECT_FLOOR, definition.floor().displayName())); + return this; + } + + public CatacombsJoinSession joinPartyFinder(PartyFinderListing listing) { + this.listing = listing; + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.PARTY_FINDER, listing.id().toString())); + return this; + } + + public CatacombsJoinSession readyCheck() { + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.READY_CHECK, "Player ready")); + return this; + } + + public CatacombsJoinSession selectClass(DungeonClassType type) { + this.selectedClass = type; + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.CLASS_SELECTION, type.displayName())); + return this; + } + + public CatacombsJoinSession selectKit(String kitId) { + this.selectedKitId = kitId; + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.KIT_SELECTION, kitId)); + return this; + } + + public CatacombsJoinSession instanceCreated() { + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.INSTANCE_CREATE, "Dungeon instance allocated")); + return this; + } + + public CatacombsJoinSession startRoom() { + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.START_ROOM, "Players spawned in start room")); + return this; + } + + public CatacombsJoinSession runStarted() { + traces.add(CatacombsJoinTrace.of(CatacombsJoinStep.RUN_STARTED, "Blood door locked, run timer started")); + return this; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinStep.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinStep.java new file mode 100644 index 000000000..48c119ef1 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinStep.java @@ -0,0 +1,14 @@ +package net.swofty.dungeons.catacombs.flow; + +public enum CatacombsJoinStep { + CLICK_MORT, + SELECT_MODE, + SELECT_FLOOR, + PARTY_FINDER, + READY_CHECK, + CLASS_SELECTION, + KIT_SELECTION, + INSTANCE_CREATE, + START_ROOM, + RUN_STARTED +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinTrace.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinTrace.java new file mode 100644 index 000000000..1d03f66e8 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/flow/CatacombsJoinTrace.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.flow; + +import java.time.Instant; + +public record CatacombsJoinTrace(CatacombsJoinStep step, Instant happenedAt, String detail) { + public static CatacombsJoinTrace of(CatacombsJoinStep step, String detail) { + return new CatacombsJoinTrace(step, Instant.now(), detail); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/generation/CatacombsGenerator.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/generation/CatacombsGenerator.java new file mode 100644 index 000000000..0300713ec --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/generation/CatacombsGenerator.java @@ -0,0 +1,27 @@ +package net.swofty.dungeons.catacombs.generation; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.swofty.dungeons.DungeonRoomType; +import net.swofty.dungeons.DungeonsAPI; +import net.swofty.dungeons.DungeonsData; +import net.swofty.dungeons.GeneratorService; +import net.swofty.dungeons.catacombs.CatacombsFloorDefinition; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class CatacombsGenerator { + public static GeneratorService generator(CatacombsFloorDefinition definition) { + DungeonsData data = new DungeonsData( + definition.floor().dungeonSize().width(), + definition.floor().dungeonSize().height()) + .with(DungeonRoomType.FAIRY, new DungeonsData.RoomData(1, 1)) + .with(DungeonRoomType.PUZZLE, new DungeonsData.RoomData(definition.puzzleRooms(), definition.puzzleRooms())) + .with(DungeonRoomType.MINI_BOSS, new DungeonsData.RoomData(definition.minibossRooms(), definition.minibossRooms())); + + if (definition.trapRooms() > 0) { + data.with(DungeonRoomType.TRAP, new DungeonsData.RoomData(definition.trapRooms(), definition.trapRooms())); + } + + return DungeonsAPI.getGeneratorService(data); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstance.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstance.java new file mode 100644 index 000000000..778655dec --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstance.java @@ -0,0 +1,27 @@ +package net.swofty.dungeons.catacombs.instance; + +import net.swofty.dungeons.SkyBlockDungeon; +import net.swofty.dungeons.catacombs.CatacombsFloorDefinition; +import net.swofty.dungeons.catacombs.boss.state.BossFightController; +import net.swofty.dungeons.catacombs.kit.DungeonClassKit; +import net.swofty.dungeons.catacombs.run.CatacombsRunState; + +import java.nio.file.Path; +import java.util.Map; +import java.util.UUID; + +public record CatacombsInstance( + UUID id, + CatacombsFloorDefinition floor, + SkyBlockDungeon dungeon, + CatacombsRunState runState, + BossFightController bossFight, + Map kits, + Map encounters, + Path renderedMap +) { + public CatacombsInstance { + kits = Map.copyOf(kits); + encounters = Map.copyOf(encounters); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstanceService.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstanceService.java new file mode 100644 index 000000000..6fbe4fbdf --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstanceService.java @@ -0,0 +1,70 @@ +package net.swofty.dungeons.catacombs.instance; + +import net.swofty.dungeons.DungeonRoomType; +import net.swofty.dungeons.SkyBlockDungeon; +import net.swofty.dungeons.catacombs.CatacombsAPI; +import net.swofty.dungeons.catacombs.CatacombsFloorDefinition; +import net.swofty.dungeons.catacombs.boss.state.BossFightController; +import net.swofty.dungeons.catacombs.kit.DungeonClassKit; +import net.swofty.dungeons.catacombs.mob.DungeonMobDefinition; +import net.swofty.dungeons.catacombs.mob.DungeonMobRole; +import net.swofty.dungeons.catacombs.run.CatacombsRunConfig; +import net.swofty.dungeons.catacombs.run.CatacombsRunState; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public final class CatacombsInstanceService { + public CatacombsInstance create(CatacombsFloorDefinition floor, + Map kits, + Path mapOutput) throws IOException { + SkyBlockDungeon dungeon = CatacombsAPI.generator(floor).generate().join(); + Map encounters = encounters(floor, dungeon); + CatacombsRunState runState = CatacombsRunState.start(new CatacombsRunConfig( + floor, + kits.entrySet().stream().collect(HashMap::new, + (map, entry) -> map.put(entry.getKey(), entry.getValue().type()), + HashMap::putAll), + dungeon.getRooms().size(), + estimateSecrets(floor, dungeon))); + Path renderedMap = null; + if (mapOutput != null) { + renderedMap = CatacombsAPI.renderMap(dungeon, mapOutput).path(); + } + return new CatacombsInstance(UUID.randomUUID(), floor, dungeon, runState, + new BossFightController(floor.boss()), kits, encounters, renderedMap); + } + + private Map encounters(CatacombsFloorDefinition floor, SkyBlockDungeon dungeon) { + Map encounters = new HashMap<>(); + int roomId = 0; + for (SkyBlockDungeon.DungeonRoom room : dungeon.getRooms().values()) { + List mobs = switch (room.getRoomType()) { + case MINI_BOSS -> CatacombsAPI.mobs(floor.floor(), DungeonMobRole.MINIBOSS).stream().limit(1).toList(); + case PUZZLE -> CatacombsAPI.mobs(floor.floor(), DungeonMobRole.PUZZLE).stream().limit(1).toList(); + case EXIT, BLOOD -> CatacombsAPI.mobs(floor.floor(), DungeonMobRole.BLOOD).stream().limit(5).toList(); + case BASE -> CatacombsAPI.mobs(floor.floor(), DungeonMobRole.STARRED).stream().limit(3).toList(); + default -> List.of(); + }; + if (!mobs.isEmpty()) { + encounters.put(roomId, new DungeonRoomEncounter(roomId, mobs)); + } + if (room.getRoomType() == DungeonRoomType.EXIT) { + room.setRoomType(DungeonRoomType.BLOOD); + } + roomId++; + } + return encounters; + } + + private int estimateSecrets(CatacombsFloorDefinition floor, SkyBlockDungeon dungeon) { + int baseRooms = (int) dungeon.getRooms().values().stream() + .filter(room -> room.getRoomType() == DungeonRoomType.BASE) + .count(); + return Math.max(5, baseRooms * 4 + floor.puzzleRooms()); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/DungeonRoomEncounter.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/DungeonRoomEncounter.java new file mode 100644 index 000000000..dba3fa9b4 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/DungeonRoomEncounter.java @@ -0,0 +1,41 @@ +package net.swofty.dungeons.catacombs.instance; + +import net.swofty.dungeons.catacombs.mob.DungeonMobDefinition; +import net.swofty.dungeons.catacombs.mob.DungeonMobInstance; + +import java.util.ArrayList; +import java.util.List; + +public final class DungeonRoomEncounter { + private final int roomId; + private final List mobs = new ArrayList<>(); + private boolean keyDropped; + + public DungeonRoomEncounter(int roomId, List definitions) { + this.roomId = roomId; + definitions.forEach(definition -> mobs.add(new DungeonMobInstance(definition))); + } + + public int roomId() { + return roomId; + } + + public List mobs() { + return List.copyOf(mobs); + } + + public boolean cleared() { + return mobs.stream().allMatch(DungeonMobInstance::dead); + } + + public boolean keyDropped() { + return keyDropped; + } + + public void damageMob(int index, long amount) { + mobs.get(index).damage(amount); + if (cleared()) { + keyDropped = true; + } + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonHotbarAction.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonHotbarAction.java new file mode 100644 index 000000000..623273e43 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonHotbarAction.java @@ -0,0 +1,8 @@ +package net.swofty.dungeons.catacombs.item; + +public enum DungeonHotbarAction { + DROP_KEY_ULTIMATE, + DROP_STACK_KEY_ABILITY, + RIGHT_CLICK_ORB, + GHOST_HOTBAR_SLOT +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonHotbarSlot.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonHotbarSlot.java new file mode 100644 index 000000000..cadb77576 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonHotbarSlot.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.item; + +import net.swofty.dungeons.catacombs.classes.DungeonClassAbility; + +public record DungeonHotbarSlot( + int slot, + DungeonHotbarAction action, + DungeonClassAbility ability +) {} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonOrbProfile.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonOrbProfile.java new file mode 100644 index 000000000..f34601c1f --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/item/DungeonOrbProfile.java @@ -0,0 +1,45 @@ +package net.swofty.dungeons.catacombs.item; + +import net.swofty.dungeons.catacombs.CatacombsFloor; +import net.swofty.dungeons.catacombs.classes.DungeonClassAbilityType; +import net.swofty.dungeons.catacombs.classes.DungeonClassDefinition; + +import java.util.List; + +public record DungeonOrbProfile( + String itemId, + String displayName, + boolean requiredForAbilities, + List mortGrantFloors, + List livingSlots, + List ghostSlots +) { + public DungeonOrbProfile { + mortGrantFloors = List.copyOf(mortGrantFloors); + livingSlots = List.copyOf(livingSlots); + ghostSlots = List.copyOf(ghostSlots); + } + + public static DungeonOrbProfile forClass(DungeonClassDefinition definition) { + List livingSlots = definition.abilities().stream() + .filter(ability -> ability.type() == DungeonClassAbilityType.ORB + || ability.type() == DungeonClassAbilityType.ULTIMATE) + .map(ability -> new DungeonHotbarSlot( + ability.type() == DungeonClassAbilityType.ULTIMATE ? 8 : 7, + ability.type() == DungeonClassAbilityType.ULTIMATE + ? DungeonHotbarAction.DROP_KEY_ULTIMATE + : DungeonHotbarAction.DROP_STACK_KEY_ABILITY, + ability)) + .toList(); + List ghostSlots = definition.abilities(DungeonClassAbilityType.GHOST).stream() + .map(ability -> new DungeonHotbarSlot(0, DungeonHotbarAction.GHOST_HOTBAR_SLOT, ability)) + .toList(); + return new DungeonOrbProfile( + "DUNGEON_STONE", + definition.type().displayName() + " Dungeon Orb", + false, + List.of(CatacombsFloor.ENTRANCE, CatacombsFloor.FLOOR_ONE, CatacombsFloor.FLOOR_TWO), + livingSlots, + ghostSlots); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonClassKit.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonClassKit.java new file mode 100644 index 000000000..49c982401 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonClassKit.java @@ -0,0 +1,16 @@ +package net.swofty.dungeons.catacombs.kit; + +import net.swofty.dungeons.catacombs.classes.DungeonClassType; + +import java.util.List; + +public record DungeonClassKit( + String id, + String displayName, + DungeonClassType type, + List items +) { + public DungeonClassKit { + items = List.copyOf(items); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonKitItem.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonKitItem.java new file mode 100644 index 000000000..2719bea21 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonKitItem.java @@ -0,0 +1,3 @@ +package net.swofty.dungeons.catacombs.kit; + +public record DungeonKitItem(String itemId, int slot, int amount) {} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonKitRegistry.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonKitRegistry.java new file mode 100644 index 000000000..701fba8e2 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/kit/DungeonKitRegistry.java @@ -0,0 +1,67 @@ +package net.swofty.dungeons.catacombs.kit; + +import net.swofty.dungeons.catacombs.classes.DungeonClassType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public record DungeonKitRegistry(Map kits) { + public DungeonKitRegistry { + kits = Map.copyOf(kits); + } + + public DungeonClassKit kit(String id) { + DungeonClassKit kit = kits.get(id); + if (kit == null) { + throw new IllegalArgumentException("Unknown dungeon kit " + id); + } + return kit; + } + + public List kits(DungeonClassType type) { + return kits.values().stream() + .filter(kit -> kit.type() == type) + .toList(); + } + + public static DungeonKitRegistry defaults() { + List kits = new ArrayList<>(); + kits.add(kit("HEALER_STARTER", "Healer Starter", DungeonClassType.HEALER, + item("DUNGEON_STONE", 8), + item("ORNATE_ZOMBIE_SWORD", 0), + item("WAND_OF_MENDING", 1), + item("REVIVE_STONE", 7))); + kits.add(kit("MAGE_STARTER", "Mage Starter", DungeonClassType.MAGE, + item("DUNGEON_STONE", 8), + item("DREADLORD_SWORD", 0), + item("CONJURING", 1), + item("DECOY", 7))); + kits.add(kit("BERSERK_STARTER", "Berserk Starter", DungeonClassType.BERSERK, + item("DUNGEON_STONE", 8), + item("ZOMBIE_KNIGHT_SWORD", 0), + item("FEL_SWORD", 1), + item("SPIRIT_LEAP", 7))); + kits.add(kit("ARCHER_STARTER", "Archer Starter", DungeonClassType.ARCHER, + item("DUNGEON_STONE", 8), + item("MACHINE_GUN_BOW", 0), + item("SUPER_UNDEAD_BOW", 1), + item("DECOY", 7))); + kits.add(kit("TANK_STARTER", "Tank Starter", DungeonClassType.TANK, + item("DUNGEON_STONE", 8), + item("EARTH_SHARD", 0), + item("SUPERBOOM_TNT", 1), + item("SPIRIT_LEAP", 7))); + return new DungeonKitRegistry(kits.stream().collect(Collectors.toMap(DungeonClassKit::id, Function.identity()))); + } + + private static DungeonClassKit kit(String id, String displayName, DungeonClassType type, DungeonKitItem... items) { + return new DungeonClassKit(id, displayName, type, List.of(items)); + } + + private static DungeonKitItem item(String itemId, int slot) { + return new DungeonKitItem(itemId, slot, 1); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapPalette.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapPalette.java new file mode 100644 index 000000000..03a0da7d5 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapPalette.java @@ -0,0 +1,37 @@ +package net.swofty.dungeons.catacombs.map; + +import net.swofty.dungeons.DungeonRoomType; + +import java.awt.Color; + +public enum DungeonMapPalette { + ENTRANCE(DungeonRoomType.ENTRANCE, new Color(0x55CC55)), + BASE(DungeonRoomType.BASE, new Color(0x8A6D54)), + FAIRY(DungeonRoomType.FAIRY, new Color(0xFF77DD)), + PUZZLE(DungeonRoomType.PUZZLE, new Color(0xAA66CC)), + MINI_BOSS(DungeonRoomType.MINI_BOSS, new Color(0xFFAA00)), + TRAP(DungeonRoomType.TRAP, new Color(0xCC3333)), + BLOOD(DungeonRoomType.BLOOD, new Color(0xAA0000)), + EXIT(DungeonRoomType.EXIT, new Color(0x333333)); + + private final DungeonRoomType roomType; + private final Color color; + + DungeonMapPalette(DungeonRoomType roomType, Color color) { + this.roomType = roomType; + this.color = color; + } + + public Color color() { + return color; + } + + public static Color forRoom(DungeonRoomType type) { + for (DungeonMapPalette value : values()) { + if (value.roomType == type) { + return value.color; + } + } + return BASE.color; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapRenderResult.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapRenderResult.java new file mode 100644 index 000000000..fd93ca082 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapRenderResult.java @@ -0,0 +1,5 @@ +package net.swofty.dungeons.catacombs.map; + +import java.nio.file.Path; + +public record DungeonMapRenderResult(Path path, int width, int height) {} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapRenderer.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapRenderer.java new file mode 100644 index 000000000..bd82780a3 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapRenderer.java @@ -0,0 +1,62 @@ +package net.swofty.dungeons.catacombs.map; + +import net.swofty.dungeons.SkyBlockDungeon; + +import javax.imageio.ImageIO; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +public final class DungeonMapRenderer { + private static final int TILE = 48; + private static final int GAP = 14; + private static final int PADDING = 24; + + public DungeonMapRenderResult renderPng(SkyBlockDungeon dungeon, Path outputPath) throws IOException { + int maxX = dungeon.getRooms().keySet().stream().mapToInt(Map.Entry::getKey).max().orElse(0); + int maxY = dungeon.getRooms().keySet().stream().mapToInt(Map.Entry::getValue).max().orElse(0); + int width = PADDING * 2 + (maxX + 1) * TILE + maxX * GAP; + int height = PADDING * 2 + (maxY + 1) * TILE + maxY * GAP; + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = image.createGraphics(); + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics.setColor(new Color(0x151515)); + graphics.fillRect(0, 0, width, height); + graphics.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + graphics.setColor(new Color(0xD9C7A7)); + for (SkyBlockDungeon.DungeonDoor door : dungeon.getDoorConnections()) { + int x1 = center(door.x1()); + int y1 = center(door.y1()); + int x2 = center(door.x2()); + int y2 = center(door.y2()); + graphics.drawLine(x1, y1, x2, y2); + } + dungeon.getRooms().forEach((point, room) -> { + int x = origin(point.getKey()); + int y = origin(point.getValue()); + graphics.setColor(DungeonMapPalette.forRoom(room.getRoomType())); + graphics.fillRoundRect(x, y, TILE, TILE, 8, 8); + graphics.setColor(room.isCritical() ? Color.WHITE : new Color(0x2A2A2A)); + graphics.setStroke(new BasicStroke(room.isCritical() ? 3 : 1)); + graphics.drawRoundRect(x, y, TILE, TILE, 8, 8); + }); + graphics.dispose(); + Files.createDirectories(outputPath.getParent()); + ImageIO.write(image, "png", outputPath.toFile()); + return new DungeonMapRenderResult(outputPath, width, height); + } + + private int origin(int coordinate) { + return PADDING + coordinate * (TILE + GAP); + } + + private int center(int coordinate) { + return origin(coordinate) + TILE / 2; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobAbility.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobAbility.java new file mode 100644 index 000000000..523d40456 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobAbility.java @@ -0,0 +1,22 @@ +package net.swofty.dungeons.catacombs.mob; + +public enum DungeonMobAbility { + MELEE, + BOW, + MAGIC_PROJECTILE, + TELEPORT, + INVISIBILITY, + SLOW, + EXPLOSION, + HEALING, + SUMMON_UNDEAD, + KNOCKBACK, + TRUE_DAMAGE, + WITHER_SKULL, + CHARGE, + SHIELD, + REVIVE, + SPLIT_CLONES, + TERMINAL_OBJECTIVE, + SPIRIT_BOW_VULNERABILITY +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobDefinition.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobDefinition.java new file mode 100644 index 000000000..0efbc48f7 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobDefinition.java @@ -0,0 +1,36 @@ +package net.swofty.dungeons.catacombs.mob; + +import net.swofty.dungeons.catacombs.CatacombsFloor; + +import java.util.Set; + +public record DungeonMobDefinition( + String id, + String displayName, + CatacombsFloor minimumFloor, + DungeonMobRole role, + long health, + long damage, + int defense, + Set abilities +) { + public DungeonMobDefinition { + abilities = Set.copyOf(abilities); + } + + public boolean canSpawn(CatacombsFloor floor) { + return floor.ordinal() >= minimumFloor.ordinal(); + } + + public DungeonMobDefinition scale(double healthMultiplier, double damageMultiplier, double defenseMultiplier) { + return new DungeonMobDefinition( + id, + displayName, + minimumFloor, + role, + Math.round(health * healthMultiplier), + Math.round(damage * damageMultiplier), + (int) Math.round(defense * defenseMultiplier), + abilities); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobInstance.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobInstance.java new file mode 100644 index 000000000..74d8cebbf --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobInstance.java @@ -0,0 +1,34 @@ +package net.swofty.dungeons.catacombs.mob; + +import java.util.UUID; + +public final class DungeonMobInstance { + private final UUID id = UUID.randomUUID(); + private final DungeonMobDefinition definition; + private long health; + + public DungeonMobInstance(DungeonMobDefinition definition) { + this.definition = definition; + this.health = definition.health(); + } + + public UUID id() { + return id; + } + + public DungeonMobDefinition definition() { + return definition; + } + + public long health() { + return health; + } + + public boolean dead() { + return health <= 0; + } + + public void damage(long amount) { + health = Math.max(0, health - amount); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobRegistry.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobRegistry.java new file mode 100644 index 000000000..7fec63272 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobRegistry.java @@ -0,0 +1,79 @@ +package net.swofty.dungeons.catacombs.mob; + +import net.swofty.dungeons.catacombs.CatacombsFloor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public record DungeonMobRegistry(Map mobs) { + public DungeonMobRegistry { + mobs = Map.copyOf(mobs); + } + + public DungeonMobDefinition mob(String id) { + DungeonMobDefinition mob = mobs.get(id); + if (mob == null) { + throw new IllegalArgumentException("Unknown dungeon mob " + id); + } + return mob; + } + + public List spawnable(CatacombsFloor floor, DungeonMobRole role) { + return mobs.values().stream() + .filter(mob -> mob.role() == role) + .filter(mob -> mob.canSpawn(floor)) + .toList(); + } + + public static DungeonMobRegistry defaults() { + List mobs = new ArrayList<>(); + mobs.add(mob("BAT", "Bat", CatacombsFloor.ENTRANCE, DungeonMobRole.SECRET, 100, 0, 0)); + mobs.add(mob("CRYPT_UNDEAD", "Crypt Undead", CatacombsFloor.ENTRANCE, DungeonMobRole.NORMAL, 1200, 120, 0)); + mobs.add(mob("UNDEAD_SKELETON", "Undead Skeleton", CatacombsFloor.ENTRANCE, DungeonMobRole.NORMAL, 1000, 100, 0, DungeonMobAbility.BOW)); + mobs.add(mob("SCARED_SKELETON", "Scared Skeleton", CatacombsFloor.ENTRANCE, DungeonMobRole.NORMAL, 1100, 90, 0, DungeonMobAbility.BOW)); + mobs.add(mob("ZOMBIE_GRUNT", "Zombie Grunt", CatacombsFloor.FLOOR_ONE, DungeonMobRole.NORMAL, 2500, 220, 0)); + mobs.add(mob("SKELETON_GRUNT", "Skeleton Grunt", CatacombsFloor.FLOOR_ONE, DungeonMobRole.NORMAL, 2200, 200, 0, DungeonMobAbility.BOW)); + mobs.add(mob("SNIPER", "Sniper", CatacombsFloor.FLOOR_ONE, DungeonMobRole.STARRED, 3500, 350, 0, DungeonMobAbility.BOW)); + mobs.add(mob("CRYPT_DREADLORD", "Crypt Dreadlord", CatacombsFloor.FLOOR_ONE, DungeonMobRole.STARRED, 4500, 420, 0, DungeonMobAbility.MAGIC_PROJECTILE)); + mobs.add(mob("CRYPT_LURKER", "Crypt Lurker", CatacombsFloor.FLOOR_ONE, DungeonMobRole.STARRED, 5000, 380, 0, DungeonMobAbility.INVISIBILITY)); + mobs.add(mob("CELLAR_SPIDER", "Cellar Spider", CatacombsFloor.FLOOR_ONE, DungeonMobRole.NORMAL, 2500, 180, 0)); + mobs.add(mob("LONELY_SPIDER", "Lonely Spider", CatacombsFloor.FLOOR_ONE, DungeonMobRole.NORMAL, 3000, 210, 0)); + mobs.add(mob("LOST_ADVENTURER", "Lost Adventurer", CatacombsFloor.FLOOR_ONE, DungeonMobRole.MINIBOSS, 120000, 1600, 100, DungeonMobAbility.HEALING, DungeonMobAbility.MELEE)); + mobs.add(mob("ANGRY_ARCHAEOLOGIST", "Angry Archaeologist", CatacombsFloor.FLOOR_ONE, DungeonMobRole.MINIBOSS, 100000, 1500, 75, DungeonMobAbility.MELEE)); + mobs.add(mob("SKELETON_SOLDIER", "Skeleton Soldier", CatacombsFloor.FLOOR_ONE, DungeonMobRole.STARRED, 7000, 520, 0, DungeonMobAbility.BOW)); + mobs.add(mob("ZOMBIE_SOLDIER", "Zombie Soldier", CatacombsFloor.FLOOR_TWO, DungeonMobRole.STARRED, 9000, 580, 0)); + mobs.add(mob("SKELETON_MASTER", "Skeleton Master", CatacombsFloor.FLOOR_THREE, DungeonMobRole.STARRED, 12000, 650, 0, DungeonMobAbility.BOW, DungeonMobAbility.TRUE_DAMAGE)); + mobs.add(mob("PUZZLE_BLAZE", "Puzzle Blaze", CatacombsFloor.FLOOR_THREE, DungeonMobRole.PUZZLE, 1500, 0, 0)); + mobs.add(mob("SHADOW_ASSASSIN", "Shadow Assassin", CatacombsFloor.FLOOR_THREE, DungeonMobRole.MINIBOSS, 250000, 2800, 200, DungeonMobAbility.TELEPORT, DungeonMobAbility.INVISIBILITY)); + mobs.add(mob("FROZEN_ADVENTURER", "Frozen Adventurer", CatacombsFloor.FLOOR_FOUR, DungeonMobRole.MINIBOSS, 400000, 3200, 250, DungeonMobAbility.MAGIC_PROJECTILE, DungeonMobAbility.SLOW)); + mobs.add(mob("KING_MIDAS", "King Midas", CatacombsFloor.FLOOR_FIVE, DungeonMobRole.MINIBOSS, 500000, 3500, 300, DungeonMobAbility.MELEE)); + mobs.add(mob("SKELETOR", "Skeletor", CatacombsFloor.FLOOR_FIVE, DungeonMobRole.STARRED, 30000, 900, 120, DungeonMobAbility.BOW)); + mobs.add(mob("SUPER_ARCHER", "Super Archer", CatacombsFloor.FLOOR_FIVE, DungeonMobRole.STARRED, 40000, 1100, 150, DungeonMobAbility.BOW)); + mobs.add(mob("SUPER_TANK_ZOMBIE", "Super Tank Zombie", CatacombsFloor.FLOOR_FIVE, DungeonMobRole.STARRED, 60000, 900, 600, DungeonMobAbility.SHIELD)); + mobs.add(mob("FEL", "Fel", CatacombsFloor.FLOOR_FIVE, DungeonMobRole.NORMAL, 35000, 1300, 100, DungeonMobAbility.TELEPORT)); + mobs.add(mob("DEATHMITE", "Deathmite", CatacombsFloor.FLOOR_FIVE, DungeonMobRole.NORMAL, 10000000, 100000, 0, DungeonMobAbility.TRUE_DAMAGE)); + mobs.add(mob("WATCHER_UNDEAD", "Watcher Undead", CatacombsFloor.ENTRANCE, DungeonMobRole.BLOOD, 5000, 500, 0, DungeonMobAbility.SUMMON_UNDEAD)); + mobs.add(mob("BONZO", "Bonzo", CatacombsFloor.FLOOR_ONE, DungeonMobRole.BOSS, 350000, 1600, 0, DungeonMobAbility.EXPLOSION, DungeonMobAbility.REVIVE)); + mobs.add(mob("SCARF", "Scarf", CatacombsFloor.FLOOR_TWO, DungeonMobRole.BOSS, 1000000, 2500, 0, DungeonMobAbility.SUMMON_UNDEAD)); + mobs.add(mob("PROFESSOR", "The Professor", CatacombsFloor.FLOOR_THREE, DungeonMobRole.BOSS, 2500000, 3000, 0, DungeonMobAbility.SUMMON_UNDEAD)); + mobs.add(mob("THORN", "Thorn", CatacombsFloor.FLOOR_FOUR, DungeonMobRole.BOSS, 3000000, 3500, 0, DungeonMobAbility.SPIRIT_BOW_VULNERABILITY)); + mobs.add(mob("LIVID", "Livid", CatacombsFloor.FLOOR_FIVE, DungeonMobRole.BOSS, 7000000, 5000, 0, DungeonMobAbility.SPLIT_CLONES)); + mobs.add(mob("SADAN", "Sadan", CatacombsFloor.FLOOR_SIX, DungeonMobRole.BOSS, 40000000, 12000, 0, DungeonMobAbility.SUMMON_UNDEAD)); + mobs.add(mob("MAXOR", "Maxor", CatacombsFloor.FLOOR_SEVEN, DungeonMobRole.BOSS, 75000000, 15000, 0, DungeonMobAbility.WITHER_SKULL)); + mobs.add(mob("STORM", "Storm", CatacombsFloor.FLOOR_SEVEN, DungeonMobRole.BOSS, 75000000, 15000, 0, DungeonMobAbility.WITHER_SKULL)); + mobs.add(mob("GOLDOR", "Goldor", CatacombsFloor.FLOOR_SEVEN, DungeonMobRole.BOSS, 75000000, 15000, 0, DungeonMobAbility.TERMINAL_OBJECTIVE)); + mobs.add(mob("NECRON", "Necron", CatacombsFloor.FLOOR_SEVEN, DungeonMobRole.BOSS, 100000000, 20000, 0, DungeonMobAbility.WITHER_SKULL, DungeonMobAbility.CHARGE)); + mobs.add(mob("WITHER_KING", "Wither King", CatacombsFloor.FLOOR_SEVEN, DungeonMobRole.BOSS, 1000000000L, 50000, 0, DungeonMobAbility.WITHER_SKULL)); + return new DungeonMobRegistry(mobs.stream().collect(Collectors.toMap(DungeonMobDefinition::id, Function.identity()))); + } + + private static DungeonMobDefinition mob(String id, String displayName, CatacombsFloor minimumFloor, + DungeonMobRole role, long health, long damage, int defense, + DungeonMobAbility... abilities) { + return new DungeonMobDefinition(id, displayName, minimumFloor, role, health, damage, defense, Set.of(abilities)); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobRole.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobRole.java new file mode 100644 index 000000000..09253e7c6 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/mob/DungeonMobRole.java @@ -0,0 +1,12 @@ +package net.swofty.dungeons.catacombs.mob; + +public enum DungeonMobRole { + NORMAL, + STARRED, + MINIBOSS, + BLOOD, + PUZZLE, + BOSS, + BOSS_ADD, + SECRET +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderListing.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderListing.java new file mode 100644 index 000000000..71b63114d --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderListing.java @@ -0,0 +1,111 @@ +package net.swofty.dungeons.catacombs.party; + +import net.swofty.dungeons.catacombs.CatacombsFloor; +import net.swofty.dungeons.catacombs.CatacombsMode; +import net.swofty.dungeons.catacombs.classes.DungeonClassType; + +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public final class PartyFinderListing { + private final UUID id; + private final UUID leaderId; + private final CatacombsFloor floor; + private final CatacombsMode mode; + private final int minimumCatacombsLevel; + private final Set allowedClasses; + private final Map members = new LinkedHashMap<>(); + private boolean open = true; + + public PartyFinderListing(UUID id, PartyFinderMember leader, CatacombsFloor floor, CatacombsMode mode, + int minimumCatacombsLevel, Set allowedClasses) { + this.id = id; + this.leaderId = leader.playerId(); + this.floor = floor; + this.mode = mode; + this.minimumCatacombsLevel = minimumCatacombsLevel; + this.allowedClasses = allowedClasses.isEmpty() + ? EnumSet.allOf(DungeonClassType.class) + : EnumSet.copyOf(allowedClasses); + members.put(leader.playerId(), leader); + } + + public UUID id() { + return id; + } + + public UUID leaderId() { + return leaderId; + } + + public CatacombsFloor floor() { + return floor; + } + + public CatacombsMode mode() { + return mode; + } + + public int minimumCatacombsLevel() { + return minimumCatacombsLevel; + } + + public boolean open() { + return open; + } + + public Map members() { + return Map.copyOf(members); + } + + public boolean full() { + return members.size() >= 5; + } + + public boolean ready() { + return members.size() >= 2 && members.values().stream().allMatch(PartyFinderMember::ready); + } + + public void join(PartyFinderMember member, int catacombsLevel) { + if (!open) { + throw new IllegalStateException("Party finder listing is closed"); + } + if (full()) { + throw new IllegalStateException("Party finder listing is full"); + } + if (catacombsLevel < minimumCatacombsLevel) { + throw new IllegalArgumentException("Catacombs level " + catacombsLevel + " is below " + minimumCatacombsLevel); + } + if (member.selectedClass() != null && !allowedClasses.contains(member.selectedClass())) { + throw new IllegalArgumentException(member.selectedClass() + " is not allowed in this listing"); + } + members.put(member.playerId(), member); + } + + public void updateClass(UUID playerId, DungeonClassType type) { + PartyFinderMember member = member(playerId); + if (!allowedClasses.contains(type)) { + throw new IllegalArgumentException(type + " is not allowed in this listing"); + } + members.put(playerId, member.withClass(type)); + } + + public void ready(UUID playerId, boolean ready) { + members.put(playerId, member(playerId).withReady(ready)); + } + + public void close() { + open = false; + } + + private PartyFinderMember member(UUID playerId) { + PartyFinderMember member = members.get(playerId); + if (member == null) { + throw new IllegalArgumentException("Player is not in this party finder listing"); + } + return member; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderMember.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderMember.java new file mode 100644 index 000000000..4af7b765c --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderMember.java @@ -0,0 +1,21 @@ +package net.swofty.dungeons.catacombs.party; + +import net.swofty.dungeons.catacombs.classes.DungeonClassType; + +import java.util.UUID; + +public record PartyFinderMember( + UUID playerId, + String name, + PartyFinderRole role, + DungeonClassType selectedClass, + boolean ready +) { + public PartyFinderMember withClass(DungeonClassType selectedClass) { + return new PartyFinderMember(playerId, name, role, selectedClass, ready); + } + + public PartyFinderMember withReady(boolean ready) { + return new PartyFinderMember(playerId, name, role, selectedClass, ready); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderRole.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderRole.java new file mode 100644 index 000000000..89faa8810 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderRole.java @@ -0,0 +1,6 @@ +package net.swofty.dungeons.catacombs.party; + +public enum PartyFinderRole { + LEADER, + MEMBER +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderService.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderService.java new file mode 100644 index 000000000..69d80fdb4 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/party/PartyFinderService.java @@ -0,0 +1,35 @@ +package net.swofty.dungeons.catacombs.party; + +import net.swofty.dungeons.catacombs.CatacombsFloorDefinition; +import net.swofty.dungeons.catacombs.classes.DungeonClassType; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public final class PartyFinderService { + private final Map listings = new HashMap<>(); + + public PartyFinderListing create(PartyFinderMember leader, CatacombsFloorDefinition floor, + int minimumCatacombsLevel, Set allowedClasses) { + PartyFinderListing listing = new PartyFinderListing(UUID.randomUUID(), leader, floor.floor(), floor.mode(), + minimumCatacombsLevel, allowedClasses); + listings.put(listing.id(), listing); + return listing; + } + + public PartyFinderListing listing(UUID id) { + PartyFinderListing listing = listings.get(id); + if (listing == null) { + throw new IllegalArgumentException("Unknown party finder listing " + id); + } + return listing; + } + + public Map openListings() { + return Map.copyOf(listings.entrySet().stream() + .filter(entry -> entry.getValue().open()) + .collect(HashMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), HashMap::putAll)); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/CatacombsPuzzle.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/CatacombsPuzzle.java new file mode 100644 index 000000000..39d989099 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/CatacombsPuzzle.java @@ -0,0 +1,42 @@ +package net.swofty.dungeons.catacombs.puzzle; + +import net.swofty.dungeons.catacombs.CatacombsFloor; + +public enum CatacombsPuzzle { + CREEPER_BEAMS("Creeper Beams", CatacombsFloor.ENTRANCE, false), + THREE_WEIRDOS("Three Weirdos", CatacombsFloor.ENTRANCE, true), + TIC_TAC_TOE("Tic Tac Toe", CatacombsFloor.ENTRANCE, true), + WATER_BOARD("Water Board", CatacombsFloor.ENTRANCE, false), + TELEPORT_MAZE("Teleport Maze", CatacombsFloor.ENTRANCE, false), + HIGHER_OR_LOWER("Higher or Lower", CatacombsFloor.FLOOR_THREE, true), + BOULDER("Boulder", CatacombsFloor.FLOOR_THREE, true), + ICE_FILL("Ice Fill", CatacombsFloor.FLOOR_SEVEN, false), + ICE_PATH("Ice Path", CatacombsFloor.FLOOR_THREE, true), + QUIZ("Quiz", CatacombsFloor.FLOOR_FOUR, true); + + private final String displayName; + private final CatacombsFloor minimumFloor; + private final boolean failable; + + CatacombsPuzzle(String displayName, CatacombsFloor minimumFloor, boolean failable) { + this.displayName = displayName; + this.minimumFloor = minimumFloor; + this.failable = failable; + } + + public String displayName() { + return displayName; + } + + public CatacombsFloor minimumFloor() { + return minimumFloor; + } + + public boolean failable() { + return failable; + } + + public boolean canGenerate(CatacombsFloor floor) { + return floor.ordinal() >= minimumFloor.ordinal(); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/CatacombsPuzzleFactory.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/CatacombsPuzzleFactory.java new file mode 100644 index 000000000..beea3771a --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/CatacombsPuzzleFactory.java @@ -0,0 +1,25 @@ +package net.swofty.dungeons.catacombs.puzzle; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class CatacombsPuzzleFactory { + public static PuzzleController create(CatacombsPuzzle puzzle) { + return switch (puzzle) { + case CREEPER_BEAMS -> new ObjectivePuzzleController(puzzle, "beam", 4); + case WATER_BOARD -> new ObjectivePuzzleController(puzzle, "gate", 5); + case TELEPORT_MAZE -> new ObjectivePuzzleController(puzzle, "finish", 1); + case ICE_FILL -> new ObjectivePuzzleController(puzzle, "layer", 3); + case ICE_PATH -> new ObjectivePuzzleController(puzzle, "detonate", 1); + case THREE_WEIRDOS -> new OrderedPuzzleController(puzzle, List.of("correct_chest")); + case TIC_TAC_TOE -> new OrderedPuzzleController(puzzle, List.of("tie")); + case HIGHER_OR_LOWER -> new OrderedPuzzleController(puzzle, + List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10")); + case BOULDER -> new ObjectivePuzzleController(puzzle, "path_open", 1); + case QUIZ -> new OrderedPuzzleController(puzzle, List.of("question_1", "question_2", "question_3")); + }; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/ObjectivePuzzleController.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/ObjectivePuzzleController.java new file mode 100644 index 000000000..cb73be93b --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/ObjectivePuzzleController.java @@ -0,0 +1,62 @@ +package net.swofty.dungeons.catacombs.puzzle; + +import java.util.ArrayList; +import java.util.List; + +public final class ObjectivePuzzleController implements PuzzleController { + private final CatacombsPuzzle puzzle; + private final String objectiveType; + private final int requiredProgress; + private final List traces = new ArrayList<>(); + private PuzzleState state = PuzzleState.READY; + private int progress; + + public ObjectivePuzzleController(CatacombsPuzzle puzzle, String objectiveType, int requiredProgress) { + this.puzzle = puzzle; + this.objectiveType = objectiveType; + this.requiredProgress = requiredProgress; + } + + @Override + public CatacombsPuzzle puzzle() { + return puzzle; + } + + @Override + public PuzzleState state() { + return state; + } + + @Override + public List traces() { + return List.copyOf(traces); + } + + @Override + public void accept(PuzzleAction action) { + if (state == PuzzleState.SOLVED || state == PuzzleState.FAILED) { + return; + } + state = PuzzleState.ACTIVE; + if ("fail".equals(action.type()) && puzzle.failable()) { + state = PuzzleState.FAILED; + traces.add(PuzzleTrace.of(state, action.value())); + return; + } + if (objectiveType.equals(action.type())) { + progress++; + traces.add(PuzzleTrace.of(state, action.type() + "=" + progress)); + if (progress >= requiredProgress) { + state = PuzzleState.SOLVED; + traces.add(PuzzleTrace.of(state, puzzle.displayName())); + } + } + } + + @Override + public void reset() { + progress = 0; + state = PuzzleState.RESET; + traces.add(PuzzleTrace.of(state, "Architect's First Draft")); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/OrderedPuzzleController.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/OrderedPuzzleController.java new file mode 100644 index 000000000..8f940ceb2 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/OrderedPuzzleController.java @@ -0,0 +1,60 @@ +package net.swofty.dungeons.catacombs.puzzle; + +import java.util.ArrayList; +import java.util.List; + +public final class OrderedPuzzleController implements PuzzleController { + private final CatacombsPuzzle puzzle; + private final List expected; + private final List traces = new ArrayList<>(); + private PuzzleState state = PuzzleState.READY; + private int index; + + public OrderedPuzzleController(CatacombsPuzzle puzzle, List expected) { + this.puzzle = puzzle; + this.expected = List.copyOf(expected); + } + + @Override + public CatacombsPuzzle puzzle() { + return puzzle; + } + + @Override + public PuzzleState state() { + return state; + } + + @Override + public List traces() { + return List.copyOf(traces); + } + + @Override + public void accept(PuzzleAction action) { + if (state == PuzzleState.SOLVED || state == PuzzleState.FAILED) { + return; + } + state = PuzzleState.ACTIVE; + if (!"select".equals(action.type()) || index >= expected.size() || !expected.get(index).equals(action.value())) { + if (puzzle.failable()) { + state = PuzzleState.FAILED; + traces.add(PuzzleTrace.of(state, action.value())); + } + return; + } + index++; + traces.add(PuzzleTrace.of(state, action.value())); + if (index >= expected.size()) { + state = PuzzleState.SOLVED; + traces.add(PuzzleTrace.of(state, puzzle.displayName())); + } + } + + @Override + public void reset() { + index = 0; + state = PuzzleState.RESET; + traces.add(PuzzleTrace.of(state, "Architect's First Draft")); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleAction.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleAction.java new file mode 100644 index 000000000..1eb6ba1bb --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleAction.java @@ -0,0 +1,7 @@ +package net.swofty.dungeons.catacombs.puzzle; + +public record PuzzleAction(String type, String value) { + public static PuzzleAction of(String type, String value) { + return new PuzzleAction(type, value); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleController.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleController.java new file mode 100644 index 000000000..b7d0967e9 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleController.java @@ -0,0 +1,15 @@ +package net.swofty.dungeons.catacombs.puzzle; + +import java.util.List; + +public interface PuzzleController { + CatacombsPuzzle puzzle(); + + PuzzleState state(); + + List traces(); + + void accept(PuzzleAction action); + + void reset(); +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleState.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleState.java new file mode 100644 index 000000000..2646dd8e2 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleState.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.puzzle; + +public enum PuzzleState { + READY, + ACTIVE, + SOLVED, + FAILED, + RESET +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleTrace.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleTrace.java new file mode 100644 index 000000000..e68f0b7c6 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/puzzle/PuzzleTrace.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.puzzle; + +import java.time.Instant; + +public record PuzzleTrace(PuzzleState state, Instant happenedAt, String detail) { + public static PuzzleTrace of(PuzzleState state, String detail) { + return new PuzzleTrace(state, Instant.now(), detail); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/CatacombsRunConfig.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/CatacombsRunConfig.java new file mode 100644 index 000000000..1113e3a43 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/CatacombsRunConfig.java @@ -0,0 +1,21 @@ +package net.swofty.dungeons.catacombs.run; + +import net.swofty.dungeons.catacombs.CatacombsFloorDefinition; +import net.swofty.dungeons.catacombs.classes.DungeonClassType; + +import java.util.Map; +import java.util.UUID; + +public record CatacombsRunConfig( + CatacombsFloorDefinition floor, + Map partyClasses, + int totalRooms, + int totalSecrets +) { + public CatacombsRunConfig { + partyClasses = Map.copyOf(partyClasses); + if (!floor.rules().allowsPartySize(partyClasses.size())) { + throw new IllegalArgumentException("Invalid Catacombs party size " + partyClasses.size()); + } + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/CatacombsRunState.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/CatacombsRunState.java new file mode 100644 index 000000000..3c9f9b690 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/CatacombsRunState.java @@ -0,0 +1,244 @@ +package net.swofty.dungeons.catacombs.run; + +import net.swofty.dungeons.catacombs.blessing.BlessingSet; +import net.swofty.dungeons.catacombs.blessing.BlessingType; + +import java.time.Duration; +import java.time.Instant; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +public final class CatacombsRunState { + private final CatacombsRunConfig config; + private final Instant startedAt; + private final Map rooms = new HashMap<>(); + private final BlessingSet blessings = new BlessingSet(); + private DungeonRunPhase phase = DungeonRunPhase.START_ROOM; + private int deaths; + private int crypts; + private int completedRooms; + private int secretsFound; + private int failedPuzzles; + private boolean spiritPetFirstDeathReduction; + private Instant finishedAt; + + private CatacombsRunState(CatacombsRunConfig config) { + this.config = config; + this.startedAt = Instant.now(); + for (int room = 0; room < config.totalRooms(); room++) { + rooms.put(room, DungeonRoomState.UNDISCOVERED); + } + } + + public static CatacombsRunState start(CatacombsRunConfig config) { + return new CatacombsRunState(config); + } + + public CatacombsRunConfig config() { + return config; + } + + public DungeonRunPhase phase() { + return phase; + } + + public int deaths() { + return deaths; + } + + public int crypts() { + return crypts; + } + + public int completedRooms() { + return completedRooms; + } + + public int secretsFound() { + return secretsFound; + } + + public int failedPuzzles() { + return failedPuzzles; + } + + public Map rooms() { + return Map.copyOf(rooms); + } + + public BlessingSet blessings() { + return blessings; + } + + public Duration elapsed() { + return Duration.between(startedAt, finishedAt == null ? Instant.now() : finishedAt); + } + + public CatacombsRunState enterClearing() { + phase = DungeonRunPhase.CLEARING; + return this; + } + + public CatacombsRunState enterBloodRoom() { + phase = DungeonRunPhase.BLOOD_ROOM; + return this; + } + + public CatacombsRunState enterBoss() { + phase = DungeonRunPhase.BOSS; + return this; + } + + public CatacombsRunState complete() { + phase = DungeonRunPhase.COMPLETED; + finishedAt = Instant.now(); + return this; + } + + public CatacombsRunState fail() { + phase = DungeonRunPhase.FAILED; + finishedAt = Instant.now(); + return this; + } + + public CatacombsRunState markRoom(int roomId, DungeonRoomState state) { + DungeonRoomState previous = rooms.put(roomId, state); + if (previous != DungeonRoomState.COMPLETED && state == DungeonRoomState.COMPLETED) { + completedRooms++; + } + return this; + } + + public CatacombsRunState recordDeath(boolean spiritPetReduced) { + if (spiritPetReduced && !spiritPetFirstDeathReduction) { + spiritPetFirstDeathReduction = true; + } + deaths++; + return this; + } + + public CatacombsRunState recordCrypt() { + crypts++; + return this; + } + + public CatacombsRunState recordSecret() { + secretsFound++; + return this; + } + + public CatacombsRunState failPuzzle(int roomId) { + failedPuzzles++; + markRoom(roomId, DungeonRoomState.FAILED); + return this; + } + + public CatacombsRunState addBlessing(BlessingType type, int level) { + blessings.add(type, level); + return this; + } + + public DungeonScoreBreakdown score() { + return new DungeonScoreBreakdown(skillScore(), explorationScore(), speedScore(), bonusScore()); + } + + public Map scoreTrace() { + Map trace = new HashMap<>(); + trace.put("deaths", deaths); + trace.put("failedPuzzles", failedPuzzles); + trace.put("completedRooms", completedRooms); + trace.put("totalRooms", config.totalRooms()); + trace.put("secretsFound", secretsFound); + trace.put("totalSecrets", config.totalSecrets()); + trace.put("crypts", crypts); + trace.put("elapsedSeconds", (int) elapsed().toSeconds()); + trace.put("speedScoreSeconds", config.floor().rules().speedScoreSeconds()); + trace.put("skill", skillScore()); + trace.put("exploration", explorationScore()); + trace.put("speed", speedScore()); + trace.put("bonus", bonusScore()); + trace.put("total", score().total()); + return Map.copyOf(trace); + } + + public Map progressionTrace() { + Map trace = new EnumMap<>(DungeonRunPhase.class); + for (DungeonRunPhase value : DungeonRunPhase.values()) { + trace.put(value, hasReached(value)); + } + return Map.copyOf(trace); + } + + private boolean hasReached(DungeonRunPhase value) { + if (phase == DungeonRunPhase.FAILED) { + return value != DungeonRunPhase.COMPLETED; + } + return value.ordinal() <= phase.ordinal(); + } + + private int skillScore() { + int deathPenalty = deaths * 2; + if (spiritPetFirstDeathReduction && deaths > 0) { + deathPenalty--; + } + return clamp(100 - deathPenalty - failedPuzzles * 10, 20, 100); + } + + private int explorationScore() { + double roomCompletion = ratio(completedRooms, config.totalRooms()); + double secretCompletion = ratio(secretsFound, config.totalSecrets()); + return clamp((int) Math.floor(roomCompletion * 60 + secretCompletion * 40), 0, 100); + } + + private int speedScore() { + int target = config.floor().rules().speedScoreSeconds(); + long elapsedSeconds = elapsed().toSeconds(); + if (elapsedSeconds <= target) { + return 100; + } + double percentOver = ((double) elapsedSeconds / target - 1) * 100; + return clamp(100 - speedPenalty(percentOver), 0, 100); + } + + private int bonusScore() { + int bonus = Math.min(5, crypts); + if (secretsFound >= config.totalSecrets()) { + bonus += 5; + } + return clamp(bonus, 0, config.floor().rules().bonusScoreCap()); + } + + private int speedPenalty(double percentOver) { + double remaining = percentOver; + int penalty = 0; + penalty += consumeSpeedBand(remaining, 20, 2); + remaining -= Math.min(remaining, 20); + penalty += consumeSpeedBand(remaining, 20, 4); + remaining -= Math.min(remaining, 20); + penalty += consumeSpeedBand(remaining, 10, 5); + remaining -= Math.min(remaining, 10); + penalty += consumeSpeedBand(remaining, 10, 6); + remaining -= Math.min(remaining, 10); + penalty += consumeSpeedBand(remaining, Double.MAX_VALUE, 7); + return penalty; + } + + private int consumeSpeedBand(double remainingPercent, double bandSize, double percentPerPoint) { + if (remainingPercent <= 0) { + return 0; + } + return (int) Math.floor(Math.min(remainingPercent, bandSize) / percentPerPoint); + } + + private double ratio(int current, int total) { + if (total <= 0) { + return 1; + } + return Math.min(1, Math.max(0, (double) current / total)); + } + + private int clamp(int value, int min, int max) { + return Math.max(min, Math.min(max, value)); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRoomState.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRoomState.java new file mode 100644 index 000000000..99a6b742c --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRoomState.java @@ -0,0 +1,9 @@ +package net.swofty.dungeons.catacombs.run; + +public enum DungeonRoomState { + UNDISCOVERED, + DISCOVERED, + CLEARED, + COMPLETED, + FAILED +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRunPhase.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRunPhase.java new file mode 100644 index 000000000..c97ca9622 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRunPhase.java @@ -0,0 +1,11 @@ +package net.swofty.dungeons.catacombs.run; + +public enum DungeonRunPhase { + QUEUED, + START_ROOM, + CLEARING, + BLOOD_ROOM, + BOSS, + COMPLETED, + FAILED +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRunRules.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRunRules.java new file mode 100644 index 000000000..db1eab028 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonRunRules.java @@ -0,0 +1,15 @@ +package net.swofty.dungeons.catacombs.run; + +public record DungeonRunRules( + int speedScoreSeconds, + int maximumDurationSeconds, + int minimumPartySize, + int maximumPartySize, + int bonusScoreCap, + boolean automaticGhostRevive, + boolean trapRoomsEnabled +) { + public boolean allowsPartySize(int size) { + return size >= minimumPartySize && size <= maximumPartySize; + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonScoreBreakdown.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonScoreBreakdown.java new file mode 100644 index 000000000..089ef650d --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonScoreBreakdown.java @@ -0,0 +1,16 @@ +package net.swofty.dungeons.catacombs.run; + +public record DungeonScoreBreakdown( + int skill, + int exploration, + int speed, + int bonus +) { + public int total() { + return skill + exploration + speed + bonus; + } + + public DungeonScoreRank rank() { + return DungeonScoreRank.fromScore(total()); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonScoreRank.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonScoreRank.java new file mode 100644 index 000000000..d66da0a4f --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/run/DungeonScoreRank.java @@ -0,0 +1,38 @@ +package net.swofty.dungeons.catacombs.run; + +import java.util.Arrays; +import java.util.Comparator; + +public enum DungeonScoreRank { + S_PLUS("S+", 300), + S("S", 270), + A("A", 230), + B("B", 160), + C("C", 100), + D("D", 40), + NONE("", 0); + + private final String displayName; + private final int minimumScore; + + DungeonScoreRank(String displayName, int minimumScore) { + this.displayName = displayName; + this.minimumScore = minimumScore; + } + + public String displayName() { + return displayName; + } + + public int minimumScore() { + return minimumScore; + } + + public static DungeonScoreRank fromScore(int score) { + return Arrays.stream(values()) + .sorted(Comparator.comparingInt(DungeonScoreRank::minimumScore).reversed()) + .filter(rank -> score >= rank.minimumScore) + .findFirst() + .orElse(NONE); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretReward.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretReward.java new file mode 100644 index 000000000..739b74b77 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretReward.java @@ -0,0 +1,19 @@ +package net.swofty.dungeons.catacombs.secret; + +import net.swofty.dungeons.catacombs.CatacombsFloor; + +import java.util.Set; + +public record CatacombsSecretReward( + SecretRewardType type, + CatacombsFloor minimumFloor, + Set secretTypes +) { + public CatacombsSecretReward { + secretTypes = Set.copyOf(secretTypes); + } + + public boolean canDrop(CatacombsFloor floor, CatacombsSecretType secretType) { + return floor.ordinal() >= minimumFloor.ordinal() && secretTypes.contains(secretType); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretRewards.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretRewards.java new file mode 100644 index 000000000..c4e4be845 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretRewards.java @@ -0,0 +1,37 @@ +package net.swofty.dungeons.catacombs.secret; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.swofty.dungeons.catacombs.CatacombsFloor; + +import java.util.List; +import java.util.Set; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class CatacombsSecretRewards { + private static final Set COMMON = Set.of( + CatacombsSecretType.CHEST, + CatacombsSecretType.GROUND_ITEM, + CatacombsSecretType.BAT); + + public static List defaults() { + return List.of( + new CatacombsSecretReward(SecretRewardType.RANDOM_BLESSING, CatacombsFloor.ENTRANCE, + Set.of(CatacombsSecretType.CHEST, CatacombsSecretType.BAT)), + new CatacombsSecretReward(SecretRewardType.HEALING_POTION, CatacombsFloor.ENTRANCE, COMMON), + new CatacombsSecretReward(SecretRewardType.DECOY, CatacombsFloor.ENTRANCE, COMMON), + new CatacombsSecretReward(SecretRewardType.TRAINING_WEIGHTS, CatacombsFloor.ENTRANCE, COMMON), + new CatacombsSecretReward(SecretRewardType.SPIRIT_LEAP, CatacombsFloor.ENTRANCE, COMMON), + new CatacombsSecretReward(SecretRewardType.INFLATABLE_JERRY, CatacombsFloor.ENTRANCE, COMMON), + new CatacombsSecretReward(SecretRewardType.TRAP, CatacombsFloor.ENTRANCE, COMMON), + new CatacombsSecretReward(SecretRewardType.DEFUSE_KIT, CatacombsFloor.ENTRANCE, COMMON), + new CatacombsSecretReward(SecretRewardType.DUNGEON_CHEST_KEY, CatacombsFloor.FLOOR_FOUR, COMMON), + new CatacombsSecretReward(SecretRewardType.TREASURE_TALISMAN, CatacombsFloor.FLOOR_FOUR, COMMON), + new CatacombsSecretReward(SecretRewardType.ARCHITECTS_FIRST_DRAFT, CatacombsFloor.ENTRANCE, + Set.of(CatacombsSecretType.CHEST)), + new CatacombsSecretReward(SecretRewardType.SECRET_DYE, CatacombsFloor.ENTRANCE, + Set.of(CatacombsSecretType.CHEST)), + new CatacombsSecretReward(SecretRewardType.WITHER_ESSENCE, CatacombsFloor.ENTRANCE, + Set.of(CatacombsSecretType.WITHER_ESSENCE))); + } +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretType.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretType.java new file mode 100644 index 000000000..2fb5dbe28 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/CatacombsSecretType.java @@ -0,0 +1,10 @@ +package net.swofty.dungeons.catacombs.secret; + +public enum CatacombsSecretType { + CHEST, + GROUND_ITEM, + REDSTONE_KEY, + BAT, + WITHER_ESSENCE, + JOURNAL +} diff --git a/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/SecretRewardType.java b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/SecretRewardType.java new file mode 100644 index 000000000..6ce6922b0 --- /dev/null +++ b/dungeons/src/main/java/net/swofty/dungeons/catacombs/secret/SecretRewardType.java @@ -0,0 +1,17 @@ +package net.swofty.dungeons.catacombs.secret; + +public enum SecretRewardType { + RANDOM_BLESSING, + HEALING_POTION, + DECOY, + TRAINING_WEIGHTS, + SPIRIT_LEAP, + INFLATABLE_JERRY, + TRAP, + DEFUSE_KIT, + DUNGEON_CHEST_KEY, + TREASURE_TALISMAN, + ARCHITECTS_FIRST_DRAFT, + SECRET_DYE, + WITHER_ESSENCE +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 78a3aa7ff..54d2cf512 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,12 +8,12 @@ configlib-yaml = "4.8.1" configurate-yaml = "4.2.0" creative = "1.7.3" fastutil = "8.5.18" -gson = "2.11.0" +gson = "2.13.2" guava = "33.5.0-jre" jackson-annotations = "2.20" jackson-bom = "3.1.0" javapoet = "1.13.0" -jedis = "7.2.0" +jedis = "7.4.1" joml = "1.10.8" json = "20251224" junit = "4.13.2" @@ -37,7 +37,7 @@ velocity-api = "3.5.0-SNAPSHOT" viabackwards = "5.7.2" vialoader = "4.0.6" viarewind = "4.0.15" -viaversion = "5.7.1" +viaversion = "5.8.1" [libraries] adventure-api = { module = "net.kyori:adventure-api", version.ref = "adventure" } diff --git a/loader/build.gradle.kts b/loader/build.gradle.kts index b43d82f95..c682b48cd 100644 --- a/loader/build.gradle.kts +++ b/loader/build.gradle.kts @@ -4,7 +4,7 @@ import java.util.* plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/loader/src/main/java/net/swofty/loader/Hypixel.java b/loader/src/main/java/net/swofty/loader/Hypixel.java index 6b852965c..32b57db7a 100644 --- a/loader/src/main/java/net/swofty/loader/Hypixel.java +++ b/loader/src/main/java/net/swofty/loader/Hypixel.java @@ -20,13 +20,12 @@ import net.swofty.commons.ServerType; import net.swofty.commons.TestFlow; import net.swofty.commons.config.ConfigProvider; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.*; +import net.swofty.commons.redis.RedisClient; import net.swofty.proxyapi.ProxyAPI; import net.swofty.proxyapi.ProxyService; -import net.swofty.proxyapi.redis.ServerOutboundMessage; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.spark.Spark; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; @@ -155,22 +154,22 @@ static void main(String[] args) { // Initialize proxy support ProxyAPI proxyAPI = new ProxyAPI(ConfigProvider.settings().getRedisUri(), serverUUID); - SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.generic.redis", TypedProxyHandler.class) - .forEach(proxyAPI::registerTypedProxyHandler); - SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.generic.redis.service", TypedServiceHandler.class) - .forEach(proxyAPI::registerTypedServiceHandler); - typeLoader.getTypedProxyHandlers().forEach(proxyAPI::registerTypedProxyHandler); - typeLoader.getTypedServiceHandlers().forEach(proxyAPI::registerTypedServiceHandler); + SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.generic.redis", RedisMessageHandler.class) + .forEach(proxyAPI::registerProxyHandler); + SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.generic.redis.service", RedisMessageHandler.class) + .forEach(proxyAPI::registerServiceHandler); + typeLoader.getProxyHandlers().forEach(proxyAPI::registerProxyHandler); + typeLoader.getServiceHandlers().forEach(proxyAPI::registerServiceHandler); if (typeLoader instanceof SkyBlockTypeLoader) { - SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.skyblockgeneric.redis", TypedProxyHandler.class) - .forEach(proxyAPI::registerTypedProxyHandler); - SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.skyblockgeneric.redis.service", TypedServiceHandler.class) - .forEach(proxyAPI::registerTypedServiceHandler); + SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.skyblockgeneric.redis", RedisMessageHandler.class) + .forEach(proxyAPI::registerProxyHandler); + SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.skyblockgeneric.redis.service", RedisMessageHandler.class) + .forEach(proxyAPI::registerServiceHandler); } else if (typeLoader instanceof RavengardTypeLoader) { - SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.ravengardgeneric.redis", TypedProxyHandler.class) - .forEach(proxyAPI::registerTypedProxyHandler); + SkyBlockGenericLoader.loopThroughPackage("net.swofty.type.ravengardgeneric.redis", RedisMessageHandler.class) + .forEach(proxyAPI::registerProxyHandler); } - ProtocolObject[] toProxyProtocols = { + RedisProtocol[] toProxyProtocols = { new RequestServerNameProtocol(), new PlayerCountProtocol(), new PlayerHandlerProtocol(), new ProxyIsOnlineProtocol(), new RegisterServerProtocol(), new FinishedWithPlayerProtocol(), @@ -178,14 +177,14 @@ static void main(String[] args) { new TestFlowServerReadyProtocol(), new StaffChatProtocol(), new PunishPlayerProtocol() }; - for (ProtocolObject protocol : toProxyProtocols) { - ServerOutboundMessage.registerToProxyProtocol(protocol); + for (RedisProtocol protocol : toProxyProtocols) { + RedisClient.registerResponseProtocol(protocol); } - List protocolObjects = SkyBlockGenericLoader.loopThroughPackage( - "net.swofty.commons.protocol.objects", ProtocolObject.class) + List protocols = SkyBlockGenericLoader.loopThroughPackage( + "net.swofty.commons.protocol.objects", RedisProtocol.class) .filter(obj -> !obj.getClass().getPackageName().startsWith("net.swofty.commons.protocol.objects.proxy")) .toList(); - protocolObjects.forEach(ServerOutboundMessage::registerFromProtocolObject); + protocols.forEach(RedisClient::registerResponseProtocol); proxyAPI.start(); // Start spark if enabled @@ -227,9 +226,9 @@ static void main(String[] args) { HypixelConst.setMaxPlayers(maxPlayers); HypixelConst.setServerUUID(serverUUID); - ServerOutboundMessage.sendToProxy(new RequestServerNameProtocol(), - new RequestServerNameProtocol.Request(), - (response) -> { + RedisClient.requestProxy(new RequestServerNameProtocol(), + new RequestServerNameProtocol.Request()) + .thenAccept(response -> { if (isTestFlow) { String serverNameRaw = response.shortenedServerName().substring(1); String serverName = "isolated" + serverNameRaw; @@ -277,14 +276,14 @@ public void onFlag(UUID uuid, FlagType flagType) { System.exit(0); }); - ServerOutboundMessage.sendToProxy(new RegisterServerProtocol(), + RedisClient.requestProxy(new RegisterServerProtocol(), new RegisterServerProtocol.Request( serverType.name(), maxPlayers, InetAddress.getLocalHost().getHostName(), null, isTestFlow ? true : null, isTestFlow ? testFlowName : null, isTestFlow ? testFlowIndex : null, - isTestFlow ? testFlowTotal : null), - (response) -> startServer.complete(response.port())); + isTestFlow ? testFlowTotal : null)) + .thenAccept(response -> startServer.complete(response.port())); } private static void handleTestFlowRegistration(String testFlowName, String handler, String players, @@ -311,9 +310,9 @@ private static void handleTestFlowRegistration(String testFlowName, String handl configList.add(Map.of("type", type, "count", count)); } - ServerOutboundMessage.sendToProxy(new RegisterTestFlowProtocol(), - new RegisterTestFlowProtocol.Request(testFlowName, handler, playerList, configList), - (response) -> { + RedisClient.requestProxy(new RegisterTestFlowProtocol(), + new RegisterTestFlowProtocol.Request(testFlowName, handler, playerList, configList)) + .thenAccept(response -> { Logger.info("Test flow registered successfully with proxy"); notifyTestFlowServerReady(testFlowName, serverType, index); }); @@ -324,9 +323,9 @@ private static void handleTestFlowRegistration(String testFlowName, String handl } private static void notifyTestFlowServerReady(String testFlowName, ServerType serverType, String index) { - ServerOutboundMessage.sendToProxy(new TestFlowServerReadyProtocol(), - new TestFlowServerReadyProtocol.Request(testFlowName, serverType.name(), Integer.parseInt(index)), - (response) -> { + RedisClient.requestProxy(new TestFlowServerReadyProtocol(), + new TestFlowServerReadyProtocol.Request(testFlowName, serverType.name(), Integer.parseInt(index))) + .thenAccept(response -> { Logger.info("Notified proxy that " + serverType.name() + " server " + index + " is ready for test flow: " + testFlowName); }); } @@ -346,8 +345,8 @@ private static void checkProxyConnected(Scheduler scheduler) { AtomicBoolean responded = new AtomicBoolean(false); try { - ServerOutboundMessage.sendToProxy(new ProxyIsOnlineProtocol(), - new ProxyIsOnlineProtocol.Request(), (response) -> { + RedisClient.requestProxy(new ProxyIsOnlineProtocol(), + new ProxyIsOnlineProtocol.Request()).thenAccept(response -> { if (response.online()) { responded.set(true); } diff --git a/packer/build.gradle.kts b/packer/build.gradle.kts index 192644521..a65dc8c0e 100644 --- a/packer/build.gradle.kts +++ b/packer/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { `java-library` application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyAPI.java b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyAPI.java index 3e99ec7b4..916a97539 100644 --- a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyAPI.java +++ b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyAPI.java @@ -1,11 +1,12 @@ package net.swofty.proxyapi; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.ServicePushProtocol; -import net.swofty.commons.redis.RedisEnvelope; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; -import net.swofty.redisapi.api.ChannelRegistry; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.redis.RedisChannels; +import net.swofty.commons.redis.RedisClient; +import net.swofty.commons.redis.RedisEndpoint; +import net.swofty.commons.redis.RedisMessageBus; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.redisapi.api.RedisAPI; import java.util.UUID; @@ -18,71 +19,57 @@ public ProxyAPI(String URI, UUID serverUUID) { RedisAPI.generateInstance(URI); RedisAPI.getInstance().setFilterId(serverUUID.toString()); + RedisClient.identify(RedisEndpoint.server(serverUUID)); } - public void registerTypedProxyHandler(TypedProxyHandler handler) { - ProtocolObject protocol = handler.getProtocol(); - - RedisAPI.getInstance().registerChannel(protocol.channel(), (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - String rawMessage = envelope.payload(); - - T typedMessage = protocol.translateFromString(rawMessage); - R response = handler.onMessage(typedMessage); - - String serializedResponse = protocol.translateReturnToString(response); - - RedisAPI.getInstance().publishMessage( - "proxy", - ChannelRegistry.getFromName(protocol.channel()), - new RedisEnvelope(envelope.id(), serverUUID.toString(), serializedResponse).serialize()); - }); + public void registerProxyHandler(RedisMessageHandler handler) { + RedisProtocol protocol = handler.protocol(); + + RedisMessageBus.registerHandler( + RedisEndpoint.server(serverUUID), + RedisChannels.protocol(protocol), + handler, + (envelope, channel) -> RedisMessageContext.between( + UUID.fromString(envelope.id()), + RedisEndpoint.proxy(), + RedisEndpoint.server(serverUUID), + protocol.channel() + ), + envelope -> RedisChannels.PROXY_RESPONSE, + envelope -> RedisChannels.protocol(protocol) + ); } - public void registerTypedServiceHandler(TypedServiceHandler handler) { - ServicePushProtocol protocol = handler.getProtocol(); - String channelName = "service_" + protocol.channel(); - - RedisAPI.getInstance().registerChannel(channelName, (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - String serviceId = envelope.from(); - String rawMessage = envelope.payload(); - - Thread.startVirtualThread(() -> { - T typedMessage = protocol.translateFromString(rawMessage); - R response = handler.onMessage(typedMessage); - - String serializedResponse = protocol.translateReturnToString(response); - - RedisAPI.getInstance().publishMessage( - serviceId, - ChannelRegistry.getFromName("service_response"), - new RedisEnvelope(envelope.id(), serverUUID.toString(), serializedResponse).serialize()); - }); - }); - - RedisAPI.getInstance().registerChannel("service_broadcast_" + protocol.channel(), (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - String serviceId = envelope.from(); - String rawMessage = envelope.payload(); - - Thread.startVirtualThread(() -> { - T typedMessage = protocol.translateFromString(rawMessage); - R response = handler.onMessage(typedMessage); - - if (response == null) return; - - String serializedResponse = protocol.translateReturnToString(response); - - RedisAPI.getInstance().publishMessage( - serviceId, - ChannelRegistry.getFromName("service_broadcast_response"), - new RedisEnvelope(envelope.id(), serverUUID.toString(), serializedResponse).serialize()); - }); - }); + public void registerServiceHandler(RedisMessageHandler handler) { + RedisProtocol protocol = handler.protocol(); + + RedisMessageBus.registerHandler( + RedisEndpoint.server(serverUUID), + RedisChannels.serviceRequest(protocol), + handler, + (envelope, channel) -> RedisMessageContext.between( + UUID.fromString(envelope.id()), + RedisEndpoint.service(envelope.from()), + RedisEndpoint.server(serverUUID), + protocol.channel() + ), + envelope -> envelope.from(), + envelope -> RedisChannels.SERVICE_RESPONSE + ); + + RedisMessageBus.registerHandler( + RedisEndpoint.server(serverUUID), + RedisChannels.serviceBroadcast(protocol), + handler, + (envelope, channel) -> RedisMessageContext.between( + UUID.fromString(envelope.id()), + RedisEndpoint.service(envelope.from()), + RedisEndpoint.server(serverUUID), + protocol.channel() + ).asBroadcast(), + envelope -> envelope.from(), + envelope -> RedisChannels.SERVICE_BROADCAST_RESPONSE + ); } public void start() { diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyInformation.java b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyInformation.java index 6d50a5196..6e99682d9 100644 --- a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyInformation.java +++ b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyInformation.java @@ -3,7 +3,7 @@ import net.swofty.commons.ServerType; import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.protocol.objects.proxy.to.RequestServersProtocol; -import net.swofty.proxyapi.redis.ServerOutboundMessage; +import net.swofty.commons.redis.RedisClient; import org.json.JSONObject; import java.util.List; @@ -15,33 +15,33 @@ public class ProxyInformation { public CompletableFuture getServerInformation(UUID uuid) { CompletableFuture future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PROTOCOL, - new RequestServersProtocol.Request("UUID", null, uuid.toString()), - response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())).getFirst())); + RedisClient.requestProxy(PROTOCOL, + new RequestServersProtocol.Request("UUID", null, uuid.toString())) + .thenAccept(response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())).getFirst())); return future; } public CompletableFuture> getServerInformation(ServerType type) { CompletableFuture> future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PROTOCOL, - new RequestServersProtocol.Request("TYPE", type.name(), null), - response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())))); + RedisClient.requestProxy(PROTOCOL, + new RequestServersProtocol.Request("TYPE", type.name(), null)) + .thenAccept(response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())))); return future; } public CompletableFuture> getAllServersInformation() { CompletableFuture> future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PROTOCOL, - new RequestServersProtocol.Request("ALL", null, null), - response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())))); + RedisClient.requestProxy(PROTOCOL, + new RequestServersProtocol.Request("ALL", null, null)) + .thenAccept(response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())))); return future; } public CompletableFuture getServerInformation(ProxyPlayer player) { CompletableFuture future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PROTOCOL, - new RequestServersProtocol.Request("PLAYER_UUID", null, player.getUuid().toString()), - response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())).getFirst())); + RedisClient.requestProxy(PROTOCOL, + new RequestServersProtocol.Request("PLAYER_UUID", null, player.getUuid().toString())) + .thenAccept(response -> future.complete(UnderstandableProxyServer.fromJSON(new JSONObject(response.serversList())).getFirst())); return future; } } diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayer.java b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayer.java index ad03ebe62..30425cee3 100644 --- a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayer.java +++ b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayer.java @@ -8,8 +8,8 @@ import net.swofty.commons.ServerType; import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.protocol.objects.proxy.to.PlayerHandlerProtocol; +import net.swofty.commons.redis.RedisClient; import net.swofty.proxyapi.impl.ProxyUnderstandableEvent; -import net.swofty.proxyapi.redis.ServerOutboundMessage; import org.json.JSONObject; import java.util.Map; @@ -33,10 +33,9 @@ public ProxyPlayer(UUID uuid) { } public void sendMessage(Component message) { - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, + RedisClient.requestProxy(PLAYER_HANDLER, new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.MESSAGE, - Map.of("message", JSONComponentSerializer.json().serialize(message))), - response -> {}); + Map.of("message", JSONComponentSerializer.json().serialize(message)))); } public void sendMessage(String message) { @@ -44,18 +43,17 @@ public void sendMessage(String message) { } public void teleport(Pos pos) { - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, + RedisClient.requestProxy(PLAYER_HANDLER, new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.TELEPORT, Map.of("x", pos.x(), "y", pos.y(), "z", pos.z(), - "yaw", pos.yaw(), "pitch", pos.pitch())), - response -> {}); + "yaw", pos.yaw(), "pitch", pos.pitch()))); } public CompletableFuture getServer() { CompletableFuture future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, - new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.GET_SERVER, Map.of()), - response -> { + RedisClient.requestProxy(PLAYER_HANDLER, + new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.GET_SERVER, Map.of())) + .thenAccept(response -> { @SuppressWarnings("unchecked") Map serverMap = (Map) response.data().get("server"); if (serverMap != null) { @@ -69,9 +67,9 @@ public CompletableFuture getServer() { public CompletableFuture isOnline() { CompletableFuture future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, - new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.IS_ONLINE, Map.of()), - response -> { + RedisClient.requestProxy(PLAYER_HANDLER, + new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.IS_ONLINE, Map.of())) + .thenAccept(response -> { Object isOnline = response.data().get("isOnline"); future.complete(Boolean.TRUE.equals(isOnline)); }); @@ -79,51 +77,46 @@ public CompletableFuture isOnline() { } public void runEvent(ProxyUnderstandableEvent event) { - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, + RedisClient.requestProxy(PLAYER_HANDLER, new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.EVENT, Map.of("event", event.getClass().getName(), - "data", event.asProxyUnderstandable())), - response -> {}); + "data", event.asProxyUnderstandable()))); } public CompletableFuture transferToWithIndication(UUID serverToTransferTo) { CompletableFuture future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, + RedisClient.requestProxy(PLAYER_HANDLER, new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.TRANSFER_WITH_UUID, - Map.of("server_uuid", serverToTransferTo.toString())), - response -> {}); + Map.of("server_uuid", serverToTransferTo.toString()))); waitingForTransferComplete.put(uuid, future); return future; } public void transferTo(ServerType serverType) { - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, + RedisClient.requestProxy(PLAYER_HANDLER, new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.TRANSFER, - Map.of("type", serverType.toString())), - response -> {}); + Map.of("type", serverType.toString()))); } public void transferToLimbo() { - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, - new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.LIMBO, Map.of()), - response -> {}); + RedisClient.requestProxy(PLAYER_HANDLER, + new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.LIMBO, Map.of())); } public CompletableFuture transferToWithIndication(ServerType serverType) { CompletableFuture future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, + RedisClient.requestProxy(PLAYER_HANDLER, new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.TRANSFER, - Map.of("type", serverType.toString())), - response -> {}); + Map.of("type", serverType.toString()))); waitingForTransferComplete.put(uuid, future); return future; } public CompletableFuture getBankHash() { CompletableFuture future = new CompletableFuture<>(); - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, - new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.BANK_HASH, Map.of()), - response -> { + RedisClient.requestProxy(PLAYER_HANDLER, + new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.BANK_HASH, Map.of())) + .thenAccept(response -> { Object bankHash = response.data().get("bankHash"); future.complete(UUID.fromString((String) bankHash)); }); @@ -131,9 +124,8 @@ public CompletableFuture getBankHash() { } public void refreshCoopData(String datapoint) { - ServerOutboundMessage.sendToProxy(PLAYER_HANDLER, + RedisClient.requestProxy(PLAYER_HANDLER, new PlayerHandlerProtocol.Request(uuid.toString(), PlayerHandlerProtocol.Action.REFRESH_COOP_DATA, - Map.of("datapoint", datapoint)), - response -> {}); + Map.of("datapoint", datapoint))); } } diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayerSet.java b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayerSet.java index 9c0d9d172..8e4895c95 100644 --- a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayerSet.java +++ b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyPlayerSet.java @@ -2,7 +2,6 @@ import lombok.Getter; -import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -15,6 +14,6 @@ public ProxyPlayerSet(List players) { } public List asProxyPlayers() { - return new ArrayList<>(players.stream().map(ProxyPlayer::new).toList()); + return players.stream().map(ProxyPlayer::new).toList(); } } diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyService.java b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyService.java index 4ab62136a..222d53c12 100644 --- a/proxy.api/src/main/java/net/swofty/proxyapi/ProxyService.java +++ b/proxy.api/src/main/java/net/swofty/proxyapi/ProxyService.java @@ -1,48 +1,16 @@ package net.swofty.proxyapi; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.PingProtocolObject; -import net.swofty.proxyapi.redis.ServerOutboundMessage; +import net.swofty.commons.redis.RedisClient; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; public record ProxyService(ServiceType type) { public CompletableFuture isOnline() { - CompletableFuture future = new CompletableFuture<>(); - AtomicBoolean hasReceivedResponse = new AtomicBoolean(false); - - ServerOutboundMessage.sendMessageToService(type, new PingProtocolObject(), - new PingProtocolObject.EmptyMessage(), (s) -> { - future.complete(true); - hasReceivedResponse.set(true); - }); - - CompletableFuture.delayedExecutor(150, TimeUnit.MILLISECONDS) - .execute(() -> { - if (!hasReceivedResponse.get()) { - future.complete(false); - } - }); - - return future; + return RedisClient.isServiceOnline(type); } public CompletableFuture handleRequest(T request) { - ProtocolObject protocolObject = ServerOutboundMessage.protocolObjects.get(request.getClass().getSimpleName()); - - CompletableFuture future = new CompletableFuture<>(); - Thread.startVirtualThread(() -> - ServerOutboundMessage.sendMessageToService( - type, - protocolObject, - request, - (s) -> Thread.startVirtualThread( - () -> future.complete(protocolObject.translateReturnFromString(s)) - ) - )); - return future; + return RedisClient.requestService(type, request); } } diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/redis/ServerOutboundMessage.java b/proxy.api/src/main/java/net/swofty/proxyapi/redis/ServerOutboundMessage.java deleted file mode 100644 index 13c61c008..000000000 --- a/proxy.api/src/main/java/net/swofty/proxyapi/redis/ServerOutboundMessage.java +++ /dev/null @@ -1,136 +0,0 @@ -package net.swofty.proxyapi.redis; - -import net.swofty.commons.ServiceType; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.redis.RedisEnvelope; -import net.swofty.redisapi.api.ChannelRegistry; -import net.swofty.redisapi.api.RedisAPI; -import org.tinylog.Logger; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.function.Consumer; - -public class ServerOutboundMessage { - private static final Map> redisMessageListeners = new HashMap<>(); - public static final Map protocolObjects = new HashMap<>(); - - public static void sendToProxy(ProtocolObject protocol, T request, Consumer response) { - UUID uuid = UUID.randomUUID(); - UUID filterID = UUID.fromString(RedisAPI.getInstance().getFilterId()); - - Consumer consumer = (s) -> { - R typed = protocol.translateReturnFromString(s); - response.accept(typed); - }; - redisMessageListeners.put(uuid, consumer); - - String serialized = protocol.translateToString(request); - RedisAPI.getInstance().publishMessage("proxy", - ChannelRegistry.getFromName(protocol.channel()), - new RedisEnvelope(uuid.toString(), filterID.toString(), serialized).serialize()); - } - - public static void registerToProxyProtocol(ProtocolObject protocol) { - RedisAPI.getInstance().registerChannel(protocol.channel(), (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - UUID uuid = UUID.fromString(envelope.id()); - - redisMessageListeners.get(uuid).accept(envelope.payload()); - redisMessageListeners.remove(uuid); - }); - } - - public static void registerFromProtocolObject(ProtocolObject object) { - String requestTypeName = getRequestTypeName(object); - protocolObjects.put(requestTypeName, object); - - RedisAPI.getInstance().registerChannel(object.channel(), (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - UUID uuid = UUID.fromString(envelope.id()); - String message = envelope.payload(); - - try { - redisMessageListeners.get(uuid).accept(message); - redisMessageListeners.remove(uuid); - } catch (Exception e) { - Logger.error("Failed to handle message from " + uuid + ": " + e.getMessage()); - } - }); - } - - public static void sendMessageToService(ServiceType service, - ProtocolObject specification, - Object rawMessage, - Consumer response) { - UUID requestId = UUID.randomUUID(); - String callbackId = RedisAPI.getInstance().getFilterId(); - if (callbackId == null) return; - - redisMessageListeners.put(requestId, response); - - String message = specification.translateToString(rawMessage); - - RedisAPI.getInstance().publishMessage(service.name(), - ChannelRegistry.getFromName(specification.channel()), - new ServiceProxyRequest(requestId, callbackId, - specification.channel(), message).toJSON().toString()); - } - - public static void sendMessageToServiceFireAndForget(ServiceType service, - ProtocolObject specification, - Object rawMessage) { - UUID requestId = UUID.randomUUID(); - String callback = null; - try { - callback = RedisAPI.getInstance().getFilterId(); - } catch (Exception ignored) { - } - - String message = specification.translateToString(rawMessage); - RedisAPI.getInstance().publishMessage( - service.name(), - ChannelRegistry.getFromName(specification.channel()), - new ServiceProxyRequest( - requestId, - callback != null ? callback : "proxy", - specification.channel(), - message - ).toJSON().toString() - ); - } - - public static void sendMessageToAllServicesFireAndForget(ProtocolObject specification, - Object rawMessage) { - for (ServiceType serviceType : ServiceType.values()) { - sendMessageToServiceFireAndForget(serviceType, specification, rawMessage); - } - } - - private static String getRequestTypeName(ProtocolObject protocolObject) { - Class clazz = protocolObject.getClass(); - Type genericSuperclass = clazz.getGenericSuperclass(); - - if (genericSuperclass instanceof ParameterizedType paramType) { - Type[] typeArguments = paramType.getActualTypeArguments(); - if (typeArguments.length > 0) { - Type firstTypeArg = typeArguments[0]; - if (firstTypeArg instanceof Class) { - return ((Class) firstTypeArg).getSimpleName(); - } else { - return firstTypeArg.getTypeName(); - } - } - } - - throw new IllegalArgumentException("Could not determine the type T for the given ProtocolObject"); - } -} diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/redis/TypedProxyHandler.java b/proxy.api/src/main/java/net/swofty/proxyapi/redis/TypedProxyHandler.java deleted file mode 100644 index e61dc1e5c..000000000 --- a/proxy.api/src/main/java/net/swofty/proxyapi/redis/TypedProxyHandler.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.swofty.proxyapi.redis; - -import net.swofty.commons.protocol.ProtocolObject; - -public interface TypedProxyHandler { - ProtocolObject getProtocol(); - R onMessage(T message); -} diff --git a/proxy.api/src/main/java/net/swofty/proxyapi/redis/TypedServiceHandler.java b/proxy.api/src/main/java/net/swofty/proxyapi/redis/TypedServiceHandler.java deleted file mode 100644 index dbac08ec0..000000000 --- a/proxy.api/src/main/java/net/swofty/proxyapi/redis/TypedServiceHandler.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.swofty.proxyapi.redis; - -import net.swofty.commons.protocol.ServicePushProtocol; - -public interface TypedServiceHandler { - ServicePushProtocol getProtocol(); - R onMessage(T message); -} diff --git a/pvp/src/main/java/net/swofty/pvp/feature/food/ChorusFruitUtil.java b/pvp/src/main/java/net/swofty/pvp/feature/food/ChorusFruitUtil.java index bdeea7cbf..3a43b2b3b 100644 --- a/pvp/src/main/java/net/swofty/pvp/feature/food/ChorusFruitUtil.java +++ b/pvp/src/main/java/net/swofty/pvp/feature/food/ChorusFruitUtil.java @@ -1,5 +1,8 @@ package net.swofty.pvp.feature.food; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.swofty.pvp.utils.ViewUtil; import net.kyori.adventure.sound.Sound; import net.minestom.server.MinecraftServer; @@ -13,7 +16,9 @@ import java.util.concurrent.ThreadLocalRandom; -public class ChorusFruitUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ChorusFruitUtil { + private static boolean randomTeleport(Entity entity, Pos to) { Instance instance = entity.getInstance(); assert instance != null; diff --git a/pvp/src/main/java/net/swofty/pvp/utils/EffectUtil.java b/pvp/src/main/java/net/swofty/pvp/utils/EffectUtil.java index 5fc291377..84e668fb9 100644 --- a/pvp/src/main/java/net/swofty/pvp/utils/EffectUtil.java +++ b/pvp/src/main/java/net/swofty/pvp/utils/EffectUtil.java @@ -1,5 +1,8 @@ package net.swofty.pvp.utils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.minestom.server.network.packet.server.play.WorldEventPacket; import net.minestom.server.worldevent.WorldEvent; import org.jetbrains.annotations.NotNull; @@ -8,7 +11,9 @@ import net.minestom.server.instance.Instance; import net.minestom.server.utils.PacketSendingUtils; -public class EffectUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class EffectUtil { + public static void sendNearby(@NotNull Instance instance, @NotNull WorldEvent effect, int x, int y, int z, int data, double distance, boolean global) { WorldEventPacket packet = new WorldEventPacket(effect.id(), new Pos(x, y, z), data, global); diff --git a/pvp/src/main/java/net/swofty/pvp/utils/EntityUtil.java b/pvp/src/main/java/net/swofty/pvp/utils/EntityUtil.java index fccaebb5b..52c9c65d9 100644 --- a/pvp/src/main/java/net/swofty/pvp/utils/EntityUtil.java +++ b/pvp/src/main/java/net/swofty/pvp/utils/EntityUtil.java @@ -1,5 +1,8 @@ package net.swofty.pvp.utils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import io.sentry.Sentry; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.HoverEvent; @@ -15,7 +18,9 @@ import java.lang.reflect.Field; import java.util.Objects; -public class EntityUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class EntityUtil { + public static void spawnItemAtLocation(Entity entity, ItemStack itemStack, double up) { if (itemStack.isAir()) return; @@ -46,7 +51,8 @@ public static void setLastDamage(LivingEntity livingEntity, Damage lastDamage) { field.setAccessible(true); field.set(livingEntity, lastDamage); } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); + java.util.logging.Logger.getLogger("PVP").log(java.util.logging.Level.SEVERE, + "Failed to set LivingEntity.lastDamage via reflection", e); Sentry.captureException(e); } } diff --git a/pvp/src/main/java/net/swofty/pvp/utils/FluidUtil.java b/pvp/src/main/java/net/swofty/pvp/utils/FluidUtil.java index 5ca86f4de..a7b26eadb 100644 --- a/pvp/src/main/java/net/swofty/pvp/utils/FluidUtil.java +++ b/pvp/src/main/java/net/swofty/pvp/utils/FluidUtil.java @@ -1,5 +1,8 @@ package net.swofty.pvp.utils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; import net.minestom.server.instance.Instance; @@ -8,7 +11,9 @@ import java.util.ArrayList; import java.util.List; -public class FluidUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FluidUtil { + public static int getLevel(Block block) { String levelStr = block.getProperty("level"); if (levelStr == null) return 8; diff --git a/pvp/src/main/java/net/swofty/pvp/utils/ProjectileUtil.java b/pvp/src/main/java/net/swofty/pvp/utils/ProjectileUtil.java index 152ed89cf..ac067a96b 100644 --- a/pvp/src/main/java/net/swofty/pvp/utils/ProjectileUtil.java +++ b/pvp/src/main/java/net/swofty/pvp/utils/ProjectileUtil.java @@ -1,5 +1,8 @@ package net.swofty.pvp.utils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.minestom.server.collision.BoundingBox; import net.minestom.server.collision.CollisionUtils; import net.minestom.server.collision.PhysicsResult; @@ -11,7 +14,9 @@ import org.jetbrains.annotations.Nullable; // Copied from Minestom, added singleCollision parameter and removed velocity update -public class ProjectileUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ProjectileUtil { + public static @NotNull PhysicsResult simulateMovement(@NotNull Pos entityPosition, @NotNull Vec entityVelocityPerTick, @NotNull BoundingBox entityBoundingBox, @NotNull WorldBorder worldBorder, @NotNull Block.Getter blockGetter, boolean entityHasPhysics, diff --git a/pvp/src/main/java/net/swofty/pvp/utils/ViewUtil.java b/pvp/src/main/java/net/swofty/pvp/utils/ViewUtil.java index 43907c3ae..4635fa86b 100644 --- a/pvp/src/main/java/net/swofty/pvp/utils/ViewUtil.java +++ b/pvp/src/main/java/net/swofty/pvp/utils/ViewUtil.java @@ -1,12 +1,17 @@ package net.swofty.pvp.utils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.kyori.adventure.audience.Audience; import net.minestom.server.adventure.audience.PacketGroupingAudience; import net.minestom.server.entity.Entity; import java.util.Collections; -public class ViewUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ViewUtil { + public static Audience viewersAndSelf(Entity origin) { if (origin.getChunk() == null) return Audience.empty(); return origin.getChunk().getViewersAsAudience(); diff --git a/service.api/build.gradle.kts b/service.api/build.gradle.kts index 27981c5ed..d84ecdace 100644 --- a/service.api/build.gradle.kts +++ b/service.api/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.api/src/main/java/net/swofty/service/api/APIService.java b/service.api/src/main/java/net/swofty/service/api/APIService.java index 35fe4f06a..4db4bb334 100644 --- a/service.api/src/main/java/net/swofty/service/api/APIService.java +++ b/service.api/src/main/java/net/swofty/service/api/APIService.java @@ -9,7 +9,7 @@ import net.swofty.service.api.http.APIResponse; import net.swofty.service.api.http.SkyBlockEndpoint; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.generic.data.mongodb.UserDatabase; import org.jetbrains.annotations.Nullable; @@ -140,8 +140,8 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.api.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.api.endpoints", RedisMessageHandler.class).toList(); } } diff --git a/service.api/src/main/java/net/swofty/service/api/endpoints/EndpointAuthenticateCode.java b/service.api/src/main/java/net/swofty/service/api/endpoints/EndpointAuthenticateCode.java index 15e1d7c30..e633d4bbf 100644 --- a/service.api/src/main/java/net/swofty/service/api/endpoints/EndpointAuthenticateCode.java +++ b/service.api/src/main/java/net/swofty/service/api/endpoints/EndpointAuthenticateCode.java @@ -1,29 +1,27 @@ package net.swofty.service.api.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.api.APIAuthenticateCodeProtocolObject; +import net.swofty.commons.protocol.objects.api.APIAuthenticateCodeProtocol; import net.swofty.service.api.APIAdminDatabase; import net.swofty.service.api.APIAdminDatabaseObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.jetbrains.annotations.Nullable; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointAuthenticateCode implements ServiceEndpoint< - APIAuthenticateCodeProtocolObject.AuthenticateCodeMessage, - APIAuthenticateCodeProtocolObject.AuthenticateCodeResponse> { +public class EndpointAuthenticateCode implements RedisMessageHandler< + APIAuthenticateCodeProtocol.AuthenticateCodeMessage, + APIAuthenticateCodeProtocol.AuthenticateCodeResponse> { @Override - public APIAuthenticateCodeProtocolObject associatedProtocolObject() { - return new APIAuthenticateCodeProtocolObject(); + public APIAuthenticateCodeProtocol protocol() { + return new APIAuthenticateCodeProtocol(); } @Override - public APIAuthenticateCodeProtocolObject.AuthenticateCodeResponse onMessage( - ServiceProxyRequest message, - APIAuthenticateCodeProtocolObject.AuthenticateCodeMessage messageObject) { + public APIAuthenticateCodeProtocol.AuthenticateCodeResponse handle(APIAuthenticateCodeProtocol.AuthenticateCodeMessage messageObject, RedisMessageContext context) { @Nullable APIAdminDatabaseObject document = APIAdminDatabase.getFromCode(messageObject.authCode()); if (document == null) { - return new APIAuthenticateCodeProtocolObject.AuthenticateCodeResponse(false, "Authentication failed"); + return new APIAuthenticateCodeProtocol.AuthenticateCodeResponse(false, "Authentication failed"); } document.setAuthenticatorName(messageObject.playerName()); @@ -31,6 +29,6 @@ public APIAuthenticateCodeProtocolObject.AuthenticateCodeResponse onMessage( APIAdminDatabase.replaceOrInsert(document); - return new APIAuthenticateCodeProtocolObject.AuthenticateCodeResponse(true, null); + return new APIAuthenticateCodeProtocol.AuthenticateCodeResponse(true, null); } } diff --git a/service.api/src/main/java/net/swofty/service/api/http/endpoints/LogoutEndpoint.java b/service.api/src/main/java/net/swofty/service/api/http/endpoints/LogoutEndpoint.java index 8f0f9d96d..b99ef39a4 100644 --- a/service.api/src/main/java/net/swofty/service/api/http/endpoints/LogoutEndpoint.java +++ b/service.api/src/main/java/net/swofty/service/api/http/endpoints/LogoutEndpoint.java @@ -27,7 +27,6 @@ public String getPath() { @Override public @Nullable APIResponse handle(Map headers, Request req, Response res) { String sessionId = req.cookie("sessionId"); - System.out.println("Session ID: " + sessionId); if (sessionId == null) { return APIResponse.error("Missing required headers"); diff --git a/service.auctionhouse/build.gradle.kts b/service.auctionhouse/build.gradle.kts index bd49f0610..c464be500 100644 --- a/service.auctionhouse/build.gradle.kts +++ b/service.auctionhouse/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.auctionhouse/src/main/java/net/swofty/service/auction/AuctionService.java b/service.auctionhouse/src/main/java/net/swofty/service/auction/AuctionService.java index 3e558eb52..390689b9a 100644 --- a/service.auctionhouse/src/main/java/net/swofty/service/auction/AuctionService.java +++ b/service.auctionhouse/src/main/java/net/swofty/service/auction/AuctionService.java @@ -3,7 +3,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.config.ConfigProvider; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -25,7 +25,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.auction.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.auction.endpoints", RedisMessageHandler.class).toList(); } } diff --git a/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointAddItem.java b/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointAddItem.java index 3034246f2..03c8bca94 100644 --- a/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointAddItem.java +++ b/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointAddItem.java @@ -2,26 +2,26 @@ import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionItem; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.skyblock.item.UnderstandableSkyBlockItem; -import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocol; import net.swofty.service.auction.AuctionActiveDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.bson.Document; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointAddItem implements ServiceEndpoint< - AuctionAddItemProtocolObject.AuctionAddItemMessage, - AuctionAddItemProtocolObject.AuctionAddItemResponse> { +public class EndpointAddItem implements RedisMessageHandler< + AuctionAddItemProtocol.AuctionAddItemMessage, + AuctionAddItemProtocol.AuctionAddItemResponse> { @Override - public AuctionAddItemProtocolObject associatedProtocolObject() { - return new AuctionAddItemProtocolObject(); + public AuctionAddItemProtocol protocol() { + return new AuctionAddItemProtocol(); } @Override - public AuctionAddItemProtocolObject.AuctionAddItemResponse onMessage(ServiceProxyRequest message, AuctionAddItemProtocolObject.AuctionAddItemMessage messageObject) { + public AuctionAddItemProtocol.AuctionAddItemResponse handle(AuctionAddItemProtocol.AuctionAddItemMessage messageObject, RedisMessageContext context) { AuctionItem auctionItem = messageObject.item(); UnderstandableSkyBlockItem item = auctionItem.getItem(); item.getAttribute("item_type").setValue("HYPERION"); @@ -41,6 +41,6 @@ public AuctionAddItemProtocolObject.AuctionAddItemResponse onMessage(ServiceProx } }); - return new AuctionAddItemProtocolObject.AuctionAddItemResponse(UUID.fromString((String) document.get("_id")), true, null); + return new AuctionAddItemProtocol.AuctionAddItemResponse(UUID.fromString((String) document.get("_id")), true, null); } } diff --git a/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItem.java b/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItem.java index 7b69b8e81..8c99f9536 100644 --- a/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItem.java +++ b/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItem.java @@ -1,26 +1,26 @@ package net.swofty.service.auction.endpoints; import net.swofty.commons.skyblock.auctions.AuctionItem; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocol; import net.swofty.service.auction.AuctionActiveDatabase; import net.swofty.service.auction.AuctionInactiveDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.bson.Document; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointFetchItem implements ServiceEndpoint< - AuctionFetchItemProtocolObject.AuctionFetchItemMessage, - AuctionFetchItemProtocolObject.AuctionFetchItemResponse> { +public class EndpointFetchItem implements RedisMessageHandler< + AuctionFetchItemProtocol.AuctionFetchItemMessage, + AuctionFetchItemProtocol.AuctionFetchItemResponse> { @Override - public AuctionFetchItemProtocolObject associatedProtocolObject() { - return new AuctionFetchItemProtocolObject(); + public AuctionFetchItemProtocol protocol() { + return new AuctionFetchItemProtocol(); } @Override - public AuctionFetchItemProtocolObject.AuctionFetchItemResponse onMessage(ServiceProxyRequest message, AuctionFetchItemProtocolObject.AuctionFetchItemMessage messageObject) { + public AuctionFetchItemProtocol.AuctionFetchItemResponse handle(AuctionFetchItemProtocol.AuctionFetchItemMessage messageObject, RedisMessageContext context) { UUID uuidToFetch = messageObject.uuid(); AuctionItem toReturn = new AuctionItem(); @@ -35,6 +35,6 @@ public AuctionFetchItemProtocolObject.AuctionFetchItemResponse onMessage(Service toReturn = AuctionItem.fromDocument(inactiveItem); } - return new AuctionFetchItemProtocolObject.AuctionFetchItemResponse(toReturn, true, null); + return new AuctionFetchItemProtocol.AuctionFetchItemResponse(toReturn, true, null); } } diff --git a/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItems.java b/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItems.java index 09c5de06c..07ff7d5c7 100644 --- a/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItems.java +++ b/service.auctionhouse/src/main/java/net/swofty/service/auction/endpoints/EndpointFetchItems.java @@ -3,27 +3,27 @@ import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionsFilter; import net.swofty.commons.skyblock.auctions.AuctionsSorting; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemsProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemsProtocol; import net.swofty.service.auction.AuctionService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.commons.skyblock.auctions.AuctionItem; import org.bson.Document; import java.util.ArrayList; import java.util.List; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointFetchItems implements ServiceEndpoint< - AuctionFetchItemsProtocolObject.AuctionFetchItemsMessage, - AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse> { +public class EndpointFetchItems implements RedisMessageHandler< + AuctionFetchItemsProtocol.AuctionFetchItemsMessage, + AuctionFetchItemsProtocol.AuctionFetchItemsResponse> { @Override - public AuctionFetchItemsProtocolObject associatedProtocolObject() { - return new AuctionFetchItemsProtocolObject(); + public AuctionFetchItemsProtocol protocol() { + return new AuctionFetchItemsProtocol(); } @Override - public AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse onMessage(ServiceProxyRequest message, AuctionFetchItemsProtocolObject.AuctionFetchItemsMessage messageObject) { + public AuctionFetchItemsProtocol.AuctionFetchItemsResponse handle(AuctionFetchItemsProtocol.AuctionFetchItemsMessage messageObject, RedisMessageContext context) { AuctionsSorting sorting = messageObject.sorting(); AuctionsFilter filter = messageObject.filter(); AuctionCategories category = messageObject.category(); @@ -31,7 +31,7 @@ public AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse onMessage(Servi List results = AuctionService.cacheService.getAuctions(category.toString(), filter); if (results.isEmpty()) { - return new AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse(new ArrayList<>(), true, null); + return new AuctionFetchItemsProtocol.AuctionFetchItemsResponse(new ArrayList<>(), true, null); } // Sort according to sorting @@ -66,6 +66,6 @@ public AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse onMessage(Servi break; } - return new AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse(results.stream().map(AuctionItem::fromDocument).toList(), true, null); + return new AuctionFetchItemsProtocol.AuctionFetchItemsResponse(results.stream().map(AuctionItem::fromDocument).toList(), true, null); } } diff --git a/service.bazaar/build.gradle.kts b/service.bazaar/build.gradle.kts index 0690ef80e..5476e5cbc 100644 --- a/service.bazaar/build.gradle.kts +++ b/service.bazaar/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" @@ -28,6 +28,8 @@ dependencies { implementation(libs.caffeine) implementation(libs.mongodb.bson) implementation(libs.mongodb.driver.sync) + implementation(libs.tinylog.api) + implementation(libs.tinylog.impl) } application { diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarMarket.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarMarket.java index f441520f7..7028df3a7 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarMarket.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarMarket.java @@ -3,6 +3,7 @@ import net.swofty.commons.skyblock.bazaar.BuyOrderRefundTransaction; import net.swofty.commons.skyblock.bazaar.OrderExpiredBazaarTransaction; import net.swofty.commons.skyblock.bazaar.SuccessfulBazaarTransaction; +import org.tinylog.Logger; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -213,9 +214,8 @@ private void match(String item, tracker.recordPartialFill(qty, actualPrice); } - System.out.println("Buy price was: " + b.originalPrice); - System.out.println("Sell price was: " + s.originalPrice); - System.out.println("Actual price was: " + actualPrice); + Logger.debug("Match — buyPrice={} sellPrice={} actualPrice={}", + b.originalPrice, s.originalPrice, actualPrice); double priceImprovement = (b.originalPrice - actualPrice) * qty; var tx = new SuccessfulBazaarTransaction( item, diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarPropagator.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarPropagator.java index 5a1129861..75fbc3367 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarPropagator.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarPropagator.java @@ -5,7 +5,8 @@ import net.swofty.commons.skyblock.bazaar.BazaarTransaction; import net.swofty.commons.skyblock.bazaar.SuccessfulBazaarTransaction; import net.swofty.commons.skyblock.bazaar.OrderExpiredBazaarTransaction; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.redis.RedisClient; +import org.tinylog.Logger; import java.util.Map; import java.util.UUID; @@ -15,17 +16,17 @@ public class BazaarPropagator { private static final BazaarTransactionPushProtocol PROTOCOL = new BazaarTransactionPushProtocol(); public void propagate(BazaarTransaction tx) { - System.out.println("Propagating transaction " + tx.getClass().getSimpleName()); + Logger.debug("Propagating transaction {}", tx.getClass().getSimpleName()); var request = new BazaarTransactionPushProtocol.Request( tx.getClass().getSimpleName(), tx.toJSON().toString() ); - ServiceToServerManager.sendToAllServers(PROTOCOL, request, 5000) + RedisClient.requestAllServersFromService(PROTOCOL, request, 5000) .thenAccept(responses -> handleServerResponses(tx, responses)) .exceptionally(throwable -> { - System.err.println("Failed to get responses from servers for transaction: " + throwable.getMessage()); + Logger.error(throwable, "Failed to get responses from servers for transaction"); return null; }); } @@ -34,7 +35,7 @@ private void handleServerResponses(BazaarTransaction tx, Map res switch (tx) { case SuccessfulBazaarTransaction success -> handleSuccessfulTransactionResponses(success, responses); case OrderExpiredBazaarTransaction expired -> handleExpiredTransactionResponses(expired, responses); - default -> System.err.println("Unknown transaction type for response handling: " + tx.getClass().getSimpleName()); + default -> Logger.warn("Unknown transaction type for response handling: {}", tx.getClass().getSimpleName()); } } @@ -42,8 +43,7 @@ private void handleSuccessfulTransactionResponses(SuccessfulBazaarTransaction tx boolean buyerHandled = false; boolean sellerHandled = false; - for (Map.Entry entry : responses.entrySet()) { - Response response = entry.getValue(); + for (Response response : responses.values()) { if (response != null && response.success()) { buyerHandled |= response.buyerHandled(); sellerHandled |= response.sellerHandled(); @@ -51,33 +51,32 @@ private void handleSuccessfulTransactionResponses(SuccessfulBazaarTransaction tx } if (!buyerHandled) { - System.out.println("Buyer " + tx.buyer() + " not handled by any server - storing as pending"); + Logger.info("Buyer {} not handled by any server — storing as pending", tx.buyer()); PendingTransactionsDatabase.storePendingTransaction(tx.buyer(), tx.buyerProfile(), tx); } if (!sellerHandled) { - System.out.println("Seller " + tx.seller() + " not handled by any server - storing as pending"); + Logger.info("Seller {} not handled by any server — storing as pending", tx.seller()); PendingTransactionsDatabase.storePendingTransaction(tx.seller(), tx.sellerProfile(), tx); } - System.out.println("Transaction handled - Buyer: " + buyerHandled + ", Seller: " + sellerHandled); + Logger.debug("Transaction handled — buyer={}, seller={}", buyerHandled, sellerHandled); } private void handleExpiredTransactionResponses(OrderExpiredBazaarTransaction tx, Map responses) { boolean ownerHandled = false; - for (Map.Entry entry : responses.entrySet()) { - Response response = entry.getValue(); + for (Response response : responses.values()) { if (response != null && response.success()) { ownerHandled |= response.buyerHandled(); } } if (!ownerHandled) { - System.out.println("Owner " + tx.owner() + " not handled by any server - storing as pending"); + Logger.info("Owner {} not handled by any server — storing as pending", tx.owner()); PendingTransactionsDatabase.storePendingTransaction(tx.owner(), tx.ownerProfile(), tx); } - System.out.println("Expired order handled - Owner: " + ownerHandled); + Logger.debug("Expired order handled — owner={}", ownerHandled); } -} \ No newline at end of file +} diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarService.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarService.java index 00b07feb5..db6d0f007 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarService.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/BazaarService.java @@ -3,7 +3,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.config.ConfigProvider; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -27,7 +27,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.bazaar.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.bazaar.endpoints", RedisMessageHandler.class).toList(); } } \ No newline at end of file diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/OrderDatabase.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/OrderDatabase.java index 1fb6be851..f9d4137d8 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/OrderDatabase.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/OrderDatabase.java @@ -4,6 +4,7 @@ import com.mongodb.MongoClientSettings; import com.mongodb.client.*; import org.bson.Document; +import org.tinylog.Logger; public class OrderDatabase { public static MongoClient client; @@ -20,7 +21,7 @@ public static void connect(String connectionString) { database = client.getDatabase("Minestom"); ordersCollection = database.getCollection("bazaarOrders"); - System.out.println("Connected to MongoDB for bazaar orders"); + Logger.info("Connected to MongoDB for bazaar orders"); } public static void disconnect() { diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/PendingTransactionsDatabase.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/PendingTransactionsDatabase.java index 08f95d1f1..876648d4d 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/PendingTransactionsDatabase.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/PendingTransactionsDatabase.java @@ -6,6 +6,7 @@ import net.swofty.commons.skyblock.bazaar.OrderExpiredBazaarTransaction; import net.swofty.commons.skyblock.bazaar.SuccessfulBazaarTransaction; import org.bson.Document; +import org.tinylog.Logger; import java.time.Instant; import java.util.ArrayList; @@ -30,7 +31,7 @@ public static void storePendingTransaction(UUID playerUuid, UUID profileUuid, Ba .append("processed", false); OrderDatabase.database.getCollection("pendingTransactions").insertOne(doc); - System.out.println("Stored pending transaction for player " + playerUuid + " on profile " + profileUuid); + Logger.info("Stored pending transaction for player {} on profile {}", playerUuid, profileUuid); } /** @@ -63,7 +64,7 @@ public static List getPendingTransactions(UUID playerUuid, U )); } } catch (Exception e) { - System.err.println("Failed to parse pending transaction: " + e.getMessage()); + Logger.error(e, "Failed to parse pending transaction"); } } @@ -105,12 +106,12 @@ private static BazaarTransaction parseTransactionFromDocument(String type, Docum null, null, null, null, null, 0, 0, null ).fromJSON(jsonData); default -> { - System.err.println("Unknown pending transaction type: " + type); + Logger.warn("Unknown pending transaction type: {}", type); yield null; } }; } catch (Exception e) { - System.err.println("Error parsing pending transaction: " + e.getMessage()); + Logger.error(e, "Error parsing pending transaction"); return null; } } diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarBuyOrder.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarBuyOrder.java index b672e7e06..6e4f49717 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarBuyOrder.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarBuyOrder.java @@ -1,25 +1,24 @@ package net.swofty.service.bazaar.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.bazaar.BazaarBuyProtocolObject; +import net.swofty.commons.protocol.objects.bazaar.BazaarBuyProtocol; import net.swofty.service.bazaar.BazaarMarket; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import org.tinylog.Logger; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointBazaarBuyOrder implements ServiceEndpoint< - BazaarBuyProtocolObject.BazaarBuyMessage, - BazaarBuyProtocolObject.BazaarBuyResponse> { +public class EndpointBazaarBuyOrder implements RedisMessageHandler< + BazaarBuyProtocol.BazaarBuyMessage, + BazaarBuyProtocol.BazaarBuyResponse> { @Override - public BazaarBuyProtocolObject associatedProtocolObject() { - return new BazaarBuyProtocolObject(); + public BazaarBuyProtocol protocol() { + return new BazaarBuyProtocol(); } @Override - public BazaarBuyProtocolObject.BazaarBuyResponse onMessage( - ServiceProxyRequest message, - BazaarBuyProtocolObject.BazaarBuyMessage msg) { + public BazaarBuyProtocol.BazaarBuyResponse handle(BazaarBuyProtocol.BazaarBuyMessage msg, RedisMessageContext context) { String itemName = msg.itemName(); UUID playerUUID = msg.playerUUID(); @@ -29,12 +28,12 @@ public BazaarBuyProtocolObject.BazaarBuyResponse onMessage( try { BazaarMarket.get().submitBuy(itemName, playerUUID, profileUUID, price, amount); - System.out.println("Buy order submitted for " + itemName + " by " + playerUUID - + " (profile: " + profileUUID + ") - Price: " + price + ", Amount: " + amount); - return new BazaarBuyProtocolObject.BazaarBuyResponse(true, null); + Logger.info("Buy order submitted for {} by {} (profile: {}) — price={}, amount={}", + itemName, playerUUID, profileUUID, price, amount); + return new BazaarBuyProtocol.BazaarBuyResponse(true, null); } catch (Exception e) { - System.err.println("Failed to submit buy order: " + e.getMessage()); - return new BazaarBuyProtocolObject.BazaarBuyResponse(false, "Buy order failed"); + Logger.error(e, "Failed to submit buy order for {} by {}", itemName, playerUUID); + return new BazaarBuyProtocol.BazaarBuyResponse(false, "Buy order failed"); } } } diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarSellOrder.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarSellOrder.java index 5323923ef..8ba8afece 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarSellOrder.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointBazaarSellOrder.java @@ -1,26 +1,25 @@ package net.swofty.service.bazaar.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.bazaar.BazaarSellProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.bazaar.BazaarSellProtocol; import net.swofty.service.bazaar.BazaarMarket; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import org.tinylog.Logger; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointBazaarSellOrder implements ServiceEndpoint< - BazaarSellProtocolObject.BazaarSellMessage, - BazaarSellProtocolObject.BazaarSellResponse> { +public class EndpointBazaarSellOrder implements RedisMessageHandler< + BazaarSellProtocol.BazaarSellMessage, + BazaarSellProtocol.BazaarSellResponse> { @Override - public ProtocolObject associatedProtocolObject() { - return new BazaarSellProtocolObject(); + public RedisProtocol protocol() { + return new BazaarSellProtocol(); } @Override - public BazaarSellProtocolObject.BazaarSellResponse onMessage( - ServiceProxyRequest message, - BazaarSellProtocolObject.BazaarSellMessage msg) { + public BazaarSellProtocol.BazaarSellResponse handle(BazaarSellProtocol.BazaarSellMessage msg, RedisMessageContext context) { String itemName = msg.itemName(); UUID playerUUID = msg.playerUUID(); @@ -30,12 +29,12 @@ public BazaarSellProtocolObject.BazaarSellResponse onMessage( try { BazaarMarket.get().submitSell(itemName, playerUUID, profileUUID, price, amount); - System.out.println("Sell order submitted for " + itemName + " by " + playerUUID - + " (profile: " + profileUUID + ") - Price: " + price + ", Amount: " + amount); - return new BazaarSellProtocolObject.BazaarSellResponse(true, null); + Logger.info("Sell order submitted for {} by {} (profile: {}) — price={}, amount={}", + itemName, playerUUID, profileUUID, price, amount); + return new BazaarSellProtocol.BazaarSellResponse(true, null); } catch (Exception e) { - System.err.println("Failed to submit sell order: " + e.getMessage()); - return new BazaarSellProtocolObject.BazaarSellResponse(false, "Sell order failed"); + Logger.error(e, "Failed to submit sell order for {} by {}", itemName, playerUUID); + return new BazaarSellProtocol.BazaarSellResponse(false, "Sell order failed"); } } } diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointCancelBazaarOrder.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointCancelBazaarOrder.java index 84b9e2fde..65dbc6882 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointCancelBazaarOrder.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointCancelBazaarOrder.java @@ -1,24 +1,25 @@ package net.swofty.service.bazaar.endpoints; import com.mongodb.client.model.Filters; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.bazaar.BazaarCancelProtocolObject; -import net.swofty.commons.protocol.objects.bazaar.BazaarCancelProtocolObject.CancelMessage; -import net.swofty.commons.protocol.objects.bazaar.BazaarCancelProtocolObject.CancelResponse; +import net.swofty.commons.protocol.objects.bazaar.BazaarCancelProtocol; +import net.swofty.commons.protocol.objects.bazaar.BazaarCancelProtocol.CancelMessage; +import net.swofty.commons.protocol.objects.bazaar.BazaarCancelProtocol.CancelResponse; import net.swofty.service.bazaar.BazaarMarket; import net.swofty.service.bazaar.OrderDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import org.tinylog.Logger; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointCancelBazaarOrder implements ServiceEndpoint< +public class EndpointCancelBazaarOrder implements RedisMessageHandler< CancelMessage, CancelResponse> { @Override - public BazaarCancelProtocolObject associatedProtocolObject() { - return new BazaarCancelProtocolObject(); + public BazaarCancelProtocol protocol() { + return new BazaarCancelProtocol(); } @Override - public CancelResponse onMessage(ServiceProxyRequest _msg, CancelMessage msg) { + public CancelResponse handle(CancelMessage msg, RedisMessageContext context) { var result = OrderDatabase.ordersCollection.deleteOne( Filters.and( Filters.eq("_id", msg.orderId().toString()), @@ -27,7 +28,8 @@ public CancelResponse onMessage(ServiceProxyRequest _msg, CancelMessage msg) { ) ); BazaarMarket.get().submitDelete(msg.orderId(), msg.playerUuid(), msg.profileUuid()); - System.out.println("Deleted order " + msg.orderId() + " for player " + msg.playerUuid() + " and profile " + msg.profileUuid()); + Logger.info("Deleted order {} for player {} and profile {}", + msg.orderId(), msg.playerUuid(), msg.profileUuid()); boolean success = result.getDeletedCount() > 0; return new CancelResponse(success, success ? null : "Cancel failed"); diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetBazaarItem.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetBazaarItem.java index a4b670d8e..a8aae0dc3 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetBazaarItem.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetBazaarItem.java @@ -1,27 +1,25 @@ package net.swofty.service.bazaar.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetItemProtocolObject; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetItemProtocolObject.OrderRecord; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetItemProtocol; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetItemProtocol.OrderRecord; import net.swofty.service.bazaar.BazaarMarket; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; import java.util.stream.Collectors; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointGetBazaarItem implements ServiceEndpoint< - BazaarGetItemProtocolObject.BazaarGetItemMessage, - BazaarGetItemProtocolObject.BazaarGetItemResponse> { +public class EndpointGetBazaarItem implements RedisMessageHandler< + BazaarGetItemProtocol.BazaarGetItemMessage, + BazaarGetItemProtocol.BazaarGetItemResponse> { @Override - public BazaarGetItemProtocolObject associatedProtocolObject() { - return new BazaarGetItemProtocolObject(); + public BazaarGetItemProtocol protocol() { + return new BazaarGetItemProtocol(); } @Override - public BazaarGetItemProtocolObject.BazaarGetItemResponse onMessage( - ServiceProxyRequest message, - BazaarGetItemProtocolObject.BazaarGetItemMessage msg) { + public BazaarGetItemProtocol.BazaarGetItemResponse handle(BazaarGetItemProtocol.BazaarGetItemMessage msg, RedisMessageContext context) { String itemName = msg.itemName(); @@ -48,7 +46,7 @@ public BazaarGetItemProtocolObject.BazaarGetItemResponse onMessage( )) .collect(Collectors.toList()); - return new BazaarGetItemProtocolObject.BazaarGetItemResponse( + return new BazaarGetItemProtocol.BazaarGetItemResponse( itemName, buyOrderRecords, sellOrderRecords, diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingOrders.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingOrders.java index afb92d37f..6040162fc 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingOrders.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingOrders.java @@ -1,30 +1,28 @@ package net.swofty.service.bazaar.endpoints; import com.mongodb.client.model.Filters; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingOrdersProtocolObject; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingOrdersProtocolObject.PendingOrder; -import net.swofty.commons.impl.ServiceProxyRequest; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingOrdersProtocol; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingOrdersProtocol.PendingOrder; import net.swofty.service.bazaar.OrderDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.bson.Document; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointGetPendingOrders implements ServiceEndpoint< - BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersMessage, - BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersResponse> { +public class EndpointGetPendingOrders implements RedisMessageHandler< + BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersMessage, + BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersResponse> { @Override - public BazaarGetPendingOrdersProtocolObject associatedProtocolObject() { - return new BazaarGetPendingOrdersProtocolObject(); + public BazaarGetPendingOrdersProtocol protocol() { + return new BazaarGetPendingOrdersProtocol(); } @Override - public BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersResponse onMessage( - ServiceProxyRequest message, - BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersMessage msg) { + public BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersResponse handle(BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersMessage msg, RedisMessageContext context) { UUID player = msg.playerUUID(); UUID profile = msg.profileUUID(); @@ -48,6 +46,6 @@ public BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersResponse onMes )); } - return new BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersResponse(out, true, null); + return new BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersResponse(out, true, null); } } diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingTransactions.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingTransactions.java index 2242beb45..bd6918583 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingTransactions.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointGetPendingTransactions.java @@ -1,29 +1,27 @@ package net.swofty.service.bazaar.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocolObject; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocolObject.BazaarGetPendingTransactionsMessage; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocolObject.BazaarGetPendingTransactionsResponse; -import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocolObject.PendingTransactionInfo; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocol; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocol.BazaarGetPendingTransactionsMessage; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocol.BazaarGetPendingTransactionsResponse; +import net.swofty.commons.protocol.objects.bazaar.BazaarGetPendingTransactionsProtocol.PendingTransactionInfo; import net.swofty.service.bazaar.PendingTransactionsDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import org.tinylog.Logger; import java.util.List; -import java.util.stream.Collectors; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointGetPendingTransactions implements ServiceEndpoint< +public class EndpointGetPendingTransactions implements RedisMessageHandler< BazaarGetPendingTransactionsMessage, BazaarGetPendingTransactionsResponse> { @Override - public BazaarGetPendingTransactionsProtocolObject associatedProtocolObject() { - return new BazaarGetPendingTransactionsProtocolObject(); + public BazaarGetPendingTransactionsProtocol protocol() { + return new BazaarGetPendingTransactionsProtocol(); } @Override - public BazaarGetPendingTransactionsResponse onMessage( - ServiceProxyRequest message, - BazaarGetPendingTransactionsMessage msg) { + public BazaarGetPendingTransactionsResponse handle(BazaarGetPendingTransactionsMessage msg, RedisMessageContext context) { List pendingTransactions = PendingTransactionsDatabase.getPendingTransactions(msg.playerUUID(), msg.profileUUID()); @@ -35,11 +33,10 @@ public BazaarGetPendingTransactionsResponse onMessage( pt.getTransaction().toJSON().toMap(), pt.getCreatedAt() )) - .collect(Collectors.toList()); + .toList(); - System.out.println("Retrieved " + transactionInfos.size() + - " pending transactions for player " + msg.playerUUID() + - " on profile " + msg.profileUUID()); + Logger.debug("Retrieved {} pending transactions for player {} on profile {}", + transactionInfos.size(), msg.playerUUID(), msg.profileUUID()); return new BazaarGetPendingTransactionsResponse(transactionInfos, true, null); } diff --git a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointProcessPendingTransactions.java b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointProcessPendingTransactions.java index 1f78b46e6..d0afc207b 100644 --- a/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointProcessPendingTransactions.java +++ b/service.bazaar/src/main/java/net/swofty/service/bazaar/endpoints/EndpointProcessPendingTransactions.java @@ -1,43 +1,42 @@ package net.swofty.service.bazaar.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.bazaar.BazaarProcessPendingTransactionsProtocolObject; -import net.swofty.commons.protocol.objects.bazaar.BazaarProcessPendingTransactionsProtocolObject.BazaarProcessPendingTransactionsMessage; -import net.swofty.commons.protocol.objects.bazaar.BazaarProcessPendingTransactionsProtocolObject.BazaarProcessPendingTransactionsResponse; +import net.swofty.commons.protocol.objects.bazaar.BazaarProcessPendingTransactionsProtocol; +import net.swofty.commons.protocol.objects.bazaar.BazaarProcessPendingTransactionsProtocol.BazaarProcessPendingTransactionsMessage; +import net.swofty.commons.protocol.objects.bazaar.BazaarProcessPendingTransactionsProtocol.BazaarProcessPendingTransactionsResponse; import net.swofty.service.bazaar.PendingTransactionsDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointProcessPendingTransactions implements ServiceEndpoint< +public class EndpointProcessPendingTransactions implements RedisMessageHandler< BazaarProcessPendingTransactionsMessage, BazaarProcessPendingTransactionsResponse> { @Override - public BazaarProcessPendingTransactionsProtocolObject associatedProtocolObject() { - return new BazaarProcessPendingTransactionsProtocolObject(); + public BazaarProcessPendingTransactionsProtocol protocol() { + return new BazaarProcessPendingTransactionsProtocol(); } @Override - public BazaarProcessPendingTransactionsResponse onMessage( - ServiceProxyRequest message, - BazaarProcessPendingTransactionsMessage msg) { + public BazaarProcessPendingTransactionsResponse handle(BazaarProcessPendingTransactionsMessage msg, RedisMessageContext context) { List successfulIds = new ArrayList<>(); List failedIds = new ArrayList<>(); - System.out.println("Processing " + msg.transactionIds().size() + - " pending transactions for player " + msg.playerUUID()); + Logger.info("Processing {} pending transactions for player {}", + msg.transactionIds().size(), msg.playerUUID()); for (String transactionId : msg.transactionIds()) { try { PendingTransactionsDatabase.markTransactionProcessed(transactionId); successfulIds.add(transactionId); - System.out.println("Successfully processed pending transaction: " + transactionId); + Logger.debug("Successfully processed pending transaction: {}", transactionId); } catch (Exception e) { failedIds.add(transactionId); - System.err.println("Failed to process pending transaction " + transactionId + ": " + e.getMessage()); + Logger.error(e, "Failed to process pending transaction {}", transactionId); } } @@ -45,7 +44,7 @@ public BazaarProcessPendingTransactionsResponse onMessage( try { PendingTransactionsDatabase.cleanupProcessedTransactions(); } catch (Exception e) { - System.err.println("Failed to cleanup processed transactions: " + e.getMessage()); + Logger.error(e, "Failed to cleanup processed transactions"); } } diff --git a/service.darkauction/build.gradle.kts b/service.darkauction/build.gradle.kts index 44275925b..b39805d44 100644 --- a/service.darkauction/build.gradle.kts +++ b/service.darkauction/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("io.github.goooler.shadow") version "8.1.8" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionScheduler.java b/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionScheduler.java index d824be5c4..43e0f320e 100644 --- a/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionScheduler.java +++ b/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionScheduler.java @@ -3,7 +3,7 @@ import net.swofty.commons.skyblock.auctions.DarkAuctionPhase; import net.swofty.commons.protocol.objects.darkauction.DarkAuctionEventProtocol; import net.swofty.commons.protocol.objects.darkauction.DarkAuctionEventPushProtocol; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.redis.RedisClient; import org.tinylog.Logger; import java.util.ArrayList; @@ -177,7 +177,7 @@ private static void broadcastEvent(DarkAuctionEventProtocol.EventType type, Dark Logger.debug("Broadcasting {} event for auction {}", type, auction.getAuctionId()); - ServiceToServerManager.sendToAllServers( + RedisClient.requestAllServersFromService( new DarkAuctionEventPushProtocol(), request, 5000 diff --git a/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionService.java b/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionService.java index 4d705382e..b03276ddb 100644 --- a/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionService.java +++ b/service.darkauction/src/main/java/net/swofty/service/darkauction/DarkAuctionService.java @@ -2,7 +2,7 @@ import net.swofty.commons.ServiceType; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.List; @@ -24,8 +24,8 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.darkauction.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.darkauction.endpoints", RedisMessageHandler.class).toList(); } public static DarkAuctionState getCurrentAuction() { diff --git a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointGetAuctionState.java b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointGetAuctionState.java index 2ca9495d8..ab2396296 100644 --- a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointGetAuctionState.java +++ b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointGetAuctionState.java @@ -1,27 +1,25 @@ package net.swofty.service.darkauction.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.darkauction.GetAuctionStateProtocol; import net.swofty.service.darkauction.DarkAuctionService; import net.swofty.service.darkauction.DarkAuctionState; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointGetAuctionState implements ServiceEndpoint< +public class EndpointGetAuctionState implements RedisMessageHandler< GetAuctionStateProtocol.GetAuctionStateMessage, GetAuctionStateProtocol.GetAuctionStateResponse> { @Override - public ProtocolObject associatedProtocolObject() { + public RedisProtocol protocol() { return new GetAuctionStateProtocol(); } @Override - public GetAuctionStateProtocol.GetAuctionStateResponse onMessage( - ServiceProxyRequest request, - GetAuctionStateProtocol.GetAuctionStateMessage msg) { + public GetAuctionStateProtocol.GetAuctionStateResponse handle(GetAuctionStateProtocol.GetAuctionStateMessage msg, RedisMessageContext context) { DarkAuctionState auction = DarkAuctionService.getCurrentAuction(); diff --git a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlaceBid.java b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlaceBid.java index d853af378..55013886b 100644 --- a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlaceBid.java +++ b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlaceBid.java @@ -1,30 +1,28 @@ package net.swofty.service.darkauction.endpoints; import net.swofty.commons.skyblock.auctions.DarkAuctionPhase; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.darkauction.PlaceBidProtocol; import net.swofty.service.darkauction.DarkAuctionScheduler; import net.swofty.service.darkauction.DarkAuctionService; import net.swofty.service.darkauction.DarkAuctionState; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointPlaceBid implements ServiceEndpoint< +public class EndpointPlaceBid implements RedisMessageHandler< PlaceBidProtocol.PlaceBidMessage, PlaceBidProtocol.PlaceBidResponse> { @Override - public ProtocolObject associatedProtocolObject() { + public RedisProtocol protocol() { return new PlaceBidProtocol(); } @Override - public PlaceBidProtocol.PlaceBidResponse onMessage( - ServiceProxyRequest request, - PlaceBidProtocol.PlaceBidMessage msg) { + public PlaceBidProtocol.PlaceBidResponse handle(PlaceBidProtocol.PlaceBidMessage msg, RedisMessageContext context) { DarkAuctionState auction = DarkAuctionService.getCurrentAuction(); diff --git a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlayerLeftAuction.java b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlayerLeftAuction.java index 6dab429b1..da9b4d0bb 100644 --- a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlayerLeftAuction.java +++ b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointPlayerLeftAuction.java @@ -1,30 +1,28 @@ package net.swofty.service.darkauction.endpoints; import net.swofty.commons.skyblock.auctions.DarkAuctionPhase; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.darkauction.PlayerLeftAuctionProtocol; import net.swofty.service.darkauction.DarkAuctionScheduler; import net.swofty.service.darkauction.DarkAuctionService; import net.swofty.service.darkauction.DarkAuctionState; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointPlayerLeftAuction implements ServiceEndpoint< +public class EndpointPlayerLeftAuction implements RedisMessageHandler< PlayerLeftAuctionProtocol.PlayerLeftMessage, PlayerLeftAuctionProtocol.PlayerLeftResponse> { @Override - public ProtocolObject associatedProtocolObject() { + public RedisProtocol protocol() { return new PlayerLeftAuctionProtocol(); } @Override - public PlayerLeftAuctionProtocol.PlayerLeftResponse onMessage( - ServiceProxyRequest request, - PlayerLeftAuctionProtocol.PlayerLeftMessage msg) { + public PlayerLeftAuctionProtocol.PlayerLeftResponse handle(PlayerLeftAuctionProtocol.PlayerLeftMessage msg, RedisMessageContext context) { DarkAuctionState auction = DarkAuctionService.getCurrentAuction(); diff --git a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointTriggerAuction.java b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointTriggerAuction.java index c2a8e4540..17aa6404b 100644 --- a/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointTriggerAuction.java +++ b/service.darkauction/src/main/java/net/swofty/service/darkauction/endpoints/EndpointTriggerAuction.java @@ -1,26 +1,24 @@ package net.swofty.service.darkauction.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.darkauction.TriggerDarkAuctionProtocol; import net.swofty.service.darkauction.DarkAuctionScheduler; import net.swofty.service.darkauction.DarkAuctionService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointTriggerAuction implements ServiceEndpoint< +public class EndpointTriggerAuction implements RedisMessageHandler< TriggerDarkAuctionProtocol.TriggerMessage, TriggerDarkAuctionProtocol.TriggerResponse> { @Override - public ProtocolObject associatedProtocolObject() { + public RedisProtocol protocol() { return new TriggerDarkAuctionProtocol(); } @Override - public TriggerDarkAuctionProtocol.TriggerResponse onMessage( - ServiceProxyRequest request, - TriggerDarkAuctionProtocol.TriggerMessage msg) { + public TriggerDarkAuctionProtocol.TriggerResponse handle(TriggerDarkAuctionProtocol.TriggerMessage msg, RedisMessageContext context) { Logger.info("Received trigger request - calendarTime: {}, forced: {}", msg.calendarTime(), msg.forced()); diff --git a/service.datamutex/build.gradle.kts b/service.datamutex/build.gradle.kts index f55e9726f..e982cdabe 100644 --- a/service.datamutex/build.gradle.kts +++ b/service.datamutex/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.datamutex/src/main/java/net/swofty/service/datamutex/DataLockManager.java b/service.datamutex/src/main/java/net/swofty/service/datamutex/DataLockManager.java index 1d02c7e51..841fb67d4 100644 --- a/service.datamutex/src/main/java/net/swofty/service/datamutex/DataLockManager.java +++ b/service.datamutex/src/main/java/net/swofty/service/datamutex/DataLockManager.java @@ -6,59 +6,45 @@ public class DataLockManager { private static final Map activeLocks = new ConcurrentHashMap<>(); - private static final long LOCK_TIMEOUT = 30000; // 30 seconds - - public static class LockInfo { - public final UUID lockId; - public final long timestamp; - public final String requesterId; - - public LockInfo(UUID lockId, long timestamp, String requesterId) { - this.lockId = lockId; - this.timestamp = timestamp; - this.requesterId = requesterId; - } + private static final long LOCK_TIMEOUT = 30_000; // 30 seconds + public record LockInfo(UUID lockId, long timestamp, String requesterId) { public boolean isExpired() { return (System.currentTimeMillis() - timestamp) > LOCK_TIMEOUT; } } /** - * Attempts to acquire a lock for the given key + * Attempts to acquire a lock for the given key. */ public static boolean acquireLock(String lockKey, String requesterId) { LockInfo existingLock = activeLocks.get(lockKey); - // Clean up expired locks if (existingLock != null && existingLock.isExpired()) { activeLocks.remove(lockKey); existingLock = null; } - // Check if already locked by someone else - if (existingLock != null && !existingLock.requesterId.equals(requesterId)) { + if (existingLock != null && !existingLock.requesterId().equals(requesterId)) { return false; } - // Acquire or renew lock - UUID lockId = UUID.randomUUID(); - activeLocks.put(lockKey, new LockInfo(lockId, System.currentTimeMillis(), requesterId)); + activeLocks.put(lockKey, new LockInfo(UUID.randomUUID(), System.currentTimeMillis(), requesterId)); return true; } /** - * Releases a lock for the given key + * Releases a lock for the given key. */ public static void releaseLock(String lockKey, String requesterId) { LockInfo lock = activeLocks.get(lockKey); - if (lock != null && lock.requesterId.equals(requesterId)) { + if (lock != null && lock.requesterId().equals(requesterId)) { activeLocks.remove(lockKey); } } /** - * Checks if a key is currently locked + * Checks if a key is currently locked. */ public static boolean isLocked(String lockKey) { LockInfo lock = activeLocks.get(lockKey); @@ -73,7 +59,7 @@ public static boolean isLocked(String lockKey) { } /** - * Gets the lock info for a key (or null if not locked) + * Gets the lock info for a key, or null if not locked. */ public static LockInfo getLockInfo(String lockKey) { LockInfo lock = activeLocks.get(lockKey); @@ -85,9 +71,9 @@ public static LockInfo getLockInfo(String lockKey) { } /** - * Cleans up all expired locks + * Cleans up all expired locks. */ public static void cleanupExpiredLocks() { activeLocks.entrySet().removeIf(entry -> entry.getValue().isExpired()); } -} \ No newline at end of file +} diff --git a/service.datamutex/src/main/java/net/swofty/service/datamutex/DataMutexService.java b/service.datamutex/src/main/java/net/swofty/service/datamutex/DataMutexService.java index dbcbfddd4..ceea2af84 100644 --- a/service.datamutex/src/main/java/net/swofty/service/datamutex/DataMutexService.java +++ b/service.datamutex/src/main/java/net/swofty/service/datamutex/DataMutexService.java @@ -5,7 +5,7 @@ import net.swofty.service.datamutex.endpoints.UnlockDataEndpoint; import net.swofty.service.datamutex.endpoints.UpdateSynchronizedDataEndpoint; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -16,7 +16,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { + public List getEndpoints() { return List.of( new SynchronizeDataEndpoint(), new UpdateSynchronizedDataEndpoint(), diff --git a/service.datamutex/src/main/java/net/swofty/service/datamutex/LockCleanupTask.java b/service.datamutex/src/main/java/net/swofty/service/datamutex/LockCleanupTask.java index 9ada9d40c..e7c0f73a1 100644 --- a/service.datamutex/src/main/java/net/swofty/service/datamutex/LockCleanupTask.java +++ b/service.datamutex/src/main/java/net/swofty/service/datamutex/LockCleanupTask.java @@ -1,5 +1,7 @@ package net.swofty.service.datamutex; +import org.tinylog.Logger; + import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -13,7 +15,7 @@ public static void startCleanupTask() { try { DataLockManager.cleanupExpiredLocks(); } catch (Exception e) { - System.err.println("Error during lock cleanup: " + e.getMessage()); + Logger.error(e, "Error during lock cleanup"); } }, 10, 10, TimeUnit.SECONDS); } diff --git a/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/SynchronizeDataEndpoint.java b/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/SynchronizeDataEndpoint.java index e3f113250..2662b3357 100644 --- a/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/SynchronizeDataEndpoint.java +++ b/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/SynchronizeDataEndpoint.java @@ -2,135 +2,108 @@ import org.tinylog.Logger; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.protocol.objects.data.GetPlayerDataPushProtocol; import net.swofty.commons.protocol.objects.data.LockPlayerDataPushProtocol; -import net.swofty.commons.protocol.objects.datamutex.SynchronizeDataProtocolObject; +import net.swofty.commons.protocol.objects.data.UnlockPlayerDataPushProtocol; +import net.swofty.commons.protocol.objects.datamutex.SynchronizeDataProtocol; import net.swofty.service.datamutex.DataLockManager; -import net.swofty.service.generic.redis.ServiceEndpoint; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisClient; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import net.swofty.commons.redis.RedisMessageContext; -public class SynchronizeDataEndpoint implements ServiceEndpoint< - SynchronizeDataProtocolObject.SynchronizeDataRequest, - SynchronizeDataProtocolObject.SynchronizeDataResponse> { +public class SynchronizeDataEndpoint implements RedisMessageHandler< + SynchronizeDataProtocol.SynchronizeDataRequest, + SynchronizeDataProtocol.SynchronizeDataResponse> { @Override - public SynchronizeDataProtocolObject associatedProtocolObject() { - return new SynchronizeDataProtocolObject(); + public SynchronizeDataProtocol protocol() { + return new SynchronizeDataProtocol(); } @Override - public SynchronizeDataProtocolObject.SynchronizeDataResponse onMessage( - ServiceProxyRequest request, - SynchronizeDataProtocolObject.SynchronizeDataRequest messageObject) { - - System.out.println("=== SYNC ENDPOINT DEBUG ==="); - System.out.println("Received sync request from: " + request.getRequestServer()); - System.out.println("Player UUID: " + messageObject.playerUUID()); - System.out.println("Data Key: " + messageObject.dataKey()); - System.out.println("Server UUIDs: " + messageObject.serverUUIDs()); + public SynchronizeDataProtocol.SynchronizeDataResponse handle(SynchronizeDataProtocol.SynchronizeDataRequest messageObject, RedisMessageContext context) { List serverUUIDs = messageObject.serverUUIDs(); UUID playerUUID = messageObject.playerUUID(); String dataKey = messageObject.dataKey(); - String requesterId = request.getRequestServer(); - + String requesterId = context.origin().id(); String lockKey = playerUUID + ":" + dataKey; - System.out.println("Lock key: " + lockKey); + + Logger.debug("sync: requester={} player={} key={} servers={} lockKey={}", + requesterId, playerUUID, dataKey, serverUUIDs, lockKey); try { - // Step 1: Acquire service-level lock - System.out.println("Attempting to acquire service lock..."); if (!DataLockManager.acquireLock(lockKey, requesterId)) { - System.out.println("Failed to acquire service lock - already locked"); - return new SynchronizeDataProtocolObject.SynchronizeDataResponse( + Logger.debug("sync: service lock {} already held", lockKey); + return new SynchronizeDataProtocol.SynchronizeDataResponse( false, null, "Data is currently locked by another operation"); } - System.out.println("Service lock acquired successfully"); - // Step 2: Lock data on all servers - System.out.println("Locking data on servers: " + serverUUIDs); - Map lockResults = ServiceToServerManager - .lockPlayerData(serverUUIDs, playerUUID, dataKey) + Map lockResults = RedisClient + .requestServersFromService(serverUUIDs, new LockPlayerDataPushProtocol(), + new LockPlayerDataPushProtocol.Request(playerUUID, dataKey)) .get(); - System.out.println("Lock results: " + lockResults); - boolean allLocked = lockResults.values().stream() .allMatch(LockPlayerDataPushProtocol.Response::success); - System.out.println("All servers locked: " + allLocked); - if (!allLocked) { - // Release service lock and any server locks we did get - System.out.println("Not all servers locked, cleaning up..."); + Logger.debug("sync: failed to lock all servers (results={}), rolling back", + lockResults); DataLockManager.releaseLock(lockKey, requesterId); - ServiceToServerManager.unlockPlayerData(serverUUIDs, playerUUID, dataKey); - - return new SynchronizeDataProtocolObject.SynchronizeDataResponse( + RedisClient.requestServersFromService(serverUUIDs, new UnlockPlayerDataPushProtocol(), + new UnlockPlayerDataPushProtocol.Request(playerUUID, dataKey)); + return new SynchronizeDataProtocol.SynchronizeDataResponse( false, null, "Failed to acquire locks on all servers"); } - // Step 3: Get data from all servers - System.out.println("Getting data from all servers..."); - Map> dataFutures = new java.util.HashMap<>(); + Map> dataFutures = new HashMap<>(); for (UUID serverUUID : serverUUIDs) { dataFutures.put(serverUUID, - ServiceToServerManager.getPlayerData(serverUUID, playerUUID, dataKey)); + RedisClient.requestServerFromService(serverUUID, new GetPlayerDataPushProtocol(), + new GetPlayerDataPushProtocol.Request(playerUUID, dataKey))); } - Map allData = new java.util.HashMap<>(); + Map allData = new HashMap<>(); for (Map.Entry> entry : dataFutures.entrySet()) { allData.put(entry.getKey(), entry.getValue().get()); } - System.out.println("Received data from servers: " + allData); - GetPlayerDataPushProtocol.Response latestData = null; long latestTimestamp = 0; - for (GetPlayerDataPushProtocol.Response data : allData.values()) { - System.out.println("Processing data response: " + data); - if (data.success()) { - long timestamp = data.timestamp(); - System.out.println("Data timestamp: " + timestamp); - if (timestamp > latestTimestamp) { - latestTimestamp = timestamp; - latestData = data; - } + if (data.success() && data.timestamp() > latestTimestamp) { + latestTimestamp = data.timestamp(); + latestData = data; } } if (latestData == null) { - System.out.println("No valid data found, cleaning up..."); + Logger.debug("sync: no valid data among {} responses, rolling back", allData.size()); DataLockManager.releaseLock(lockKey, requesterId); - ServiceToServerManager.unlockPlayerData(serverUUIDs, playerUUID, dataKey); - - return new SynchronizeDataProtocolObject.SynchronizeDataResponse( + RedisClient.requestServersFromService(serverUUIDs, new UnlockPlayerDataPushProtocol(), + new UnlockPlayerDataPushProtocol.Request(playerUUID, dataKey)); + return new SynchronizeDataProtocol.SynchronizeDataResponse( false, null, "No valid data found on any server"); } - System.out.println("Using latest data with timestamp: " + latestTimestamp); - System.out.println("Latest data content: " + latestData.data()); - - return new SynchronizeDataProtocolObject.SynchronizeDataResponse( + Logger.debug("sync: settled on timestamp={}", latestTimestamp); + return new SynchronizeDataProtocol.SynchronizeDataResponse( true, latestData.data(), null); } catch (Exception e) { - System.out.println("Exception in sync endpoint: " + e.getMessage()); - Logger.error(e, "Error occurred in data mutex endpoint"); - - // Always unlock on error + Logger.error(e, "Error occurred in data mutex endpoint (lockKey={})", lockKey); DataLockManager.releaseLock(lockKey, requesterId); - ServiceToServerManager.unlockPlayerData(serverUUIDs, playerUUID, dataKey); - - return new SynchronizeDataProtocolObject.SynchronizeDataResponse( + RedisClient.requestServersFromService(serverUUIDs, new UnlockPlayerDataPushProtocol(), + new UnlockPlayerDataPushProtocol.Request(playerUUID, dataKey)); + return new SynchronizeDataProtocol.SynchronizeDataResponse( false, null, "Error during synchronization: " + e.getMessage()); } } -} \ No newline at end of file +} diff --git a/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UnlockDataEndpoint.java b/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UnlockDataEndpoint.java index 527623380..4c6b667cc 100644 --- a/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UnlockDataEndpoint.java +++ b/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UnlockDataEndpoint.java @@ -1,32 +1,32 @@ package net.swofty.service.datamutex.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.datamutex.UnlockDataProtocolObject; +import net.swofty.commons.protocol.objects.data.UnlockPlayerDataPushProtocol; +import net.swofty.commons.protocol.objects.datamutex.UnlockDataProtocol; import net.swofty.service.datamutex.DataLockManager; -import net.swofty.service.generic.redis.ServiceEndpoint; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisClient; +import org.tinylog.Logger; import java.util.List; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class UnlockDataEndpoint implements ServiceEndpoint< - UnlockDataProtocolObject.UnlockDataRequest, - UnlockDataProtocolObject.UnlockDataResponse> { +public class UnlockDataEndpoint implements RedisMessageHandler< + UnlockDataProtocol.UnlockDataRequest, + UnlockDataProtocol.UnlockDataResponse> { @Override - public UnlockDataProtocolObject associatedProtocolObject() { - return new UnlockDataProtocolObject(); + public UnlockDataProtocol protocol() { + return new UnlockDataProtocol(); } @Override - public UnlockDataProtocolObject.UnlockDataResponse onMessage( - ServiceProxyRequest request, - UnlockDataProtocolObject.UnlockDataRequest messageObject) { + public UnlockDataProtocol.UnlockDataResponse handle(UnlockDataProtocol.UnlockDataRequest messageObject, RedisMessageContext context) { List serverUUIDs = messageObject.serverUUIDs(); UUID playerUUID = messageObject.playerUUID(); String dataKey = messageObject.dataKey(); - String requesterId = request.getRequestServer(); + String requesterId = context.origin().id(); String lockKey = playerUUID + ":" + dataKey; @@ -34,26 +34,25 @@ public UnlockDataProtocolObject.UnlockDataResponse onMessage( // Release service-level lock DataLockManager.releaseLock(lockKey, requesterId); - ServiceToServerManager.unlockPlayerData(serverUUIDs, playerUUID, dataKey) - .thenAccept(results -> { - results.forEach((serverUUID, response) -> { - if (!response.success()) { - System.err.println("Failed to unlock data on server " + serverUUID + - " for player " + playerUUID + ", dataKey: " + dataKey); - } - }); - }) + RedisClient.requestServersFromService(serverUUIDs, new UnlockPlayerDataPushProtocol(), + new UnlockPlayerDataPushProtocol.Request(playerUUID, dataKey)) + .thenAccept(results -> results.forEach((serverUUID, response) -> { + if (!response.success()) { + Logger.warn("Failed to unlock data on server {} for player {}, dataKey: {}", + serverUUID, playerUUID, dataKey); + } + })) .exceptionally(throwable -> { - System.err.println("Error unlocking data on servers: " + throwable.getMessage()); + Logger.error(throwable, "Error unlocking data on servers"); return null; }); - return new UnlockDataProtocolObject.UnlockDataResponse( + return new UnlockDataProtocol.UnlockDataResponse( true, null); } catch (Exception e) { - return new UnlockDataProtocolObject.UnlockDataResponse( + return new UnlockDataProtocol.UnlockDataResponse( false, "Error during unlock: " + e.getMessage()); } } -} \ No newline at end of file +} diff --git a/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UpdateSynchronizedDataEndpoint.java b/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UpdateSynchronizedDataEndpoint.java index 74b033404..b2563b3f8 100644 --- a/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UpdateSynchronizedDataEndpoint.java +++ b/service.datamutex/src/main/java/net/swofty/service/datamutex/endpoints/UpdateSynchronizedDataEndpoint.java @@ -1,104 +1,83 @@ -// Replace your UpdateSynchronizedDataEndpoint with this debug version package net.swofty.service.datamutex.endpoints; import org.tinylog.Logger; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.protocol.objects.data.UpdatePlayerDataPushProtocol; -import net.swofty.commons.protocol.objects.datamutex.UpdateSynchronizedDataProtocolObject; +import net.swofty.commons.protocol.objects.data.UnlockPlayerDataPushProtocol; +import net.swofty.commons.protocol.objects.datamutex.UpdateSynchronizedDataProtocol; import net.swofty.service.datamutex.DataLockManager; -import net.swofty.service.generic.redis.ServiceEndpoint; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisClient; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import net.swofty.commons.redis.RedisMessageContext; -public class UpdateSynchronizedDataEndpoint implements ServiceEndpoint< - UpdateSynchronizedDataProtocolObject.UpdateDataRequest, - UpdateSynchronizedDataProtocolObject.UpdateDataResponse> { +public class UpdateSynchronizedDataEndpoint implements RedisMessageHandler< + UpdateSynchronizedDataProtocol.UpdateDataRequest, + UpdateSynchronizedDataProtocol.UpdateDataResponse> { @Override - public UpdateSynchronizedDataProtocolObject associatedProtocolObject() { - return new UpdateSynchronizedDataProtocolObject(); + public UpdateSynchronizedDataProtocol protocol() { + return new UpdateSynchronizedDataProtocol(); } @Override - public UpdateSynchronizedDataProtocolObject.UpdateDataResponse onMessage( - ServiceProxyRequest request, - UpdateSynchronizedDataProtocolObject.UpdateDataRequest messageObject) { - - System.out.println("=== UPDATE ENDPOINT DEBUG ==="); - System.out.println("Received update request from: " + request.getRequestServer()); - System.out.println("Player UUID: " + messageObject.playerUUID()); - System.out.println("Data Key: " + messageObject.dataKey()); - System.out.println("Server UUIDs: " + messageObject.serverUUIDs()); - System.out.println("New Data Length: " + messageObject.newData().length() + " chars"); + public UpdateSynchronizedDataProtocol.UpdateDataResponse handle(UpdateSynchronizedDataProtocol.UpdateDataRequest messageObject, RedisMessageContext context) { List serverUUIDs = messageObject.serverUUIDs(); UUID playerUUID = messageObject.playerUUID(); String dataKey = messageObject.dataKey(); String newData = messageObject.newData(); - String requesterId = request.getRequestServer(); - + String requesterId = context.origin().id(); String lockKey = playerUUID + ":" + dataKey; - System.out.println("Lock key: " + lockKey); + + Logger.debug("update: requester={} player={} key={} servers={} bytes={} lockKey={}", + requesterId, playerUUID, dataKey, serverUUIDs, newData.length(), lockKey); try { - // Verify we still hold the lock - System.out.println("Verifying service lock..."); DataLockManager.LockInfo lockInfo = DataLockManager.getLockInfo(lockKey); - if (lockInfo == null || !lockInfo.requesterId.equals(requesterId)) { - System.out.println("Lock verification failed - lockInfo: " + lockInfo + ", requesterId: " + requesterId); - return new UpdateSynchronizedDataProtocolObject.UpdateDataResponse( + if (lockInfo == null || !lockInfo.requesterId().equals(requesterId)) { + Logger.debug("update: lock check failed (held by {})", + lockInfo == null ? "" : lockInfo.requesterId()); + return new UpdateSynchronizedDataProtocol.UpdateDataResponse( false, "Lock has expired or is held by another requester"); } - System.out.println("Service lock verified successfully"); - System.out.println("Updating data on servers: " + serverUUIDs); - Map> updateFutures = new java.util.HashMap<>(); + Map> updateFutures = new HashMap<>(); for (UUID serverUUID : serverUUIDs) { - System.out.println("Sending update to server " + serverUUID); - updateFutures.put(serverUUID, - ServiceToServerManager.updatePlayerData(serverUUID, playerUUID, dataKey, newData)); + RedisClient.requestServerFromService(serverUUID, new UpdatePlayerDataPushProtocol(), + new UpdatePlayerDataPushProtocol.Request(playerUUID, dataKey, newData))); } - System.out.println("Waiting for update responses..."); - Map updateResults = new java.util.HashMap<>(); + Map updateResults = new HashMap<>(); for (Map.Entry> entry : updateFutures.entrySet()) { - UpdatePlayerDataPushProtocol.Response result = entry.getValue().get(); - updateResults.put(entry.getKey(), result); - System.out.println("Update result from " + entry.getKey() + ": " + result); + updateResults.put(entry.getKey(), entry.getValue().get()); } boolean allUpdated = updateResults.values().stream() .allMatch(UpdatePlayerDataPushProtocol.Response::success); - System.out.println("All servers updated successfully: " + allUpdated); - if (!allUpdated) { - System.out.println("Some updates failed, returning error"); - return new UpdateSynchronizedDataProtocolObject.UpdateDataResponse( + Logger.warn("update: partial failure (results={})", updateResults); + return new UpdateSynchronizedDataProtocol.UpdateDataResponse( false, "Failed to update data on all servers"); } - System.out.println("All updates successful!"); - return new UpdateSynchronizedDataProtocolObject.UpdateDataResponse( - true, null); + return new UpdateSynchronizedDataProtocol.UpdateDataResponse(true, null); } catch (Exception e) { - System.out.println("Exception in update endpoint: " + e.getMessage()); - Logger.error(e, "Error occurred in data mutex endpoint"); - - return new UpdateSynchronizedDataProtocolObject.UpdateDataResponse( + Logger.error(e, "Error occurred in data mutex update endpoint (lockKey={})", lockKey); + return new UpdateSynchronizedDataProtocol.UpdateDataResponse( false, "Error during data update: " + e.getMessage()); } finally { - // Always release locks when done - System.out.println("Releasing locks in finally block..."); DataLockManager.releaseLock(lockKey, requesterId); - ServiceToServerManager.unlockPlayerData(serverUUIDs, playerUUID, dataKey); + RedisClient.requestServersFromService(serverUUIDs, new UnlockPlayerDataPushProtocol(), + new UnlockPlayerDataPushProtocol.Request(playerUUID, dataKey)); } } -} \ No newline at end of file +} diff --git a/service.elections/build.gradle.kts b/service.elections/build.gradle.kts index 4ec8e0379..c135db3c6 100644 --- a/service.elections/build.gradle.kts +++ b/service.elections/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.1" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" @@ -28,10 +28,10 @@ dependencies { implementation("com.github.ben-manes.caffeine:caffeine:3.2.3") implementation("org.tinylog:tinylog-api:2.7.0") implementation("org.tinylog:tinylog-impl:2.7.0") - implementation("com.google.code.gson:gson:2.11.0") + implementation("com.google.code.gson:gson:2.13.2") implementation("org.mongodb:bson:5.6.2") implementation("org.mongodb:mongodb-driver-sync:5.6.2") - implementation("redis.clients:jedis:7.2.0") + implementation("redis.clients:jedis:7.4.1") } application { diff --git a/service.elections/src/main/java/net/swofty/service/election/ElectionService.java b/service.elections/src/main/java/net/swofty/service/election/ElectionService.java index ba20b9026..7541c7c61 100644 --- a/service.elections/src/main/java/net/swofty/service/election/ElectionService.java +++ b/service.elections/src/main/java/net/swofty/service/election/ElectionService.java @@ -3,7 +3,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.config.ConfigProvider; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -21,7 +21,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.election.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.election.endpoints", RedisMessageHandler.class).toList(); } } diff --git a/service.elections/src/main/java/net/swofty/service/election/endpoints/CastVoteEndpoint.java b/service.elections/src/main/java/net/swofty/service/election/endpoints/CastVoteEndpoint.java index e1bee4dc1..658d6e8c3 100644 --- a/service.elections/src/main/java/net/swofty/service/election/endpoints/CastVoteEndpoint.java +++ b/service.elections/src/main/java/net/swofty/service/election/endpoints/CastVoteEndpoint.java @@ -1,54 +1,52 @@ package net.swofty.service.election.endpoints; import com.google.gson.Gson; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.election.CastVoteProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.election.CastVoteProtocol; import net.swofty.service.election.ElectionDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.List; import java.util.Map; +import net.swofty.commons.redis.RedisMessageContext; -public class CastVoteEndpoint implements ServiceEndpoint - { +public class CastVoteEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new CastVoteProtocolObject(); + public RedisProtocol protocol() { + return new CastVoteProtocol(); } @Override @SuppressWarnings("unchecked") - public CastVoteProtocolObject.CastVoteResponse onMessage( - ServiceProxyRequest message, - CastVoteProtocolObject.CastVoteMessage messageObject) { + public CastVoteProtocol.CastVoteResponse handle(CastVoteProtocol.CastVoteMessage messageObject, RedisMessageContext context) { try { String rawData = ElectionDatabase.loadElectionData(); if (rawData == null) { - return new CastVoteProtocolObject.CastVoteResponse(false, null, "Vote failed"); + return new CastVoteProtocol.CastVoteResponse(false, null, "Vote failed"); } Map data = new Gson().fromJson(rawData, Map.class); Boolean electionOpen = (Boolean) data.get("electionOpen"); if (electionOpen == null || !electionOpen) { - return new CastVoteProtocolObject.CastVoteResponse(false, null, "Vote failed"); + return new CastVoteProtocol.CastVoteResponse(false, null, "Vote failed"); } int electionYear = ((Number) data.get("electionYear")).intValue(); List> candidates = (List>) data.get("candidates"); if (candidates == null) { - return new CastVoteProtocolObject.CastVoteResponse(false, null, "Vote failed"); + return new CastVoteProtocol.CastVoteResponse(false, null, "Vote failed"); } boolean validCandidate = candidates.stream() .anyMatch(c -> messageObject.candidateName().equals(c.get("mayorName"))); if (!validCandidate) { - return new CastVoteProtocolObject.CastVoteResponse(false, null, "Vote failed"); + return new CastVoteProtocol.CastVoteResponse(false, null, "Vote failed"); } ElectionDatabase.castVote( @@ -58,10 +56,10 @@ public CastVoteProtocolObject.CastVoteResponse onMessage( ); Map tallies = ElectionDatabase.getTallies(electionYear); - return new CastVoteProtocolObject.CastVoteResponse(true, tallies, null); + return new CastVoteProtocol.CastVoteResponse(true, tallies, null); } catch (Exception e) { Logger.error(e, "Failed to cast vote"); - return new CastVoteProtocolObject.CastVoteResponse(false, null, "Vote failed"); + return new CastVoteProtocol.CastVoteResponse(false, null, "Vote failed"); } } } diff --git a/service.elections/src/main/java/net/swofty/service/election/endpoints/GetCandidatesEndpoint.java b/service.elections/src/main/java/net/swofty/service/election/endpoints/GetCandidatesEndpoint.java index 52b043171..9df3ec42f 100644 --- a/service.elections/src/main/java/net/swofty/service/election/endpoints/GetCandidatesEndpoint.java +++ b/service.elections/src/main/java/net/swofty/service/election/endpoints/GetCandidatesEndpoint.java @@ -1,70 +1,68 @@ package net.swofty.service.election.endpoints; import com.google.gson.Gson; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.election.GetCandidatesProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.election.GetCandidatesProtocol; import net.swofty.service.election.ElectionDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; import java.util.Map; +import net.swofty.commons.redis.RedisMessageContext; -public class GetCandidatesEndpoint implements ServiceEndpoint - { +public class GetCandidatesEndpoint implements RedisMessageHandler + { private static final Gson GSON = new Gson(); @Override - public ProtocolObject associatedProtocolObject() { - return new GetCandidatesProtocolObject(); + public RedisProtocol protocol() { + return new GetCandidatesProtocol(); } @Override @SuppressWarnings("unchecked") - public GetCandidatesProtocolObject.GetCandidatesResponse onMessage( - ServiceProxyRequest message, - GetCandidatesProtocolObject.GetCandidatesMessage messageObject) { + public GetCandidatesProtocol.GetCandidatesResponse handle(GetCandidatesProtocol.GetCandidatesMessage messageObject, RedisMessageContext context) { try { String rawData = ElectionDatabase.loadElectionData(); if (rawData == null) { - return new GetCandidatesProtocolObject.GetCandidatesResponse(false, List.of(), true, null); + return new GetCandidatesProtocol.GetCandidatesResponse(false, List.of(), true, null); } Map data = GSON.fromJson(rawData, Map.class); Boolean electionOpen = (Boolean) data.get("electionOpen"); if (electionOpen == null || !electionOpen) { - return new GetCandidatesProtocolObject.GetCandidatesResponse(false, List.of(), true, null); + return new GetCandidatesProtocol.GetCandidatesResponse(false, List.of(), true, null); } int electionYear = ((Number) data.get("electionYear")).intValue(); List> candidates = (List>) data.get("candidates"); if (candidates == null || candidates.isEmpty()) { - return new GetCandidatesProtocolObject.GetCandidatesResponse(true, List.of(), true, null); + return new GetCandidatesProtocol.GetCandidatesResponse(true, List.of(), true, null); } Map tallies = ElectionDatabase.getTallies(electionYear); long totalVotes = tallies.values().stream().mapToLong(Long::longValue).sum(); - List infos = new ArrayList<>(); + List infos = new ArrayList<>(); for (Map c : candidates) { String name = (String) c.get("mayorName"); List perks = (List) c.get("activePerks"); if (perks == null) perks = List.of(); long voteCount = tallies.getOrDefault(name, 0L); double pct = totalVotes > 0 ? (voteCount * 100.0) / totalVotes : 0; - infos.add(new GetCandidatesProtocolObject.CandidateInfo(name, perks, voteCount, pct)); + infos.add(new GetCandidatesProtocol.CandidateInfo(name, perks, voteCount, pct)); } - return new GetCandidatesProtocolObject.GetCandidatesResponse(true, infos, true, null); + return new GetCandidatesProtocol.GetCandidatesResponse(true, infos, true, null); } catch (Exception e) { Logger.error(e, "Failed to get candidates"); - return new GetCandidatesProtocolObject.GetCandidatesResponse(false, List.of(), true, null); + return new GetCandidatesProtocol.GetCandidatesResponse(false, List.of(), true, null); } } } diff --git a/service.elections/src/main/java/net/swofty/service/election/endpoints/GetElectionDataEndpoint.java b/service.elections/src/main/java/net/swofty/service/election/endpoints/GetElectionDataEndpoint.java index ff1107d1e..acae98839 100644 --- a/service.elections/src/main/java/net/swofty/service/election/endpoints/GetElectionDataEndpoint.java +++ b/service.elections/src/main/java/net/swofty/service/election/endpoints/GetElectionDataEndpoint.java @@ -1,36 +1,34 @@ package net.swofty.service.election.endpoints; import com.google.gson.Gson; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.election.GetElectionDataProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.election.GetElectionDataProtocol; import net.swofty.service.election.ElectionDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.List; import java.util.Map; +import net.swofty.commons.redis.RedisMessageContext; -public class GetElectionDataEndpoint implements ServiceEndpoint - { +public class GetElectionDataEndpoint implements RedisMessageHandler + { private static final Gson GSON = new Gson(); @Override - public ProtocolObject associatedProtocolObject() { - return new GetElectionDataProtocolObject(); + public RedisProtocol protocol() { + return new GetElectionDataProtocol(); } @Override @SuppressWarnings("unchecked") - public GetElectionDataProtocolObject.GetElectionDataResponse onMessage( - ServiceProxyRequest message, - GetElectionDataProtocolObject.GetElectionDataMessage messageObject) { + public GetElectionDataProtocol.GetElectionDataResponse handle(GetElectionDataProtocol.GetElectionDataMessage messageObject, RedisMessageContext context) { String data = ElectionDatabase.loadElectionData(); if (data == null) { - return new GetElectionDataProtocolObject.GetElectionDataResponse(false, null, true, null); + return new GetElectionDataProtocol.GetElectionDataResponse(false, null, true, null); } try { @@ -45,10 +43,10 @@ public GetElectionDataProtocolObject.GetElectionDataResponse onMessage( parsed.put("voteTallies", tallies); } - return new GetElectionDataProtocolObject.GetElectionDataResponse(true, GSON.toJson(parsed), true, null); + return new GetElectionDataProtocol.GetElectionDataResponse(true, GSON.toJson(parsed), true, null); } catch (Exception e) { Logger.error(e, "Failed to parse election data"); - return new GetElectionDataProtocolObject.GetElectionDataResponse(false, null, true, null); + return new GetElectionDataProtocol.GetElectionDataResponse(false, null, true, null); } } } diff --git a/service.elections/src/main/java/net/swofty/service/election/endpoints/GetPlayerVoteEndpoint.java b/service.elections/src/main/java/net/swofty/service/election/endpoints/GetPlayerVoteEndpoint.java index 31ac3814e..a807cc711 100644 --- a/service.elections/src/main/java/net/swofty/service/election/endpoints/GetPlayerVoteEndpoint.java +++ b/service.elections/src/main/java/net/swofty/service/election/endpoints/GetPlayerVoteEndpoint.java @@ -1,52 +1,50 @@ package net.swofty.service.election.endpoints; import com.google.gson.Gson; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.election.GetPlayerVoteProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.election.GetPlayerVoteProtocol; import net.swofty.service.election.ElectionDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.Map; +import net.swofty.commons.redis.RedisMessageContext; -public class GetPlayerVoteEndpoint implements ServiceEndpoint - { +public class GetPlayerVoteEndpoint implements RedisMessageHandler + { private static final Gson GSON = new Gson(); @Override - public ProtocolObject associatedProtocolObject() { - return new GetPlayerVoteProtocolObject(); + public RedisProtocol protocol() { + return new GetPlayerVoteProtocol(); } @Override @SuppressWarnings("unchecked") - public GetPlayerVoteProtocolObject.GetPlayerVoteResponse onMessage( - ServiceProxyRequest message, - GetPlayerVoteProtocolObject.GetPlayerVoteMessage messageObject) { + public GetPlayerVoteProtocol.GetPlayerVoteResponse handle(GetPlayerVoteProtocol.GetPlayerVoteMessage messageObject, RedisMessageContext context) { try { String rawData = ElectionDatabase.loadElectionData(); if (rawData == null) { - return new GetPlayerVoteProtocolObject.GetPlayerVoteResponse(null, true, null); + return new GetPlayerVoteProtocol.GetPlayerVoteResponse(null, true, null); } Map data = GSON.fromJson(rawData, Map.class); Number yearNum = (Number) data.get("electionYear"); if (yearNum == null) { - return new GetPlayerVoteProtocolObject.GetPlayerVoteResponse(null, true, null); + return new GetPlayerVoteProtocol.GetPlayerVoteResponse(null, true, null); } String vote = ElectionDatabase.getPlayerVote( messageObject.accountId().toString(), yearNum.intValue() ); - return new GetPlayerVoteProtocolObject.GetPlayerVoteResponse(vote, true, null); + return new GetPlayerVoteProtocol.GetPlayerVoteResponse(vote, true, null); } catch (Exception e) { Logger.error(e, "Failed to get player vote"); - return new GetPlayerVoteProtocolObject.GetPlayerVoteResponse(null, true, null); + return new GetPlayerVoteProtocol.GetPlayerVoteResponse(null, true, null); } } } diff --git a/service.elections/src/main/java/net/swofty/service/election/endpoints/ResolveElectionEndpoint.java b/service.elections/src/main/java/net/swofty/service/election/endpoints/ResolveElectionEndpoint.java index 863d89f68..2ec2ffac6 100644 --- a/service.elections/src/main/java/net/swofty/service/election/endpoints/ResolveElectionEndpoint.java +++ b/service.elections/src/main/java/net/swofty/service/election/endpoints/ResolveElectionEndpoint.java @@ -1,11 +1,10 @@ package net.swofty.service.election.endpoints; import com.google.gson.Gson; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.election.ResolveElectionProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.election.ResolveElectionProtocol; import net.swofty.service.election.ElectionDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.ArrayList; @@ -13,30 +12,29 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; +import net.swofty.commons.redis.RedisMessageContext; -public class ResolveElectionEndpoint implements ServiceEndpoint - { +public class ResolveElectionEndpoint implements RedisMessageHandler + { private static final Gson GSON = new Gson(); private static final List SPECIAL_MAYORS = List.of("SCORPIUS", "DERPY", "JERRY"); @Override - public ProtocolObject associatedProtocolObject() { - return new ResolveElectionProtocolObject(); + public RedisProtocol protocol() { + return new ResolveElectionProtocol(); } @Override @SuppressWarnings("unchecked") - public ResolveElectionProtocolObject.ResolveElectionResponse onMessage( - ServiceProxyRequest message, - ResolveElectionProtocolObject.ResolveElectionMessage messageObject) { + public ResolveElectionProtocol.ResolveElectionResponse handle(ResolveElectionProtocol.ResolveElectionMessage messageObject, RedisMessageContext context) { try { String rawData = ElectionDatabase.loadElectionData(); if (rawData == null) { - return new ResolveElectionProtocolObject.ResolveElectionResponse(false, null, true, null); + return new ResolveElectionProtocol.ResolveElectionResponse(false, null, true, null); } Map data = GSON.fromJson(rawData, Map.class); @@ -44,7 +42,7 @@ public ResolveElectionProtocolObject.ResolveElectionResponse onMessage( if (electionOpen == null || !electionOpen) { data.remove("votes"); - return new ResolveElectionProtocolObject.ResolveElectionResponse(false, GSON.toJson(data), true, null); + return new ResolveElectionProtocol.ResolveElectionResponse(false, GSON.toJson(data), true, null); } int electionYear = messageObject.year(); @@ -62,7 +60,7 @@ public ResolveElectionProtocolObject.ResolveElectionResponse onMessage( sorted.sort((a, b) -> Long.compare(b.getValue(), a.getValue())); if (sorted.isEmpty()) { - return new ResolveElectionProtocolObject.ResolveElectionResponse(false, GSON.toJson(data), true, null); + return new ResolveElectionProtocol.ResolveElectionResponse(false, GSON.toJson(data), true, null); } long topVotes = sorted.getFirst().getValue(); @@ -154,10 +152,10 @@ public ResolveElectionProtocolObject.ResolveElectionResponse onMessage( ElectionDatabase.saveElectionData(GSON.toJson(data)); - return new ResolveElectionProtocolObject.ResolveElectionResponse(true, GSON.toJson(data), true, null); + return new ResolveElectionProtocol.ResolveElectionResponse(true, GSON.toJson(data), true, null); } catch (Exception e) { Logger.error(e, "Failed to resolve election"); - return new ResolveElectionProtocolObject.ResolveElectionResponse(false, null, true, null); + return new ResolveElectionProtocol.ResolveElectionResponse(false, null, true, null); } } diff --git a/service.elections/src/main/java/net/swofty/service/election/endpoints/StartElectionEndpoint.java b/service.elections/src/main/java/net/swofty/service/election/endpoints/StartElectionEndpoint.java index dc4d3008d..9b541ce78 100644 --- a/service.elections/src/main/java/net/swofty/service/election/endpoints/StartElectionEndpoint.java +++ b/service.elections/src/main/java/net/swofty/service/election/endpoints/StartElectionEndpoint.java @@ -1,34 +1,32 @@ package net.swofty.service.election.endpoints; import com.google.gson.Gson; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.election.StartElectionProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.election.StartElectionProtocol; import net.swofty.service.election.ElectionDatabase; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; import java.util.Map; +import net.swofty.commons.redis.RedisMessageContext; -public class StartElectionEndpoint implements ServiceEndpoint - { +public class StartElectionEndpoint implements RedisMessageHandler + { private static final Gson GSON = new Gson(); @Override - public ProtocolObject associatedProtocolObject() { - return new StartElectionProtocolObject(); + public RedisProtocol protocol() { + return new StartElectionProtocol(); } @Override @SuppressWarnings("unchecked") - public StartElectionProtocolObject.StartElectionResponse onMessage( - ServiceProxyRequest message, - StartElectionProtocolObject.StartElectionMessage messageObject) { + public StartElectionProtocol.StartElectionResponse handle(StartElectionProtocol.StartElectionMessage messageObject, RedisMessageContext context) { try { String rawData = ElectionDatabase.loadElectionData(); @@ -42,7 +40,7 @@ public StartElectionProtocolObject.StartElectionResponse onMessage( Map tallies = ElectionDatabase.getTallies(messageObject.year()); existing.put("voteTallies", tallies); existing.remove("votes"); - return new StartElectionProtocolObject.StartElectionResponse(false, GSON.toJson(existing), true, null); + return new StartElectionProtocol.StartElectionResponse(false, GSON.toJson(existing), true, null); } } @@ -62,10 +60,10 @@ public StartElectionProtocolObject.StartElectionResponse onMessage( ElectionDatabase.initTallies(messageObject.year(), candidateNames); electionData.remove("votes"); - return new StartElectionProtocolObject.StartElectionResponse(true, GSON.toJson(electionData), true, null); + return new StartElectionProtocol.StartElectionResponse(true, GSON.toJson(electionData), true, null); } catch (Exception e) { Logger.error(e, "Failed to start election"); - return new StartElectionProtocolObject.StartElectionResponse(false, null, true, null); + return new StartElectionProtocol.StartElectionResponse(false, null, true, null); } } } diff --git a/service.friend/build.gradle.kts b/service.friend/build.gradle.kts index ee385ed64..d0ef5349f 100644 --- a/service.friend/build.gradle.kts +++ b/service.friend/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.friend/src/main/java/net/swofty/service/friend/FriendCache.java b/service.friend/src/main/java/net/swofty/service/friend/FriendCache.java index 5cd5ee6a8..e49031d10 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/FriendCache.java +++ b/service.friend/src/main/java/net/swofty/service/friend/FriendCache.java @@ -7,7 +7,7 @@ import net.swofty.commons.friend.events.response.*; import net.swofty.commons.protocol.objects.friend.FriendEventPushProtocol; import net.swofty.commons.protocol.objects.messaging.SendMessagePushProtocol; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.redis.RedisClient; import org.bson.Document; import org.tinylog.Logger; @@ -496,7 +496,7 @@ private static void persistFriendData(UUID playerUuid) { } private static void sendEvent(FriendEvent event) { - ServiceToServerManager.sendToAllServers( + RedisClient.requestAllServersFromService( new FriendEventPushProtocol(), new FriendEventPushProtocol.Request( event.getClass().getSimpleName(), @@ -512,7 +512,7 @@ private static void sendErrorToPlayer(UUID playerUUID, String message) { } private static void sendMessageToPlayer(UUID playerUUID, String message) { - ServiceToServerManager.sendToAllServers( + RedisClient.requestAllServersFromService( new SendMessagePushProtocol(), new SendMessagePushProtocol.Request(playerUUID, message), 300 diff --git a/service.friend/src/main/java/net/swofty/service/friend/FriendService.java b/service.friend/src/main/java/net/swofty/service/friend/FriendService.java index c19bee4b1..7949d0d6d 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/FriendService.java +++ b/service.friend/src/main/java/net/swofty/service/friend/FriendService.java @@ -3,7 +3,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.config.ConfigProvider; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -24,7 +24,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.friend.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.friend.endpoints", RedisMessageHandler.class).toList(); } } diff --git a/service.friend/src/main/java/net/swofty/service/friend/endpoints/AreFriendsEndpoint.java b/service.friend/src/main/java/net/swofty/service/friend/endpoints/AreFriendsEndpoint.java index a379cef85..185740141 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/endpoints/AreFriendsEndpoint.java +++ b/service.friend/src/main/java/net/swofty/service/friend/endpoints/AreFriendsEndpoint.java @@ -1,25 +1,23 @@ package net.swofty.service.friend.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.friend.AreFriendsProtocolObject; +import net.swofty.commons.protocol.objects.friend.AreFriendsProtocol; import net.swofty.service.friend.FriendCache; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisMessageContext; -public class AreFriendsEndpoint implements ServiceEndpoint< - AreFriendsProtocolObject.AreFriendsMessage, - AreFriendsProtocolObject.AreFriendsResponse> { +public class AreFriendsEndpoint implements RedisMessageHandler< + AreFriendsProtocol.AreFriendsMessage, + AreFriendsProtocol.AreFriendsResponse> { @Override - public AreFriendsProtocolObject associatedProtocolObject() { - return new AreFriendsProtocolObject(); + public AreFriendsProtocol protocol() { + return new AreFriendsProtocol(); } @Override - public AreFriendsProtocolObject.AreFriendsResponse onMessage( - ServiceProxyRequest message, - AreFriendsProtocolObject.AreFriendsMessage messageObject) { + public AreFriendsProtocol.AreFriendsResponse handle(AreFriendsProtocol.AreFriendsMessage messageObject, RedisMessageContext context) { boolean areFriends = FriendCache.areFriends(messageObject.player(), messageObject.other()); - return new AreFriendsProtocolObject.AreFriendsResponse(areFriends, true, null); + return new AreFriendsProtocol.AreFriendsResponse(areFriends, true, null); } } diff --git a/service.friend/src/main/java/net/swofty/service/friend/endpoints/FriendEventToServiceEndpoint.java b/service.friend/src/main/java/net/swofty/service/friend/endpoints/FriendEventToServiceEndpoint.java index 1fb50037e..9c8cc1e11 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/endpoints/FriendEventToServiceEndpoint.java +++ b/service.friend/src/main/java/net/swofty/service/friend/endpoints/FriendEventToServiceEndpoint.java @@ -1,31 +1,29 @@ package net.swofty.service.friend.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.friend.FriendEvent; import net.swofty.commons.friend.events.*; -import net.swofty.commons.protocol.objects.friend.SendFriendEventToServiceProtocolObject; +import net.swofty.commons.protocol.objects.friend.SendFriendEventToServiceProtocol; import net.swofty.service.friend.FriendCache; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; +import net.swofty.commons.redis.RedisMessageContext; -public class FriendEventToServiceEndpoint implements ServiceEndpoint< - SendFriendEventToServiceProtocolObject.SendFriendEventToServiceMessage, - SendFriendEventToServiceProtocolObject.SendFriendEventToServiceResponse> { +public class FriendEventToServiceEndpoint implements RedisMessageHandler< + SendFriendEventToServiceProtocol.SendFriendEventToServiceMessage, + SendFriendEventToServiceProtocol.SendFriendEventToServiceResponse> { @Override - public SendFriendEventToServiceProtocolObject associatedProtocolObject() { - return new SendFriendEventToServiceProtocolObject(); + public SendFriendEventToServiceProtocol protocol() { + return new SendFriendEventToServiceProtocol(); } @Override - public SendFriendEventToServiceProtocolObject.SendFriendEventToServiceResponse onMessage( - ServiceProxyRequest message, - SendFriendEventToServiceProtocolObject.SendFriendEventToServiceMessage messageObject) { + public SendFriendEventToServiceProtocol.SendFriendEventToServiceResponse handle(SendFriendEventToServiceProtocol.SendFriendEventToServiceMessage messageObject, RedisMessageContext context) { try { FriendEvent event = messageObject.event(); - System.out.println("Received friend event: " + event.getClass().getSimpleName()); + Logger.debug("Received friend event: {}", event.getClass().getSimpleName()); switch (event) { case FriendAddRequestEvent e -> FriendCache.handleAddRequest( e, @@ -61,11 +59,10 @@ public SendFriendEventToServiceProtocolObject.SendFriendEventToServiceResponse o default -> Logger.warn("Unknown friend event type: " + event.getClass().getSimpleName()); } - return new SendFriendEventToServiceProtocolObject.SendFriendEventToServiceResponse(true, null); + return new SendFriendEventToServiceProtocol.SendFriendEventToServiceResponse(true, null); } catch (Exception e) { - System.out.println("Failed to process friend event: " + e.getMessage()); Logger.error(e, "Failed to process friend event in service endpoint"); - return new SendFriendEventToServiceProtocolObject.SendFriendEventToServiceResponse(false, "Event processing failed"); + return new SendFriendEventToServiceProtocol.SendFriendEventToServiceResponse(false, "Event processing failed"); } } } diff --git a/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetFriendDataEndpoint.java b/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetFriendDataEndpoint.java index 438fae9d5..836a13c31 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetFriendDataEndpoint.java +++ b/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetFriendDataEndpoint.java @@ -1,26 +1,24 @@ package net.swofty.service.friend.endpoints; import net.swofty.commons.friend.FriendData; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.friend.GetFriendDataProtocolObject; +import net.swofty.commons.protocol.objects.friend.GetFriendDataProtocol; import net.swofty.service.friend.FriendCache; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisMessageContext; -public class GetFriendDataEndpoint implements ServiceEndpoint< - GetFriendDataProtocolObject.GetFriendDataMessage, - GetFriendDataProtocolObject.GetFriendDataResponse> { +public class GetFriendDataEndpoint implements RedisMessageHandler< + GetFriendDataProtocol.GetFriendDataMessage, + GetFriendDataProtocol.GetFriendDataResponse> { @Override - public GetFriendDataProtocolObject associatedProtocolObject() { - return new GetFriendDataProtocolObject(); + public GetFriendDataProtocol protocol() { + return new GetFriendDataProtocol(); } @Override - public GetFriendDataProtocolObject.GetFriendDataResponse onMessage( - ServiceProxyRequest message, - GetFriendDataProtocolObject.GetFriendDataMessage messageObject) { + public GetFriendDataProtocol.GetFriendDataResponse handle(GetFriendDataProtocol.GetFriendDataMessage messageObject, RedisMessageContext context) { FriendData data = FriendCache.getFriendData(messageObject.playerUuid()); - return new GetFriendDataProtocolObject.GetFriendDataResponse(data, true, null); + return new GetFriendDataProtocol.GetFriendDataResponse(data, true, null); } } diff --git a/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPendingRequestsEndpoint.java b/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPendingRequestsEndpoint.java index e823184c3..81a983ebc 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPendingRequestsEndpoint.java +++ b/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPendingRequestsEndpoint.java @@ -1,28 +1,26 @@ package net.swofty.service.friend.endpoints; import net.swofty.commons.friend.PendingFriendRequest; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.friend.GetPendingFriendRequestsProtocolObject; +import net.swofty.commons.protocol.objects.friend.GetPendingFriendRequestsProtocol; import net.swofty.service.friend.FriendCache; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; +import net.swofty.commons.redis.RedisMessageContext; -public class GetPendingRequestsEndpoint implements ServiceEndpoint< - GetPendingFriendRequestsProtocolObject.GetPendingRequestsMessage, - GetPendingFriendRequestsProtocolObject.GetPendingRequestsResponse> { +public class GetPendingRequestsEndpoint implements RedisMessageHandler< + GetPendingFriendRequestsProtocol.GetPendingRequestsMessage, + GetPendingFriendRequestsProtocol.GetPendingRequestsResponse> { @Override - public GetPendingFriendRequestsProtocolObject associatedProtocolObject() { - return new GetPendingFriendRequestsProtocolObject(); + public GetPendingFriendRequestsProtocol protocol() { + return new GetPendingFriendRequestsProtocol(); } @Override - public GetPendingFriendRequestsProtocolObject.GetPendingRequestsResponse onMessage( - ServiceProxyRequest message, - GetPendingFriendRequestsProtocolObject.GetPendingRequestsMessage messageObject) { + public GetPendingFriendRequestsProtocol.GetPendingRequestsResponse handle(GetPendingFriendRequestsProtocol.GetPendingRequestsMessage messageObject, RedisMessageContext context) { List requests = FriendCache.getPendingRequestsFor(messageObject.playerUuid()); - return new GetPendingFriendRequestsProtocolObject.GetPendingRequestsResponse(requests, true, null); + return new GetPendingFriendRequestsProtocol.GetPendingRequestsResponse(requests, true, null); } } diff --git a/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPresenceEndpoint.java b/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPresenceEndpoint.java index 2385ae98a..bf1402185 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPresenceEndpoint.java +++ b/service.friend/src/main/java/net/swofty/service/friend/endpoints/GetPresenceEndpoint.java @@ -1,29 +1,27 @@ package net.swofty.service.friend.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.presence.PresenceInfo; -import net.swofty.commons.protocol.objects.presence.GetPresenceBulkProtocolObject; +import net.swofty.commons.protocol.objects.presence.GetPresenceBulkProtocol; import net.swofty.service.friend.PresenceStorage; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; +import net.swofty.commons.redis.RedisMessageContext; -public class GetPresenceEndpoint implements ServiceEndpoint< - GetPresenceBulkProtocolObject.GetPresenceBulkMessage, - GetPresenceBulkProtocolObject.GetPresenceBulkResponse> { +public class GetPresenceEndpoint implements RedisMessageHandler< + GetPresenceBulkProtocol.GetPresenceBulkMessage, + GetPresenceBulkProtocol.GetPresenceBulkResponse> { @Override - public GetPresenceBulkProtocolObject associatedProtocolObject() { - return new GetPresenceBulkProtocolObject(); + public GetPresenceBulkProtocol protocol() { + return new GetPresenceBulkProtocol(); } @Override - public GetPresenceBulkProtocolObject.GetPresenceBulkResponse onMessage( - ServiceProxyRequest message, - GetPresenceBulkProtocolObject.GetPresenceBulkMessage messageObject) { + public GetPresenceBulkProtocol.GetPresenceBulkResponse handle(GetPresenceBulkProtocol.GetPresenceBulkMessage messageObject, RedisMessageContext context) { List presence = PresenceStorage.getBulk(messageObject.uuids()); - return new GetPresenceBulkProtocolObject.GetPresenceBulkResponse(presence, true, null); + return new GetPresenceBulkProtocol.GetPresenceBulkResponse(presence, true, null); } } diff --git a/service.friend/src/main/java/net/swofty/service/friend/endpoints/UpdatePresenceEndpoint.java b/service.friend/src/main/java/net/swofty/service/friend/endpoints/UpdatePresenceEndpoint.java index ce678d89f..186bf5c72 100644 --- a/service.friend/src/main/java/net/swofty/service/friend/endpoints/UpdatePresenceEndpoint.java +++ b/service.friend/src/main/java/net/swofty/service/friend/endpoints/UpdatePresenceEndpoint.java @@ -1,25 +1,23 @@ package net.swofty.service.friend.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.presence.PresenceInfo; -import net.swofty.commons.protocol.objects.presence.UpdatePresenceProtocolObject; +import net.swofty.commons.protocol.objects.presence.UpdatePresenceProtocol; import net.swofty.service.friend.FriendCache; import net.swofty.service.friend.PresenceStorage; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisMessageContext; -public class UpdatePresenceEndpoint implements ServiceEndpoint< - UpdatePresenceProtocolObject.UpdatePresenceMessage, - UpdatePresenceProtocolObject.UpdatePresenceResponse> { +public class UpdatePresenceEndpoint implements RedisMessageHandler< + UpdatePresenceProtocol.UpdatePresenceMessage, + UpdatePresenceProtocol.UpdatePresenceResponse> { @Override - public UpdatePresenceProtocolObject associatedProtocolObject() { - return new UpdatePresenceProtocolObject(); + public UpdatePresenceProtocol protocol() { + return new UpdatePresenceProtocol(); } @Override - public UpdatePresenceProtocolObject.UpdatePresenceResponse onMessage( - ServiceProxyRequest message, - UpdatePresenceProtocolObject.UpdatePresenceMessage messageObject) { + public UpdatePresenceProtocol.UpdatePresenceResponse handle(UpdatePresenceProtocol.UpdatePresenceMessage messageObject, RedisMessageContext context) { PresenceInfo incoming = messageObject.presence(); PresenceInfo previous = PresenceStorage.upsertPreservingServer(incoming); @@ -35,7 +33,7 @@ public UpdatePresenceProtocolObject.UpdatePresenceResponse onMessage( } } - return new UpdatePresenceProtocolObject.UpdatePresenceResponse(true, null); + return new UpdatePresenceProtocol.UpdatePresenceResponse(true, null); } } diff --git a/service.generic/build.gradle.kts b/service.generic/build.gradle.kts index e513d9711..c7b0ea4eb 100644 --- a/service.generic/build.gradle.kts +++ b/service.generic/build.gradle.kts @@ -23,4 +23,5 @@ dependencies { implementation(libs.atlas.redis) implementation(libs.adventure.api) implementation(libs.adventure.text.serializer.gson) + implementation(libs.tinylog.api) } \ No newline at end of file diff --git a/service.generic/src/main/java/net/swofty/service/generic/ServiceInitializer.java b/service.generic/src/main/java/net/swofty/service/generic/ServiceInitializer.java index 78d3840c6..5e769729c 100644 --- a/service.generic/src/main/java/net/swofty/service/generic/ServiceInitializer.java +++ b/service.generic/src/main/java/net/swofty/service/generic/ServiceInitializer.java @@ -2,20 +2,22 @@ import lombok.RequiredArgsConstructor; import net.swofty.commons.config.ConfigProvider; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.redis.RedisEnvelope; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.redis.RedisChannels; +import net.swofty.commons.redis.RedisClient; +import net.swofty.commons.redis.RedisEndpoint; +import net.swofty.commons.redis.RedisMessageBus; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.commons.skyblock.item.attribute.ItemAttribute; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.redisapi.api.ChannelRegistry; import net.swofty.redisapi.api.RedisAPI; import net.swofty.service.generic.redis.PingEndpoint; -import net.swofty.service.generic.redis.ServiceEndpoint; import net.swofty.service.generic.redis.ServiceRedisManager; -import net.swofty.service.generic.redis.ServiceToServerManager; -import org.json.JSONObject; +import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.concurrent.CountDownLatch; @RequiredArgsConstructor @@ -23,43 +25,37 @@ public class ServiceInitializer { private final SkyBlockService service; public void init() { - System.out.println("Initializing service " + service.getType().name() + "..."); + Logger.info("Initializing service {}...", service.getType().name()); ItemAttribute.registerItemAttributes(); - /** - * Register Redis - */ ServiceRedisManager.connect(ConfigProvider.settings().getRedisUri(), service.getType()); - // Initialize service-to-server communication - ServiceToServerManager.initialize(service.getType()); + RedisClient.registerResponseChannel(RedisChannels.SERVICE_RESPONSE); + RedisClient.registerResponseChannel(RedisChannels.SERVICE_BROADCAST_RESPONSE); - List endpoints = new ArrayList<>(service.getEndpoints()); + List endpoints = new ArrayList<>(service.getEndpoints()); endpoints.add(new PingEndpoint()); endpoints.forEach(endpoint -> { - ProtocolObject protocolObject = endpoint.associatedProtocolObject(); - System.out.println("Registering channel " + protocolObject.channel()); + RedisProtocol protocolObject = endpoint.protocol(); + Logger.debug("Registering channel {}", protocolObject.channel()); - RedisAPI.getInstance().registerChannel(protocolObject.channel(), message -> { - // Everything after the first semicolon is the actual message - String realMessage = message.message.substring(message.message.indexOf(";") + 1); - ServiceProxyRequest request = ServiceProxyRequest.fromJSON(new JSONObject(realMessage)); - - Object messageData = protocolObject.translateFromString(request.getMessage()); - - Thread.startVirtualThread(() -> { - Object rawResponse = endpoint.onMessage(request, messageData); - String response = protocolObject.translateReturnToString(rawResponse); - - RedisAPI.getInstance().publishMessage(request.getRequestServer(), - ChannelRegistry.getFromName(request.getEndpoint()), - new RedisEnvelope(request.getRequestId().toString(), service.getType().name(), response).serialize()).join(); - }); - }); + RedisMessageBus.registerHandler( + RedisEndpoint.service(service.getType()), + RedisChannels.protocol(protocolObject), + endpoint, + (envelope, channel) -> RedisMessageContext.between( + UUID.fromString(envelope.id()), + RedisEndpoint.server(envelope.from()), + RedisEndpoint.service(service.getType()), + protocolObject.channel() + ), + envelope -> envelope.from(), + envelope -> RedisChannels.protocol(protocolObject) + ); }); RedisAPI.getInstance().startListeners(); - System.out.println("Service " + service.getType().name() + " initialized!"); + Logger.info("Service {} initialized!", service.getType().name()); try { new CountDownLatch(1).await(); diff --git a/service.generic/src/main/java/net/swofty/service/generic/SkyBlockService.java b/service.generic/src/main/java/net/swofty/service/generic/SkyBlockService.java index c34684d9d..3722b54ac 100644 --- a/service.generic/src/main/java/net/swofty/service/generic/SkyBlockService.java +++ b/service.generic/src/main/java/net/swofty/service/generic/SkyBlockService.java @@ -1,7 +1,7 @@ package net.swofty.service.generic; import net.swofty.commons.ServiceType; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.reflections.Reflections; import java.lang.reflect.InvocationTargetException; @@ -13,7 +13,7 @@ public interface SkyBlockService { ServiceType getType(); - List getEndpoints(); + List getEndpoints(); static void init(SkyBlockService service) { new ServiceInitializer(service).init(); diff --git a/service.generic/src/main/java/net/swofty/service/generic/redis/BroadcastRequest.java b/service.generic/src/main/java/net/swofty/service/generic/redis/BroadcastRequest.java deleted file mode 100644 index cc687fdee..000000000 --- a/service.generic/src/main/java/net/swofty/service/generic/redis/BroadcastRequest.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.swofty.service.generic.redis; - -import lombok.Getter; -import org.json.JSONObject; - -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; - -public class BroadcastRequest { - @Getter - private final CompletableFuture> future; - private final Map responses; - - public BroadcastRequest(CompletableFuture> future) { - this.future = future; - this.responses = new ConcurrentHashMap<>(); - } - - public synchronized void addResponse(UUID serverUUID, JSONObject response) { - if (!future.isDone()) { - responses.put(serverUUID, response); - } - } - - public Map getResponses() { - return new ConcurrentHashMap<>(responses); - } -} \ No newline at end of file diff --git a/service.generic/src/main/java/net/swofty/service/generic/redis/PingEndpoint.java b/service.generic/src/main/java/net/swofty/service/generic/redis/PingEndpoint.java index 6e6b829f8..4d46cddbc 100644 --- a/service.generic/src/main/java/net/swofty/service/generic/redis/PingEndpoint.java +++ b/service.generic/src/main/java/net/swofty/service/generic/redis/PingEndpoint.java @@ -1,19 +1,20 @@ package net.swofty.service.generic.redis; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.PingProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.PingProtocol; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; -public class PingEndpoint implements ServiceEndpoint< - PingProtocolObject.EmptyMessage, - PingProtocolObject.EmptyMessage> { +public class PingEndpoint implements RedisMessageHandler< + PingProtocol.EmptyMessage, + PingProtocol.EmptyMessage> { @Override - public ProtocolObject associatedProtocolObject() { - return new PingProtocolObject(); + public RedisProtocol protocol() { + return new PingProtocol(); } @Override - public PingProtocolObject.EmptyMessage onMessage(ServiceProxyRequest message, PingProtocolObject.EmptyMessage messageObject) { - return new PingProtocolObject.EmptyMessage(); + public PingProtocol.EmptyMessage handle(PingProtocol.EmptyMessage messageObject, RedisMessageContext context) { + return new PingProtocol.EmptyMessage(); } } diff --git a/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceEndpoint.java b/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceEndpoint.java deleted file mode 100644 index 1588069a0..000000000 --- a/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceEndpoint.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.swofty.service.generic.redis; - -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; - -public interface ServiceEndpoint { - ProtocolObject associatedProtocolObject(); - R onMessage(ServiceProxyRequest message, T messageObject); -} diff --git a/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceRedisManager.java b/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceRedisManager.java index 5e4723c38..1ae13157d 100644 --- a/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceRedisManager.java +++ b/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceRedisManager.java @@ -1,11 +1,14 @@ package net.swofty.service.generic.redis; import net.swofty.commons.ServiceType; +import net.swofty.commons.redis.RedisClient; +import net.swofty.commons.redis.RedisEndpoint; import net.swofty.redisapi.api.RedisAPI; public class ServiceRedisManager { public static void connect(String URI, ServiceType type) { RedisAPI.generateInstance(URI); RedisAPI.getInstance().setFilterId(type.name()); + RedisClient.identify(RedisEndpoint.service(type)); } } diff --git a/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceToServerManager.java b/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceToServerManager.java deleted file mode 100644 index 1c690599d..000000000 --- a/service.generic/src/main/java/net/swofty/service/generic/redis/ServiceToServerManager.java +++ /dev/null @@ -1,207 +0,0 @@ -package net.swofty.service.generic.redis; - -import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.ServicePushProtocol; -import net.swofty.commons.redis.RedisEnvelope; -import net.swofty.commons.protocol.objects.data.GetPlayerDataPushProtocol; -import net.swofty.commons.protocol.objects.data.LockPlayerDataPushProtocol; -import net.swofty.commons.protocol.objects.data.UnlockPlayerDataPushProtocol; -import net.swofty.commons.protocol.objects.data.UpdatePlayerDataPushProtocol; -import net.swofty.commons.protocol.objects.game.GameInformationPushProtocol; -import net.swofty.commons.protocol.objects.gui.KickFromGUIPushProtocol; -import net.swofty.redisapi.api.ChannelRegistry; -import net.swofty.redisapi.api.RedisAPI; -import org.json.JSONObject; - -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.*; -import java.util.concurrent.TimeoutException; - -public class ServiceToServerManager { - private static final Map> pendingRequests = new ConcurrentHashMap<>(); - // Keep track of in-flight broadcasts - private static final Map pendingBroadcastRequests = new ConcurrentHashMap<>(); - // Single threaded scheduler to fire timeouts - private static final ScheduledExecutorService scheduler = - Executors.newSingleThreadScheduledExecutor(r -> { - Thread t = new Thread(r, "broadcast-timeouter"); - t.setDaemon(true); - return t; - }); - private static ServiceType currentServiceType; - - public static void initialize(ServiceType serviceType) { - currentServiceType = serviceType; - - // Register response handler for server responses - RedisAPI.getInstance().registerChannel("service_response", (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - UUID requestId = UUID.fromString(envelope.id()); - - CompletableFuture future = pendingRequests.remove(requestId); - if (future != null) { - future.complete(new JSONObject(envelope.payload())); - } - }); - - RedisAPI.getInstance().registerChannel("service_broadcast_response", (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - UUID requestId = UUID.fromString(envelope.id()); - UUID serverUUID = UUID.fromString(envelope.from()); - - BroadcastRequest broadcastRequest = pendingBroadcastRequests.get(requestId); - if (broadcastRequest != null) { - broadcastRequest.addResponse(serverUUID, new JSONObject(envelope.payload())); - } - }); - } - - public static CompletableFuture sendToServer( - UUID serverUUID, - ServicePushProtocol protocol, - T message - ) { - UUID requestId = UUID.randomUUID(); - CompletableFuture future = new CompletableFuture<>(); - CompletableFuture rawFuture = new CompletableFuture<>(); - - pendingRequests.put(requestId, rawFuture); - - rawFuture.orTimeout(10, TimeUnit.SECONDS).exceptionally(throwable -> { - pendingRequests.remove(requestId); - return null; - }); - - rawFuture.thenAccept(json -> { - if (json == null) { - future.completeExceptionally(new TimeoutException("Service push timed out")); - return; - } - try { - R response = protocol.translateReturnFromString(json.toString()); - future.complete(response); - } catch (Exception e) { - future.completeExceptionally(e); - } - }); - - String serialized = protocol.translateToString(message); - String channelName = "service_" + protocol.channel(); - - RedisAPI.getInstance().publishMessage( - serverUUID.toString(), - ChannelRegistry.getFromName(channelName), - new RedisEnvelope(requestId.toString(), currentServiceType.name(), serialized).serialize() - ); - - return future; - } - - public static CompletableFuture> sendToAllServers( - ServicePushProtocol protocol, - T message, - int timeoutMs - ) { - UUID requestId = UUID.randomUUID(); - CompletableFuture> rawFuture = new CompletableFuture<>(); - CompletableFuture> typedFuture = new CompletableFuture<>(); - - BroadcastRequest broadcastRequest = new BroadcastRequest(rawFuture); - pendingBroadcastRequests.put(requestId, broadcastRequest); - - String serialized = protocol.translateToString(message); - String channelName = "service_broadcast_" + protocol.channel(); - - RedisAPI.getInstance().publishMessage("all", - ChannelRegistry.getFromName(channelName), - new RedisEnvelope(requestId.toString(), currentServiceType.name(), serialized).serialize()); - - scheduler.schedule(() -> { - BroadcastRequest req = pendingBroadcastRequests.remove(requestId); - if (req != null) { - req.getFuture().complete(req.getResponses()); - } - }, timeoutMs, TimeUnit.MILLISECONDS); - - rawFuture.thenAccept(rawMap -> { - Map typedMap = new ConcurrentHashMap<>(); - rawMap.forEach((uuid, json) -> { - try { - typedMap.put(uuid, protocol.translateReturnFromString(json.toString())); - } catch (Exception e) { - System.err.println("Failed to deserialize push response from " + uuid + ": " + e.getMessage()); - } - }); - typedFuture.complete(typedMap); - }); - - return typedFuture; - } - - public static CompletableFuture> sendToServers( - List serverUUIDs, - ServicePushProtocol protocol, - T message - ) { - Map> futures = new ConcurrentHashMap<>(); - - for (UUID serverUUID : serverUUIDs) { - futures.put(serverUUID, sendToServer(serverUUID, protocol, message)); - } - - return CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0])) - .thenApply(v -> { - Map results = new ConcurrentHashMap<>(); - futures.forEach((uuid, future) -> { - try { - results.put(uuid, future.get()); - } catch (Exception e) { - // skip failed entries - } - }); - return results; - }); - } - - private static final GetPlayerDataPushProtocol GET_PLAYER_DATA_PROTOCOL = new GetPlayerDataPushProtocol(); - private static final UpdatePlayerDataPushProtocol UPDATE_PLAYER_DATA_PROTOCOL = new UpdatePlayerDataPushProtocol(); - private static final LockPlayerDataPushProtocol LOCK_PLAYER_DATA_PROTOCOL = new LockPlayerDataPushProtocol(); - private static final UnlockPlayerDataPushProtocol UNLOCK_PLAYER_DATA_PROTOCOL = new UnlockPlayerDataPushProtocol(); - - public static CompletableFuture getPlayerData(UUID serverUUID, UUID playerUUID, String dataKey) { - return sendToServer(serverUUID, GET_PLAYER_DATA_PROTOCOL, - new GetPlayerDataPushProtocol.Request(playerUUID, dataKey)); - } - - public static CompletableFuture updatePlayerData(UUID serverUUID, UUID playerUUID, String dataKey, String newData) { - return sendToServer(serverUUID, UPDATE_PLAYER_DATA_PROTOCOL, - new UpdatePlayerDataPushProtocol.Request(playerUUID, dataKey, newData)); - } - - public static CompletableFuture> lockPlayerData(List serverUUIDs, UUID playerUUID, String dataKey) { - return sendToServers(serverUUIDs, LOCK_PLAYER_DATA_PROTOCOL, - new LockPlayerDataPushProtocol.Request(playerUUID, dataKey)); - } - - public static CompletableFuture> unlockPlayerData(List serverUUIDs, UUID playerUUID, String dataKey) { - return sendToServers(serverUUIDs, UNLOCK_PLAYER_DATA_PROTOCOL, - new UnlockPlayerDataPushProtocol.Request(playerUUID, dataKey)); - } - - private static final KickFromGUIPushProtocol KICK_FROM_GUI_PROTOCOL = new KickFromGUIPushProtocol(); - private static final GameInformationPushProtocol GAME_INFORMATION_PROTOCOL = new GameInformationPushProtocol(); - - public static CompletableFuture> kickFromGUI(List serverUUIDs, List playerUUIDs, String guiType) { - return sendToServers(serverUUIDs, KICK_FROM_GUI_PROTOCOL, - new KickFromGUIPushProtocol.Request(playerUUIDs, guiType)); - } - - public static CompletableFuture> gameInformation(UUID serverUUID, UUID playerUUID, String gameId) { - return sendToServers(List.of(serverUUID), GAME_INFORMATION_PROTOCOL, - new GameInformationPushProtocol.Request(playerUUID, gameId)); - } -} \ No newline at end of file diff --git a/service.itemtracker/build.gradle.kts b/service.itemtracker/build.gradle.kts index 753c0c5f4..4a25341ed 100644 --- a/service.itemtracker/build.gradle.kts +++ b/service.itemtracker/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/ItemTrackerService.java b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/ItemTrackerService.java index b6cfd5a9a..33b955cf7 100644 --- a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/ItemTrackerService.java +++ b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/ItemTrackerService.java @@ -3,7 +3,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.config.ConfigProvider; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -20,7 +20,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.itemtracker.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.itemtracker.endpoints", RedisMessageHandler.class).toList(); } } diff --git a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/TrackedItemsDatabase.java b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/TrackedItemsDatabase.java index 3e84376ae..6c03fdf26 100644 --- a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/TrackedItemsDatabase.java +++ b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/TrackedItemsDatabase.java @@ -41,10 +41,10 @@ public TrackedItem get() { public void insertOrUpdate(TrackedItem trackedItem) { if (!exists()) { - collection.insertOne(trackedItem.toDocument().append("_id", trackedItem.itemUUID.toString())); + collection.insertOne(trackedItem.toDocument().append("_id", trackedItem.getItemUUID().toString())); return; } - collection.replaceOne(Filters.eq("_id", trackedItem.itemUUID.toString()), trackedItem.toDocument()); + collection.replaceOne(Filters.eq("_id", trackedItem.getItemUUID().toString()), trackedItem.toDocument()); } } diff --git a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointGetTrackedItem.java b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointGetTrackedItem.java index 9cc671a73..ab7aec89a 100644 --- a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointGetTrackedItem.java +++ b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointGetTrackedItem.java @@ -1,24 +1,24 @@ package net.swofty.service.itemtracker.endpoints; import net.swofty.commons.TrackedItem; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.itemtracker.TrackedItemsDatabase; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointGetTrackedItem implements ServiceEndpoint< - TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage, - TrackedItemRetrieveProtocolObject.TrackedItemResponse> { +public class EndpointGetTrackedItem implements RedisMessageHandler< + TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage, + TrackedItemRetrieveProtocol.TrackedItemResponse> { @Override - public TrackedItemRetrieveProtocolObject associatedProtocolObject() { - return new TrackedItemRetrieveProtocolObject(); + public TrackedItemRetrieveProtocol protocol() { + return new TrackedItemRetrieveProtocol(); } @Override - public TrackedItemRetrieveProtocolObject.TrackedItemResponse onMessage(ServiceProxyRequest message, TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage messageObject) { + public TrackedItemRetrieveProtocol.TrackedItemResponse handle(TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage messageObject, RedisMessageContext context) { UUID itemUUID = messageObject.itemUUID(); if (!new TrackedItemsDatabase(itemUUID).exists()) { @@ -26,6 +26,6 @@ public TrackedItemRetrieveProtocolObject.TrackedItemResponse onMessage(ServicePr } TrackedItem item = new TrackedItemsDatabase(itemUUID).get(); - return new TrackedItemRetrieveProtocolObject.TrackedItemResponse(item, true, null); + return new TrackedItemRetrieveProtocol.TrackedItemResponse(item, true, null); } } \ No newline at end of file diff --git a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointUpdateItem.java b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointUpdateItem.java index 098f7410e..afa529fdd 100644 --- a/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointUpdateItem.java +++ b/service.itemtracker/src/main/java/net/swofty/service/itemtracker/endpoints/EndpointUpdateItem.java @@ -1,24 +1,24 @@ package net.swofty.service.itemtracker.endpoints; import net.swofty.commons.TrackedItem; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemUpdateProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemUpdateProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.itemtracker.TrackedItemsDatabase; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class EndpointUpdateItem implements ServiceEndpoint< - TrackedItemUpdateProtocolObject.TrackedItemUpdateMessage, - TrackedItemUpdateProtocolObject.TrackedItemUpdateResponse> { +public class EndpointUpdateItem implements RedisMessageHandler< + TrackedItemUpdateProtocol.TrackedItemUpdateMessage, + TrackedItemUpdateProtocol.TrackedItemUpdateResponse> { @Override - public TrackedItemUpdateProtocolObject associatedProtocolObject() { - return new TrackedItemUpdateProtocolObject(); + public TrackedItemUpdateProtocol protocol() { + return new TrackedItemUpdateProtocol(); } @Override - public TrackedItemUpdateProtocolObject.TrackedItemUpdateResponse onMessage(ServiceProxyRequest message, TrackedItemUpdateProtocolObject.TrackedItemUpdateMessage messageObject) { + public TrackedItemUpdateProtocol.TrackedItemUpdateResponse handle(TrackedItemUpdateProtocol.TrackedItemUpdateMessage messageObject, RedisMessageContext context) { UUID itemUUID = messageObject.itemUUID(); UUID attachedPlayerUUID = messageObject.attachedPlayerUUID(); UUID attachedPlayerProfile = messageObject.attachedPlayerProfile(); @@ -41,6 +41,6 @@ public TrackedItemUpdateProtocolObject.TrackedItemUpdateResponse onMessage(Servi } }); - return new TrackedItemUpdateProtocolObject.TrackedItemUpdateResponse(); + return new TrackedItemUpdateProtocol.TrackedItemUpdateResponse(); } } diff --git a/service.orchestrator/build.gradle.kts b/service.orchestrator/build.gradle.kts index f06fd7367..c95a5a84e 100644 --- a/service.orchestrator/build.gradle.kts +++ b/service.orchestrator/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("io.github.goooler.shadow") version "8.1.8" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/OrchestratorService.java b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/OrchestratorService.java index 480e257d4..510f7f2f8 100644 --- a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/OrchestratorService.java +++ b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/OrchestratorService.java @@ -2,7 +2,7 @@ import net.swofty.commons.ServiceType; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; import java.util.concurrent.Executors; @@ -28,7 +28,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.orchestrator.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.orchestrator.endpoints", RedisMessageHandler.class).toList(); } } \ No newline at end of file diff --git a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameChooseEndpoint.java b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameChooseEndpoint.java index b301bc696..30783d14e 100644 --- a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameChooseEndpoint.java +++ b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameChooseEndpoint.java @@ -1,25 +1,26 @@ package net.swofty.service.orchestrator.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.game.GameInformationPushProtocol; +import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocol; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisClient; +import net.swofty.commons.redis.RedisMessageContext; -public class GameChooseEndpoint implements ServiceEndpoint - { +public class GameChooseEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new ChooseGameProtocolObject(); + public RedisProtocol protocol() { + return new ChooseGameProtocol(); } @Override - public ChooseGameProtocolObject.ChooseGameResponse onMessage(ServiceProxyRequest message, - ChooseGameProtocolObject.ChooseGameMessage body) { - ServiceToServerManager.gameInformation(body.server().uuid(), body.player(), body.gameId()); - return new ChooseGameProtocolObject.ChooseGameResponse(true, null); + public ChooseGameProtocol.ChooseGameResponse handle(ChooseGameProtocol.ChooseGameMessage body, RedisMessageContext context) { + RedisClient.requestServerFromService(body.server().uuid(), new GameInformationPushProtocol(), + new GameInformationPushProtocol.Request(body.player(), body.gameId())); + return new ChooseGameProtocol.ChooseGameResponse(true, null); } } diff --git a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameHeartbeatEndpoint.java b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameHeartbeatEndpoint.java index 17fc357e8..2380d44b0 100644 --- a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameHeartbeatEndpoint.java +++ b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GameHeartbeatEndpoint.java @@ -1,23 +1,22 @@ package net.swofty.service.orchestrator.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.orchestrator.OrchestratorCache; +import net.swofty.commons.redis.RedisMessageContext; -public class GameHeartbeatEndpoint implements ServiceEndpoint - { +public class GameHeartbeatEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new GameHeartbeatProtocolObject(); + public RedisProtocol protocol() { + return new GameHeartbeatProtocol(); } @Override - public GameHeartbeatProtocolObject.HeartbeatResponse onMessage(ServiceProxyRequest message, - GameHeartbeatProtocolObject.HeartbeatMessage body) { + public GameHeartbeatProtocol.HeartbeatResponse handle(GameHeartbeatProtocol.HeartbeatMessage body, RedisMessageContext context) { OrchestratorCache.handleHeartbeat( body.uuid(), body.shortName(), @@ -26,6 +25,6 @@ public GameHeartbeatProtocolObject.HeartbeatResponse onMessage(ServiceProxyReque body.onlinePlayers(), body.games() ); - return new GameHeartbeatProtocolObject.HeartbeatResponse(true, null); + return new GameHeartbeatProtocol.HeartbeatResponse(true, null); } } \ No newline at end of file diff --git a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetGameCountsEndpoint.java b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetGameCountsEndpoint.java index 41c61ae53..219fc98f3 100644 --- a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetGameCountsEndpoint.java +++ b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetGameCountsEndpoint.java @@ -1,23 +1,23 @@ package net.swofty.service.orchestrator.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.GetGameCountsProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.orchestrator.GetGameCountsProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.orchestrator.OrchestratorCache; +import net.swofty.commons.redis.RedisMessageContext; -public class GetGameCountsEndpoint implements ServiceEndpoint - { +public class GetGameCountsEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new GetGameCountsProtocolObject(); + public RedisProtocol protocol() { + return new GetGameCountsProtocol(); } @Override - public GetGameCountsProtocolObject.GetGameCountsResponse onMessage(ServiceProxyRequest message, GetGameCountsProtocolObject.GetGameCountsMessage body) { + public GetGameCountsProtocol.GetGameCountsResponse handle(GetGameCountsProtocol.GetGameCountsMessage body, RedisMessageContext context) { var stats = OrchestratorCache.getGameCounts(body.type(), body.gameTypeName(), body.mapName()); - return new GetGameCountsProtocolObject.GetGameCountsResponse(stats.playerCount(), stats.gameCount(), true, null); + return new GetGameCountsProtocol.GetGameCountsResponse(stats.playerCount(), stats.gameCount(), true, null); } } diff --git a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetMapsEndpoint.java b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetMapsEndpoint.java index d50d0ad01..efc96459a 100644 --- a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetMapsEndpoint.java +++ b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetMapsEndpoint.java @@ -1,23 +1,23 @@ package net.swofty.service.orchestrator.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.orchestrator.OrchestratorCache; +import net.swofty.commons.redis.RedisMessageContext; -public class GetMapsEndpoint implements ServiceEndpoint - { +public class GetMapsEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new GetMapsProtocolObject(); + public RedisProtocol protocol() { + return new GetMapsProtocol(); } @Override - public GetMapsProtocolObject.GetMapsResponse onMessage(ServiceProxyRequest message, GetMapsProtocolObject.GetMapsMessage body) { + public GetMapsProtocol.GetMapsResponse handle(GetMapsProtocol.GetMapsMessage body, RedisMessageContext context) { var maps = OrchestratorCache.getMaps(body.type(), body.mode()); - return new GetMapsProtocolObject.GetMapsResponse(maps.stream().sorted().toList(), true, null); + return new GetMapsProtocol.GetMapsResponse(maps.stream().sorted().toList(), true, null); } } \ No newline at end of file diff --git a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetServerForMapEndpoint.java b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetServerForMapEndpoint.java index 42733132d..df1757e28 100644 --- a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetServerForMapEndpoint.java +++ b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/GetServerForMapEndpoint.java @@ -2,46 +2,46 @@ import net.swofty.commons.ServerType; import net.swofty.commons.UnderstandableProxyServer; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocol; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol; import net.swofty.commons.bedwars.BedwarsGameType; import net.swofty.commons.murdermystery.MurderMysteryGameType; import net.swofty.commons.skywars.SkywarsGameType; -import net.swofty.service.generic.redis.ServiceToServerManager; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisClient; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.orchestrator.OrchestratorCache; +import org.tinylog.Logger; import java.util.ArrayList; import java.util.concurrent.CompletableFuture; +import net.swofty.commons.redis.RedisMessageContext; -public class GetServerForMapEndpoint implements ServiceEndpoint - { +public class GetServerForMapEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new GetServerForMapProtocolObject(); + public RedisProtocol protocol() { + return new GetServerForMapProtocol(); } @Override - public GetServerForMapProtocolObject.GetServerForMapResponse onMessage(ServiceProxyRequest message, - GetServerForMapProtocolObject.GetServerForMapMessage body) { + public GetServerForMapProtocol.GetServerForMapResponse handle(GetServerForMapProtocol.GetServerForMapMessage body, RedisMessageContext context) { return switch (body.type()) { case BEDWARS_GAME -> handleBedwars(body); case MURDER_MYSTERY_GAME -> handleMurderMystery(body); case SKYWARS_GAME -> handleSkywars(body); - default -> new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + default -> new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); }; } - private GetServerForMapProtocolObject.GetServerForMapResponse handleBedwars( - GetServerForMapProtocolObject.GetServerForMapMessage body) { + private GetServerForMapProtocol.GetServerForMapResponse handleBedwars( + GetServerForMapProtocol.GetServerForMapMessage body) { try { BedwarsGameType gameType = parseBedwarsGameType(body.mode()); if (gameType == null) { - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } int neededSlots = body.neededSlots() > 0 ? body.neededSlots() : 1; @@ -60,7 +60,7 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleBedwars( hostingServer.maxPlayers(), hostingServer.shortName() ); - return new GetServerForMapProtocolObject.GetServerForMapResponse(proxy, existingGameWithServer.game().getGameId().toString(), true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(proxy, existingGameWithServer.game().getGameId().toString(), true, null); } } @@ -68,7 +68,7 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleBedwars( OrchestratorCache.GameServerState availableServer = OrchestratorCache.instantiateServer(gameType, body.map()); if (availableServer != null) { try { - CompletableFuture responseFuture = ServiceToServerManager.sendToServer( + CompletableFuture responseFuture = RedisClient.requestServerFromService( availableServer.uuid(), new InstantiateGamePushProtocol(), new InstantiateGamePushProtocol.Request(gameType.toString(), body.map()) @@ -86,25 +86,25 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleBedwars( availableServer.maxPlayers(), availableServer.shortName() ); - return new GetServerForMapProtocolObject.GetServerForMapResponse(proxy, response.gameId(), true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(proxy, response.gameId(), true, null); } } catch (Exception e) { - System.err.println("Failed to instantiate Bedwars game: " + e.getMessage()); + Logger.error(e, "Failed to instantiate Bedwars game"); } } - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } catch (Exception e) { - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } } - private GetServerForMapProtocolObject.GetServerForMapResponse handleMurderMystery( - GetServerForMapProtocolObject.GetServerForMapMessage body) { + private GetServerForMapProtocol.GetServerForMapResponse handleMurderMystery( + GetServerForMapProtocol.GetServerForMapMessage body) { try { MurderMysteryGameType gameType = parseMurderMysteryGameType(body.mode()); if (gameType == null) { - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } int neededSlots = body.neededSlots() > 0 ? body.neededSlots() : 1; @@ -124,7 +124,7 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleMurderMyster hostingServer.maxPlayers(), hostingServer.shortName() ); - return new GetServerForMapProtocolObject.GetServerForMapResponse(proxy, existingGameWithServer.game().getGameId().toString(), true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(proxy, existingGameWithServer.game().getGameId().toString(), true, null); } } @@ -133,7 +133,7 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleMurderMyster ServerType.MURDER_MYSTERY_GAME, gameType.getMaxPlayers()); if (availableServer != null) { try { - CompletableFuture responseFuture = ServiceToServerManager.sendToServer( + CompletableFuture responseFuture = RedisClient.requestServerFromService( availableServer.uuid(), new InstantiateGamePushProtocol(), new InstantiateGamePushProtocol.Request(gameType.name(), body.map()) @@ -151,16 +151,16 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleMurderMyster availableServer.maxPlayers(), availableServer.shortName() ); - return new GetServerForMapProtocolObject.GetServerForMapResponse(proxy, response.gameId(), true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(proxy, response.gameId(), true, null); } } catch (Exception e) { - System.err.println("Failed to instantiate Murder Mystery game: " + e.getMessage()); + Logger.error(e, "Failed to instantiate Murder Mystery game"); } } - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } catch (Exception e) { - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } } @@ -201,12 +201,12 @@ private MurderMysteryGameType parseMurderMysteryGameType(String mode) { }; } - private GetServerForMapProtocolObject.GetServerForMapResponse handleSkywars( - GetServerForMapProtocolObject.GetServerForMapMessage body) { + private GetServerForMapProtocol.GetServerForMapResponse handleSkywars( + GetServerForMapProtocol.GetServerForMapMessage body) { try { SkywarsGameType gameType = parseSkywarsGameType(body.mode()); if (gameType == null) { - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } int neededSlots = body.neededSlots() > 0 ? body.neededSlots() : 1; @@ -226,7 +226,7 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleSkywars( hostingServer.maxPlayers(), hostingServer.shortName() ); - return new GetServerForMapProtocolObject.GetServerForMapResponse(proxy, existingGameWithServer.game().getGameId().toString(), true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(proxy, existingGameWithServer.game().getGameId().toString(), true, null); } } @@ -235,7 +235,7 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleSkywars( ServerType.SKYWARS_GAME, gameType.getMaxPlayers()); if (availableServer != null) { try { - CompletableFuture responseFuture = ServiceToServerManager.sendToServer( + CompletableFuture responseFuture = RedisClient.requestServerFromService( availableServer.uuid(), new InstantiateGamePushProtocol(), new InstantiateGamePushProtocol.Request(gameType.name(), body.map()) @@ -253,16 +253,16 @@ private GetServerForMapProtocolObject.GetServerForMapResponse handleSkywars( availableServer.maxPlayers(), availableServer.shortName() ); - return new GetServerForMapProtocolObject.GetServerForMapResponse(proxy, response.gameId(), true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(proxy, response.gameId(), true, null); } } catch (Exception e) { - System.err.println("Failed to instantiate Skywars game: " + e.getMessage()); + Logger.error(e, "Failed to instantiate Skywars game"); } } - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } catch (Exception e) { - return new GetServerForMapProtocolObject.GetServerForMapResponse(null, null, true, null); + return new GetServerForMapProtocol.GetServerForMapResponse(null, null, true, null); } } diff --git a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/RejoinGameEndpoint.java b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/RejoinGameEndpoint.java index a2c987a5e..9fca76c54 100644 --- a/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/RejoinGameEndpoint.java +++ b/service.orchestrator/src/main/java/net/swofty/service/orchestrator/endpoints/RejoinGameEndpoint.java @@ -2,42 +2,42 @@ import net.swofty.commons.ServerType; import net.swofty.commons.UnderstandableProxyServer; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.RejoinGameProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.orchestrator.RejoinGameProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.orchestrator.OrchestratorCache; +import org.tinylog.Logger; import java.util.ArrayList; +import net.swofty.commons.redis.RedisMessageContext; -public class RejoinGameEndpoint implements ServiceEndpoint< - RejoinGameProtocolObject.RejoinGameRequest, - RejoinGameProtocolObject.RejoinGameResponse> { +public class RejoinGameEndpoint implements RedisMessageHandler< + RejoinGameProtocol.RejoinGameRequest, + RejoinGameProtocol.RejoinGameResponse> { @Override - public ProtocolObject associatedProtocolObject() { - return new RejoinGameProtocolObject(); + public RedisProtocol protocol() { + return new RejoinGameProtocol(); } @Override - public RejoinGameProtocolObject.RejoinGameResponse onMessage(ServiceProxyRequest message, - RejoinGameProtocolObject.RejoinGameRequest body) { + public RejoinGameProtocol.RejoinGameResponse handle(RejoinGameProtocol.RejoinGameRequest body, RedisMessageContext context) { try { // Find the game this player is part of (active or disconnected) OrchestratorCache.GameWithServer gameWithServer = OrchestratorCache.findPlayerGame(body.playerUuid()); if (gameWithServer == null) { - return new RejoinGameProtocolObject.RejoinGameResponse(false, null, null, null, null, false, true, null); + return new RejoinGameProtocol.RejoinGameResponse(false, null, null, null, null, false, true, null); } OrchestratorCache.GameServerState hostingServer = OrchestratorCache.getServerByUuid(gameWithServer.serverUuid()); if (hostingServer == null) { - return new RejoinGameProtocolObject.RejoinGameResponse(false, null, null, null, null, false, true, null); + return new RejoinGameProtocol.RejoinGameResponse(false, null, null, null, null, false, true, null); } // Skywars does not support rejoining if (hostingServer.type() == ServerType.SKYWARS_GAME) { - return new RejoinGameProtocolObject.RejoinGameResponse(false, null, null, null, null, false, true, null); + return new RejoinGameProtocol.RejoinGameResponse(false, null, null, null, null, false, true, null); } // Check if this player is in the disconnected list (meaning they should rejoin) @@ -47,7 +47,7 @@ public RejoinGameProtocolObject.RejoinGameResponse onMessage(ServiceProxyRequest if (!isDisconnected) { // Player is already in an active game, not a rejoin scenario - return new RejoinGameProtocolObject.RejoinGameResponse(false, null, null, null, null, false, true, null); + return new RejoinGameProtocol.RejoinGameResponse(false, null, null, null, null, false, true, null); } UnderstandableProxyServer proxy = new UnderstandableProxyServer( @@ -60,7 +60,7 @@ public RejoinGameProtocolObject.RejoinGameResponse onMessage(ServiceProxyRequest hostingServer.shortName() ); - return new RejoinGameProtocolObject.RejoinGameResponse( + return new RejoinGameProtocol.RejoinGameResponse( true, proxy, gameWithServer.game().getGameId().toString(), @@ -71,8 +71,8 @@ public RejoinGameProtocolObject.RejoinGameResponse onMessage(ServiceProxyRequest null ); } catch (Exception e) { - System.err.println("Failed to check rejoin: " + e.getMessage()); - return new RejoinGameProtocolObject.RejoinGameResponse(false, null, null, null, null, false, true, null); + Logger.error(e, "Failed to check rejoin"); + return new RejoinGameProtocol.RejoinGameResponse(false, null, null, null, null, false, true, null); } } } diff --git a/service.party/build.gradle.kts b/service.party/build.gradle.kts index e60f3c4c9..fe105bbfb 100644 --- a/service.party/build.gradle.kts +++ b/service.party/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.party/src/main/java/net/swofty/service/party/PartyCache.java b/service.party/src/main/java/net/swofty/service/party/PartyCache.java index eb03948ca..87e81f9f5 100644 --- a/service.party/src/main/java/net/swofty/service/party/PartyCache.java +++ b/service.party/src/main/java/net/swofty/service/party/PartyCache.java @@ -6,7 +6,7 @@ import net.swofty.commons.party.PendingParty; import net.swofty.commons.protocol.objects.messaging.SendMessagePushProtocol; import net.swofty.commons.protocol.objects.party.PartyBroadcastPushProtocol; -import net.swofty.service.generic.redis.ServiceToServerManager; +import net.swofty.commons.redis.RedisClient; import java.util.ArrayList; import java.util.HashMap; @@ -276,7 +276,7 @@ public static void handleWarp(PartyAction.Warp action) { .filter(uuid -> !uuid.equals(warperUUID)) .toList(); - Map responses = ServiceToServerManager.sendToAllServers( + Map responses = RedisClient.requestAllServersFromService( new PartyBroadcastPushProtocol(), new PartyBroadcastPushProtocol.Request(new PartyBroadcast.Warp(party, warperUUID)), WARP_BROADCAST_TIMEOUT_MS).join(); @@ -368,7 +368,7 @@ private static void cancelDisconnectTimer(UUID playerUUID) { } private static void broadcast(PartyBroadcast broadcast) { - ServiceToServerManager.sendToAllServers( + RedisClient.requestAllServersFromService( new PartyBroadcastPushProtocol(), new PartyBroadcastPushProtocol.Request(broadcast), BROADCAST_TIMEOUT_MS); @@ -376,7 +376,7 @@ private static void broadcast(PartyBroadcast broadcast) { private static void sendErrorToPlayer(UUID playerUUID, String message) { String separator = "§9§m-----------------------------------------------------"; - ServiceToServerManager.sendToAllServers( + RedisClient.requestAllServersFromService( new SendMessagePushProtocol(), new SendMessagePushProtocol.Request(playerUUID, separator + "\n" + message + "\n" + separator), BROADCAST_TIMEOUT_MS); diff --git a/service.party/src/main/java/net/swofty/service/party/PartyService.java b/service.party/src/main/java/net/swofty/service/party/PartyService.java index b9d6cb6ca..c272992ad 100644 --- a/service.party/src/main/java/net/swofty/service/party/PartyService.java +++ b/service.party/src/main/java/net/swofty/service/party/PartyService.java @@ -2,7 +2,7 @@ import net.swofty.commons.ServiceType; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -18,7 +18,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.party.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.party.endpoints", RedisMessageHandler.class).toList(); } } \ No newline at end of file diff --git a/service.party/src/main/java/net/swofty/service/party/endpoints/GetPartyEndpoint.java b/service.party/src/main/java/net/swofty/service/party/endpoints/GetPartyEndpoint.java index 59f588dcf..43d8535b6 100644 --- a/service.party/src/main/java/net/swofty/service/party/endpoints/GetPartyEndpoint.java +++ b/service.party/src/main/java/net/swofty/service/party/endpoints/GetPartyEndpoint.java @@ -1,27 +1,27 @@ package net.swofty.service.party.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.party.FullParty; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.party.GetPartyProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.party.GetPartyProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.party.PartyCache; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class GetPartyEndpoint implements ServiceEndpoint - { +public class GetPartyEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new GetPartyProtocolObject(); + public RedisProtocol protocol() { + return new GetPartyProtocol(); } @Override - public GetPartyProtocolObject.GetPartyResponse onMessage(ServiceProxyRequest message, GetPartyProtocolObject.GetPartyMessage messageObject) { + public GetPartyProtocol.GetPartyResponse handle(GetPartyProtocol.GetPartyMessage messageObject, RedisMessageContext context) { UUID memberUUID = messageObject.memberUuid(); FullParty party = PartyCache.getPartyFromPlayer(memberUUID); if (party == null) throw new RuntimeException("Player is not in a party"); - return new GetPartyProtocolObject.GetPartyResponse(party, true, null); + return new GetPartyProtocol.GetPartyResponse(party, true, null); } } diff --git a/service.party/src/main/java/net/swofty/service/party/endpoints/IsPlayerInPartyEndpoint.java b/service.party/src/main/java/net/swofty/service/party/endpoints/IsPlayerInPartyEndpoint.java index 0abb8a6e2..6104036a6 100644 --- a/service.party/src/main/java/net/swofty/service/party/endpoints/IsPlayerInPartyEndpoint.java +++ b/service.party/src/main/java/net/swofty/service/party/endpoints/IsPlayerInPartyEndpoint.java @@ -1,27 +1,27 @@ package net.swofty.service.party.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.objects.party.IsPlayerInPartyProtocolObject; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.objects.party.IsPlayerInPartyProtocol; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.party.PartyCache; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class IsPlayerInPartyEndpoint implements ServiceEndpoint< - IsPlayerInPartyProtocolObject.IsPlayerInPartyMessage, - IsPlayerInPartyProtocolObject.IsPlayerInPartyResponse> { +public class IsPlayerInPartyEndpoint implements RedisMessageHandler< + IsPlayerInPartyProtocol.IsPlayerInPartyMessage, + IsPlayerInPartyProtocol.IsPlayerInPartyResponse> { @Override - public IsPlayerInPartyProtocolObject associatedProtocolObject() { - return new IsPlayerInPartyProtocolObject(); + public IsPlayerInPartyProtocol protocol() { + return new IsPlayerInPartyProtocol(); } @Override - public IsPlayerInPartyProtocolObject.IsPlayerInPartyResponse onMessage(ServiceProxyRequest message, IsPlayerInPartyProtocolObject.IsPlayerInPartyMessage messageObject) { + public IsPlayerInPartyProtocol.IsPlayerInPartyResponse handle(IsPlayerInPartyProtocol.IsPlayerInPartyMessage messageObject, RedisMessageContext context) { UUID playerUUID = messageObject.playerUUID(); boolean isInParty = PartyCache.isInParty(playerUUID); - return new IsPlayerInPartyProtocolObject.IsPlayerInPartyResponse(isInParty, true, null); + return new IsPlayerInPartyProtocol.IsPlayerInPartyResponse(isInParty, true, null); } } \ No newline at end of file diff --git a/service.party/src/main/java/net/swofty/service/party/endpoints/PartyActionEndpoint.java b/service.party/src/main/java/net/swofty/service/party/endpoints/PartyActionEndpoint.java index e6733773b..37adb1a43 100644 --- a/service.party/src/main/java/net/swofty/service/party/endpoints/PartyActionEndpoint.java +++ b/service.party/src/main/java/net/swofty/service/party/endpoints/PartyActionEndpoint.java @@ -1,23 +1,23 @@ package net.swofty.service.party.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; import net.swofty.commons.party.PartyAction; -import net.swofty.commons.protocol.objects.party.SendPartyActionProtocolObject; -import net.swofty.commons.protocol.objects.party.SendPartyActionProtocolObject.Request; -import net.swofty.commons.protocol.objects.party.SendPartyActionProtocolObject.Response; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.protocol.objects.party.SendPartyActionProtocol; +import net.swofty.commons.protocol.objects.party.SendPartyActionProtocol.Request; +import net.swofty.commons.protocol.objects.party.SendPartyActionProtocol.Response; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.service.party.PartyCache; import org.tinylog.Logger; +import net.swofty.commons.redis.RedisMessageContext; -public class PartyActionEndpoint implements ServiceEndpoint { +public class PartyActionEndpoint implements RedisMessageHandler { @Override - public SendPartyActionProtocolObject associatedProtocolObject() { - return new SendPartyActionProtocolObject(); + public SendPartyActionProtocol protocol() { + return new SendPartyActionProtocol(); } @Override - public Response onMessage(ServiceProxyRequest message, Request request) { + public Response handle(Request request, RedisMessageContext context) { try { PartyAction action = request.action(); switch (action) { diff --git a/service.punishment/build.gradle.kts b/service.punishment/build.gradle.kts index 677ae159f..e6ae798e6 100644 --- a/service.punishment/build.gradle.kts +++ b/service.punishment/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/service.punishment/src/main/java/net/swofty/service/punishment/ProxyRedis.java b/service.punishment/src/main/java/net/swofty/service/punishment/ProxyRedis.java deleted file mode 100644 index f6eb9d655..000000000 --- a/service.punishment/src/main/java/net/swofty/service/punishment/ProxyRedis.java +++ /dev/null @@ -1,76 +0,0 @@ -package net.swofty.service.punishment; -import org.tinylog.Logger; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; - -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.redis.RedisEnvelope; - -import java.net.URI; -import java.time.Duration; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public class ProxyRedis { - private static JedisPool jedisPool; - private static volatile boolean initialized = false; - private static volatile boolean connecting = false; - - public static void connect(String redisUri) { - Thread.startVirtualThread(() -> connectSync(redisUri)); - } - - private static synchronized void connectSync(String redisUri) { - if (initialized || connecting) return; - connecting = true; - - try { - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMaxTotal(5); - poolConfig.setMaxIdle(1); - poolConfig.setMinIdle(1); - poolConfig.setMaxWait(Duration.ofSeconds(2)); - poolConfig.setTestOnBorrow(true); - poolConfig.setTestWhileIdle(true); - poolConfig.setBlockWhenExhausted(false); - - URI uri = URI.create(redisUri); - jedisPool = new JedisPool(poolConfig, uri); - - try (Jedis jedis = jedisPool.getResource()) { - jedis.ping(); - } - - initialized = true; - Logger.info("ProxyRedis: connected to Redis"); - } catch (Exception e) { - Logger.error("ProxyRedis: Redis not available player ban enforcement unavailable"); - initialized = false; - jedisPool = null; - } finally { - connecting = false; - } - } - - public static CompletableFuture publishMessage(String filterId, String channel, String message) { - return CompletableFuture.runAsync(() -> { - try (Jedis jedis = jedisPool.getResource()) { - jedis.publish(channel, filterId + ";" + message); - } catch (Exception ex) { - throw new RuntimeException("Failed to publish message to Redis", ex); - } - }); - } - - public static void publishToProxy(ProtocolObject protocol, T message) { - UUID uuid = UUID.randomUUID(); - String serialized = protocol.translateToString(message); - publishMessage("proxy", protocol.channel(), - new RedisEnvelope(uuid.toString(), uuid.toString(), serialized).serialize()); - } - - public static boolean isInitialized() { - return initialized && jedisPool != null && !jedisPool.isClosed(); - } -} diff --git a/service.punishment/src/main/java/net/swofty/service/punishment/PunishmentService.java b/service.punishment/src/main/java/net/swofty/service/punishment/PunishmentService.java index 2d2fb5ddf..1cb8fdc50 100644 --- a/service.punishment/src/main/java/net/swofty/service/punishment/PunishmentService.java +++ b/service.punishment/src/main/java/net/swofty/service/punishment/PunishmentService.java @@ -4,7 +4,7 @@ import net.swofty.commons.config.ConfigProvider; import net.swofty.commons.punishment.PunishmentRedis; import net.swofty.service.generic.SkyBlockService; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; @@ -13,9 +13,8 @@ public class PunishmentService implements SkyBlockService { static void main(String[] args) { String mongoUri = ConfigProvider.settings().getMongodb(); new PunishmentDatabase(null).connect(mongoUri); - SkyBlockService.init(new PunishmentService()); PunishmentRedis.connect(ConfigProvider.settings().getRedisUri()); - ProxyRedis.connect(ConfigProvider.settings().getRedisUri()); + SkyBlockService.init(new PunishmentService()); } @Override @@ -24,7 +23,7 @@ public ServiceType getType() { } @Override - public List getEndpoints() { - return loopThroughPackage("net.swofty.service.punishment.endpoints", ServiceEndpoint.class).toList(); + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.punishment.endpoints", RedisMessageHandler.class).toList(); } } diff --git a/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/GetActivePunishmentEndpoint.java b/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/GetActivePunishmentEndpoint.java index 0dab4f1f9..15b0464ee 100644 --- a/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/GetActivePunishmentEndpoint.java +++ b/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/GetActivePunishmentEndpoint.java @@ -1,33 +1,33 @@ package net.swofty.service.punishment.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.punishment.GetActivePunishmentProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.punishment.GetActivePunishmentProtocol; import net.swofty.commons.punishment.ActivePunishment; import net.swofty.commons.punishment.PunishmentRedis; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; import java.util.Optional; +import net.swofty.commons.redis.RedisMessageContext; -public class GetActivePunishmentEndpoint implements ServiceEndpoint - { +public class GetActivePunishmentEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new GetActivePunishmentProtocolObject(); + public RedisProtocol protocol() { + return new GetActivePunishmentProtocol(); } @Override - public GetActivePunishmentProtocolObject.GetActivePunishmentResponse onMessage(ServiceProxyRequest message, GetActivePunishmentProtocolObject.GetActivePunishmentMessage messageObject) { + public GetActivePunishmentProtocol.GetActivePunishmentResponse handle(GetActivePunishmentProtocol.GetActivePunishmentMessage messageObject, RedisMessageContext context) { Optional existing = PunishmentRedis.getActive(messageObject.target(), messageObject.type()); if (existing.isEmpty()) { - return new GetActivePunishmentProtocolObject.GetActivePunishmentResponse(false, null, null, null, 0, List.of(), true, null); + return new GetActivePunishmentProtocol.GetActivePunishmentResponse(false, null, null, null, 0, List.of(), true, null); } ActivePunishment punishment = existing.get(); - return new GetActivePunishmentProtocolObject.GetActivePunishmentResponse( + return new GetActivePunishmentProtocol.GetActivePunishmentResponse( true, punishment.type(), punishment.banId(), diff --git a/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/PunishPlayerEndpoint.java b/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/PunishPlayerEndpoint.java index 970b7b0cd..a47c11d3c 100644 --- a/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/PunishPlayerEndpoint.java +++ b/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/PunishPlayerEndpoint.java @@ -1,47 +1,48 @@ package net.swofty.service.punishment.endpoints; import com.google.gson.Gson; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.punishment.PunishPlayerServiceProtocol; import net.swofty.commons.protocol.objects.proxy.to.PunishPlayerProtocol; -import net.swofty.commons.protocol.objects.punishment.PunishPlayerProtocolObject; import net.swofty.commons.punishment.*; -import net.swofty.service.generic.redis.ServiceEndpoint; -import net.swofty.service.punishment.ProxyRedis; +import net.swofty.commons.redis.RedisEndpoint; +import net.swofty.commons.redis.RedisMessageBus; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.time.Instant; import java.util.Optional; +import net.swofty.commons.redis.RedisMessageContext; -public class PunishPlayerEndpoint implements ServiceEndpoint - { +public class PunishPlayerEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new PunishPlayerProtocolObject(); + public RedisProtocol protocol() { + return new PunishPlayerServiceProtocol(); } @Override - public PunishPlayerProtocolObject.PunishPlayerResponse onMessage(ServiceProxyRequest message, PunishPlayerProtocolObject.PunishPlayerMessage messageObject) { + public PunishPlayerServiceProtocol.PunishPlayerResponse handle(PunishPlayerServiceProtocol.PunishPlayerMessage messageObject, RedisMessageContext context) { PunishmentType punishmentType; try { punishmentType = PunishmentType.valueOf(messageObject.type()); } catch (IllegalArgumentException e) { - return new PunishPlayerProtocolObject.PunishPlayerResponse(false, null, PunishPlayerProtocolObject.ErrorCode.INVALID_TYPE, "The punishment type provided is invalid."); + return new PunishPlayerServiceProtocol.PunishPlayerResponse(false, null, PunishPlayerServiceProtocol.ErrorCode.INVALID_TYPE, "The punishment type provided is invalid."); } Instant now = Instant.now(); if (messageObject.expiresAt() > 0 && Instant.ofEpochMilli(messageObject.expiresAt()).isBefore(now)) { - return new PunishPlayerProtocolObject.PunishPlayerResponse(false, null, PunishPlayerProtocolObject.ErrorCode.INVALID_EXPIRY, "The expiration time provided is invalid."); + return new PunishPlayerServiceProtocol.PunishPlayerResponse(false, null, PunishPlayerServiceProtocol.ErrorCode.INVALID_EXPIRY, "The expiration time provided is invalid."); } boolean hasOverwriteTag = messageObject.tags() != null && messageObject.tags().contains(PunishmentTag.OVERWRITE); if (!hasOverwriteTag) { Optional existing = PunishmentRedis.getActive(messageObject.target(), messageObject.type()); if (existing.isPresent()) { - return new PunishPlayerProtocolObject.PunishPlayerResponse(false, null, - PunishPlayerProtocolObject.ErrorCode.ALREADY_PUNISHED, existing.get().banId()); + return new PunishPlayerServiceProtocol.PunishPlayerResponse(false, null, + PunishPlayerServiceProtocol.ErrorCode.ALREADY_PUNISHED, existing.get().banId()); } } @@ -59,12 +60,16 @@ public PunishPlayerProtocolObject.PunishPlayerResponse onMessage(ServiceProxyReq ); } catch (Exception e) { Logger.error("Failed to save punishment to Redis", e); - return new PunishPlayerProtocolObject.PunishPlayerResponse(false, null, - PunishPlayerProtocolObject.ErrorCode.DATABASE_ERROR, "Failed to save punishment."); + return new PunishPlayerServiceProtocol.PunishPlayerResponse(false, null, + PunishPlayerServiceProtocol.ErrorCode.DATABASE_ERROR, "Failed to save punishment."); } Gson gson = new Gson(); - ProxyRedis.publishToProxy(new PunishPlayerProtocol(), + RedisMessageBus.publish( + RedisEndpoint.service(context.destination().id()), + RedisEndpoint.proxy().id(), + new PunishPlayerProtocol().channel(), + new PunishPlayerProtocol(), new PunishPlayerProtocol.Request( messageObject.target().toString(), messageObject.type(), @@ -73,13 +78,14 @@ public PunishPlayerProtocolObject.PunishPlayerResponse onMessage(ServiceProxyReq reason.getBanType() != null ? reason.getBanType().name() : null, reason.getMuteType() != null ? reason.getMuteType().name() : null, messageObject.tags() != null ? gson.toJson(messageObject.tags()) : null - )); + ) + ); Logger.info("Issued {} punishment to {} for reason '{}' (expires at: {})", messageObject.type(), messageObject.target(), reason.getReasonString(), messageObject.expiresAt() ); - return new PunishPlayerProtocolObject.PunishPlayerResponse(true, id.id(), null, null); + return new PunishPlayerServiceProtocol.PunishPlayerResponse(true, id.id(), null, null); } } diff --git a/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/UnpunishPlayerEndpoint.java b/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/UnpunishPlayerEndpoint.java index 1479c8901..faafdf13e 100644 --- a/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/UnpunishPlayerEndpoint.java +++ b/service.punishment/src/main/java/net/swofty/service/punishment/endpoints/UnpunishPlayerEndpoint.java @@ -1,40 +1,40 @@ package net.swofty.service.punishment.endpoints; -import net.swofty.commons.impl.ServiceProxyRequest; -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.protocol.objects.punishment.UnpunishPlayerProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.protocol.objects.punishment.UnpunishPlayerProtocol; import net.swofty.commons.punishment.ActivePunishment; import net.swofty.commons.punishment.PunishmentRedis; -import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.Optional; +import net.swofty.commons.redis.RedisMessageContext; -public class UnpunishPlayerEndpoint implements ServiceEndpoint - { +public class UnpunishPlayerEndpoint implements RedisMessageHandler + { @Override - public ProtocolObject associatedProtocolObject() { - return new UnpunishPlayerProtocolObject(); + public RedisProtocol protocol() { + return new UnpunishPlayerProtocol(); } @Override - public UnpunishPlayerProtocolObject.UnpunishPlayerResponse onMessage(ServiceProxyRequest message, UnpunishPlayerProtocolObject.UnpunishPlayerMessage messageObject) { + public UnpunishPlayerProtocol.UnpunishPlayerResponse handle(UnpunishPlayerProtocol.UnpunishPlayerMessage messageObject, RedisMessageContext context) { Optional existing = PunishmentRedis.getActive(messageObject.target(), messageObject.type()); if (existing.isEmpty()) { - return new UnpunishPlayerProtocolObject.UnpunishPlayerResponse(false, "No active " + messageObject.type().toLowerCase() + " found for this player."); + return new UnpunishPlayerProtocol.UnpunishPlayerResponse(false, "No active " + messageObject.type().toLowerCase() + " found for this player."); } try { PunishmentRedis.revoke(messageObject.target(), messageObject.type()); } catch (Exception e) { Logger.error("Failed to revoke punishment", e); - return new UnpunishPlayerProtocolObject.UnpunishPlayerResponse(false, "Failed to revoke punishment from database."); + return new UnpunishPlayerProtocol.UnpunishPlayerResponse(false, "Failed to revoke punishment from database."); } Logger.info("Revoked {} for {} by staff {}", messageObject.type(), messageObject.target(), messageObject.staff()); - return new UnpunishPlayerProtocolObject.UnpunishPlayerResponse(true, null); + return new UnpunishPlayerProtocol.UnpunishPlayerResponse(true, null); } } diff --git a/spark/build.gradle.kts b/spark/build.gradle.kts index 0fe015dfa..ef30d1336 100644 --- a/spark/build.gradle.kts +++ b/spark/build.gradle.kts @@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { java application - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" } group = "net.swofty" diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java index 26bc2a91f..08eff5dfb 100644 --- a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java @@ -5,8 +5,8 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.type.backwaterbayou.tab.BackwaterBayouServerModule; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.HypixelEventClass; @@ -41,9 +41,7 @@ public void afterInitialize(MinecraftServer server) { @Override public LoaderValues getLoaderValues() { return new LoaderValues( - (type) -> switch (type) { - default -> new Pos(-12.5, 74, -10.5, -55, 0); - }, // Spawn position + (type) -> new Pos(-12.5, 74, -10.5, -55, 0), // Spawn position true // Announce death messages ); } @@ -55,7 +53,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new BackwaterBayouServerModule(), + new AreaServerModule("tablist.server_info.area.backwater_bayou"), new AccountInformationModule() )); } @@ -85,7 +83,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/events/ActionPlayerJoin.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/events/ActionPlayerJoin.java index 173ba7c29..1459fce2e 100644 --- a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/events/ActionPlayerJoin.java +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java new file mode 100644 index 000000000..ce4ab913c --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUIFishingRodParts extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIFishingRodParts { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java new file mode 100644 index 000000000..1abe3f435 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUIHook extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIHookGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIJunkerJoel.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIJunkerJoel.java new file mode 100644 index 000000000..35ee873cb --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIJunkerJoel.java @@ -0,0 +1,461 @@ +package net.swofty.type.backwaterbayou.gui; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +// TODO: use ShopView +public class GUIJunkerJoel extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Junker Joel", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + layout.slot(10, ItemStackCreator.getStackHead( + "§9Junk Sinker", + "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", + 1, + "§7Grants §6+10⛃ Treasure Chance §7while", + "§7in the §2Backwater Bayou §7but replaces", + "§7all §6Treasure §7catches with §2Junk§7!", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Sinker §7to a", + "§7Fishing Rod.", + "", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§610,000 Coins", + "", + "§eClick to trade!" + )); + layout.slot(11, ItemStackCreator.getStackHead( + "§9Treasure Bait §8x16", + "c1695c80854447b5db5a0ee6d57ef0a7d91d815bd7e6318c516a39d12fe0639e", + 16, + "§8Fishing Bait", + "§8Consumes on Cast", + "", + "§7Grants §b+10☂ Fishing Speed§7 and §6+2⛃", + "§6Treasure Chance§7.", + "", + "§9§lRARE BAIT", + "", + "§7Cost", + "§aRusty Coin", + "", + "§eClick to trade!", + "§eRight-click for more trading options!" + )); + layout.slot(12, ItemStackCreator.getStack( + "§aChallenging Rod", + Material.FISHING_ROD, + 1, + "§7Damage: §c+75", + "§7Strength: §c+75", + "§7Fishing Speed: §b+35", + "§7Sea Creature Chance: §3+2%", + "", + "§9ථ Hook §8§lNONE", + "§9ꨃ Line §8§lNONE", + "§9࿉ Sinker §8§lNONE", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply parts to this rod.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON FISHING ROD", + "", + "§7Cost", + "§fFishing Rod", + "§aRusty Coin §8x16", + "", + "§eClick to trade!" + )); + layout.slot(13, ItemStackCreator.getStackHead( + "§aBackwater Helmet", + "f6f6c3ebab908a184d49a0f8c85edd3ed48a65d69213bc0367db67a7a1c0c3a7", + 1, + "§7Health: §c+30", + "§7Defense: §a+15", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON HELMET", + "", + "§7Cost", + "§fAngler Helmet", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(14, ItemStackCreator.getStack( + "§aBackwater Chestplate", + Material.LEATHER_CHESTPLATE, + 1, + "§7Health: §c+50", + "§7Defense: §a+25", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON CHESTPLATE", + "", + "§7Cost", + "§fAngler Chestplate", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(15, ItemStackCreator.getStack( + "§aBackwater Leggings", + Material.LEATHER_LEGGINGS, + 1, + "§7Health: §c+40", + "§7Defense: §a+20", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON LEGGINGS", + "", + "§7Cost", + "§fAngler Leggings", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(16, ItemStackCreator.getStack( + "§aBackwater Boots", + Material.LEATHER_BOOTS, + 1, + "§7Health: §c+20", + "§7Defense: §a+10", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON BOOTS", + "", + "§7Cost", + "§fAngler Boots", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(19, ItemStackCreator.getStackHead( + "§fJunk Talisman", + "d24c6d00c53b51685a6be7453d236228f9837f1c1e27a9175813983ca49c792f", + 1, + "§7Grants §6+2.5⛃ Treasure Chance §7while", + "§7on the §2Backwater Bayou§7.", + "", + "§8§oOne man's trash is another man's", + "§8§otreasure.", + "", + "§8Works while in Accessory Bag!", + "§f§lCOMMON ACCESSORY", + "", + "§7Cost", + "§aRusty Coin §8x32", + "", + "§eClick to trade!" + )); + layout.slot(20, ItemStackCreator.getStackHead( + "§aJunk Ring", + "4c920d3593ed4936defc894b88c43a2bb0b50c3a1e9a6dd8e859cb27bd3cabd", + 1, + "§7Grants §6+5⛃ Treasure Chance §7while", + "§7on the §2Backwater Bayou§7.", + "", + "§8§oOne man's trash is another man's", + "§8§otreasure.", + "", + "§8Works while in Accessory Bag!", + "§a§lUNCOMMON ACCESSORY", + "", + "§7Cost", + "§fJunk Talisman", + "§9Busted Belt Buckle §8x4", + "", + "§eClick to trade!" + )); + layout.slot(21, ItemStackCreator.getStackHead( + "§9Junk Artifact", + "9727812f708dee1826bceecdadb9c7719e3d0f385a3b2515d00b5f665d8ba83e", + 1, + "§7Grants §6+7.5⛃ Treasure Chance §7while", + "§7on the §2Backwater Bayou§7.", + "", + "§8§oOne man's trash is another man's", + "§8§otreasure.", + "", + "§8Works while in Accessory Bag!", + "§9§lRARE ACCESSORY", + "", + "§7Cost", + "§aJunk Ring", + "§5Old Leather Boot", + "", + "§eClick to trade!" + )); + layout.slot(22, ItemStackCreator.getStackHead( + "§aBackwater Necklace", + "ab6f8eea74ca22c2ab64592bab2699df39c3e7c1db7d2c9fc687be0dc8c7f1ed", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON NECKLACE", + "", + "§7Cost", + "§fAngler Necklace", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(23, ItemStackCreator.getStackHead( + "§aBackwater Cloak", + "f2adeecbf20b58fd4cad8aaa3b4653d7165e07aa167be48a321b096d56a9fe35", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON CLOAK", + "", + "§7Cost", + "§fAngler Cloak", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(24, ItemStackCreator.getStackHead( + "§aBackwater Belt", + "3c150be849a39208a38a83c5605e79aef93a12b37072b931693990192cb77a19", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON BELT", + "", + "§7Cost", + "§fAngler Belt", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(25, ItemStackCreator.getStackHead( + "§aBackwater Gloves", + "9a6c887b86b2a59fdea5052413eab74d434c07f52231ce7ac33af5b395beded0", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON GLOVES", + "", + "§7Cost", + "§fAngler Bracelet", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(28, ItemStackCreator.getStackHead( + "§7[Lvl 100] §fHermit Crab", + "26629dfa3fdfef04054024e0156d5e19da5401b1911f59b4bd3982685fe54c2c", + 1, + "§8Fishing Pet", + "", + "§7Defense: §a+20", + "§7Fishing Speed: §b+20", + "§7Sea Creature Chance: §3+2%", + "", + "§6Comfort Zone", + "§7Grants §b+20☂ Fishing Speed §7for §a30s", + "§7upon catching §6Treasure§7.", + "", + "§cThis is a preview of Lvl 100.", + "§cNew pets are lowest level!", + "", + "§7Cost", + "§aRusty Coin §8x32", + "", + "§eClick to trade!" + )); + layout.slot(29, ItemStackCreator.getStackHead( + "§9Stingy Sinker", + "e886d5cac32bd32fc07938908c552b7b27965d92065b3157dfc7ef849281ee9d", + 1, + "§7Grants a §a10% §7chance to not consume", + "§7Bait.", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Sinker §7to a", + "§7Fishing Rod.", + "", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§aRusty Coin §8x64", + "", + "§eClick to trade!" + )); + layout.slot(30, ItemStackCreator.getStackHead( + "§9Speedy Line", + "5cbac3c84e21e65ec88007604c4eba1da391e185544b90252fc16ca695c59b4b", + 1, + "§7Grants §b+10☂ Fishing Speed§7.", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Line §7to a Fishing", + "§7Rod.", + "", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§9Busted Belt Buckle §8x8", + "", + "§eClick to trade!" + )); + layout.slot(31, ItemStackCreator.getStackHead( + "§9Bronze Ship Engine", + "9172c1e729e0ca00193ab5d43e893fabedf5a80fc647258176e8502432885925", + 1, + "§8Ship Part", + "", + "§7Bring this item to §6Captain Baha§7.", + "", + "§7Grants §3+0.5☯ Fishing Wisdom §7when", + "§7attached to your §6Ship§7.", + "", + "§8§l* Soulbound §l*", + "§9§lRARE", + "", + "§7Cost", + "§aRusty Coin §8x64", + "§9Busted Belt Buckle §8x8", + "", + "§eClick to trade!" + )); + layout.slot(32, ItemStackCreator.getStackHead( + "§6Gold Bottle Cap", + "269698fd92fb14827af97e54a3f28f5e2685d7e94bd128c0c27f259df996717c", + 1, + "§8Combinable in Anvil", + "", + "§7When applied to a fishing rod,", + "§7increases its §9Luck of the Sea §7level", + "§7by §a1§7!", + "§8Can be applied once.", + "§8Requires Luck of the Sea VI!", + "", + "§8§oOne man's trash is, indeed, another", + "§8§oman's treasure.", + "", + "§6§lLEGENDARY", + "", + "§7Cost", + "§aRusty Coin §8x512", + "§9Busted Belt Buckle §8x64", + "§5Old Leather Boot §8x8", + "", + "§eClick to trade!" + )); + layout.slot(33, ItemStackCreator.getStackHead( + "§9Treasure Hook", + "9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e", + 1, + "§7Only allows you to catch items and", + "§6Treasure§7.", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Hook §7to a Fishing", + "§7Rod.", + "", + "§4❣ §cRequires §aFishing Skill 25§c.", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§6Bayou Water Orb", + "§5Old Leather Boot §8x4", + "§9Busted Belt Buckle §8x32", + "§aRusty Coin §8x256", + "", + "§cNot unlocked!" + )); + layout.slot(34, ItemStackCreator.getStack( + "§9Travel Scroll to the Bayou", + Material.MAP, + 1, + "§7Consume this item to add its", + "§7destination to your Fast Travel", + "§7options.", + "", + "§7Island: §aBackwater Bayou", + "§7Teleport: §eSpawn", + "", + "§9§lRARE TRAVEL SCROLL", + "", + "§7Cost", + "§9Busted Belt Buckle §8x8", + "", + "§eClick to trade!" + )); + layout.slot(49, ItemStackCreator.getStack( + "§aSell Item", + Material.HOPPER, + 1, + "§7Click items in your inventory to sell", + "§7them to this Shop!" + )); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java new file mode 100644 index 000000000..3f9f8aa0e --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUILine extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUILineGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java new file mode 100644 index 000000000..6591d0734 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUIRodPartGuide extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIRodPartGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java new file mode 100644 index 000000000..07fc59d6b --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUISinker extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUISinkerGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCCaptainBaha.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCCaptainBaha.java new file mode 100644 index 000000000..8e232ac42 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCCaptainBaha.java @@ -0,0 +1,75 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; + +public class NPCCaptainBaha extends HypixelNPC { + + public NPCCaptainBaha() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§6Captain Baha", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "A9Wh529RWV2HEMvVnPzQEPfvT7p8m2GU8IB5FowBVYRash8GUSC6OvO88v5eBXAsCJvAauOnCFkp0DrxNTHUTS6E8rcGpo5ieHTr+QYglXIlA8S+rgA5eGODgI3LEtOZucHJ6H64a23Bu41lNMpN2c+LzQbisqC9WBnfVBxYo6qrzgh5JBGsRDIg2h3UKmTnNgJPuhN2cwRDDlHG8/k+xES5ZqyEFvdjGn6O5HHL6xyMkCukjZN0E8s03NkpkKxZXEm1M/Eg8EWtwGqZIa3DHNmxchYok4mDPMst8iRy4pGRlJN+VBCmGLIV7pq4QZlGzuXWplrX/PAOb+B36Rg67SHvmIk23tpnu+7uvB3rw9NedWY1+xLp8W4gPKpynOobSCbKiJ6bX0mCQfURVh2svFT5nG/VnKCL0TE8CUiTxOuxJR8QWwWRI4BMRMJQfQxy0mofvPnR5g1XUnHzvGWr4m44dmooqyCgB4W9iysADAEgc9CVtizjroopAJLXCtfsxwIuioHaZsBKQU1NpvpH55bPqf//RI9FyJJwOXTgX7fbF49z0eAgjnRAyF9VE9VYI2hFZwa3BIFnvdGxlZhE63QPB+nmKQMT0WzTz15lm77lxvvpQsurkm2gKr6FlL9+SokbTUuQmisyzS84s2EocpRscgc9JF1Dv/NjK7T+3GU="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MDQxOTU1NzI0NiwKICAicHJvZmlsZUlkIiA6ICIzY2I3YTA3YWY3ZjM0ZWZiYTlkNGI4ODQ3NDM4Mzc0ZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJBUkJVWklLMTIwMTMiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzcxYzQ0YWQ0MDdjMDIxNzM3YWQ3ODkwN2I1MDY4ZDdiY2MwYzY1OGIyYTJmYmFiZjAxNzA2NTYzYmQ5NDQ3ZCIKICAgIH0KICB9Cn0="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(-22.5, 75, -8.5, -115, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) { + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_VISITED_BACKWATER_BAYOU)) { + setDialogue(player, "arrived").thenRun(() -> + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_VISITED_BACKWATER_BAYOU, true)); + return; + } + + setDialogue(player, "idle"); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("arrived").lines(new String[]{ + "Land ho! We have arrived at the §2Backwater Bayou§f!", + "You go on and explore! Come back to the §6Ship §fand set sail when you're done!" + }).build(), + DialogueSet.builder() + .key("idle").lines(new String[]{ + "The §6Ship Navigator §fis yours whenever you're ready to head back.", + "Don't keep the marsh waiting too long, though." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCHattie.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCHattie.java new file mode 100644 index 000000000..10b6e5f33 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCHattie.java @@ -0,0 +1,69 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.stream.Stream; + +public class NPCHattie extends HypixelNPC { + + public NPCHattie() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§dHattie", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "vQ5zgSiec5YR9aUfRwR+dZH29487jWT9Pr7PfdIx9pCuK07orJTg5/h8LQBsLFFiNNxQDnENw7/JeaRUP9JxZcxT/OjVLGnlR/P5fn+AET6tSok86mYS81JMDuFPFR2qhoEPBEmOnT0JDmMW4MCCVZtjBz5ENvHvVelZ3eDqy5KROz2u1qwjVBL6QToyT1pLravS8Y/juJDkmFEr4HW76cErnsXU73TOcJ8VeN0oV8KMeKyayLnFK6zZ0OMHZmBEDyQJ59tfoNo12jkdyEZ2rIo/Ix2inZ/VB4QYA+sODyFbTb+YGWSOBU50fkGngwLXsCsc51xm3nGNm3+fVvO5Y6MoVKsUk9G7pddppFdw0G/dOLuoyMTtcWVbuYPqvVhd+b47h5z3zG5767FmZbm2QwlR1VqKC6KqyZFSR5T8p6RdZxz5to+d6RGs1reK5tCGyyPwyVc0TW1hTXQ523uiMYmPKbRWUssjd2uypIAFSiytjVWRl9LI2K5QrRazyv4t8e4JIoDczELdgM8y2qxHrbb4rdMbkSS2/KQnYWDBZoR4xprZR0j4rOxbXVjwQ/lZsHhYV7SPbtun2sHyNd/nD+XvydM7V7Zjci1Zt48AvHpkHGn+4J/eTLpBHe4C4aKdDCnnfdwb1F3DPWyQKs5nsc/LSvTacfwYZwW7SQ6f+U0="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTczOTk4ODE2OTQyNCwKICAicHJvZmlsZUlkIiA6ICI0YWY1YmQ3NTdmZDE0MWEwOTczYmUxNTFkZWRjNmM5ZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJjcmFzaGludG95b3VybW9tIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2E4NzQxZTFiZTdjY2VlN2E3YjY2ZDE5YWMwZjZmNDM2ZmFlNjhkNGFkZjNlNzVkMjBmNTk1MjIxYzIyOTMwMSIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9"; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(17.5, 71, 14.5, -135, 20); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + HypixelPlayer player = event.player(); + if (isInDialogue(player)) { + return; + } + + setDialogue(player, "hotspots-" + (1 + (int) (Math.random() * 2))); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("hotspots-1").lines(new String[]{ + "Hotspots are temporary rings that appear above the water or lava.", + "Fish inside one and you'll get a bonus while your bobber stays in it.", + "The Bayou, Hub, Spider's Den, and Crimson Isle all have them. Keep your eyes open!" + }).build(), + DialogueSet.builder() + .key("hotspots-2").lines(new String[]{ + "Hotspots can boost your §bFishing Speed§f, §3Sea Creature Chance§f, §6Treasure Chance§f, or even §5Trophy Fish Chance§f.", + "Some creatures only show up when you're fishing inside one.", + "If the water starts glowing, don't waste the opportunity." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCJunkerJoel.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCJunkerJoel.java new file mode 100644 index 000000000..d66c9ac7d --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCJunkerJoel.java @@ -0,0 +1,64 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.backwaterbayou.gui.GUIJunkerJoel; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.stream.Stream; + +public class NPCJunkerJoel extends HypixelNPC { + + public NPCJunkerJoel() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§2Junker Joel", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "cuTJRxZ5c0tPjwo+PK4Wuzp8Gymj87qIm+p9QQHLfgQWj75RkXAigGjcbWcIpBol4eP9xQ1KpZwuCfoIToRc9Y1HMMNAzdm459KJfSkhiHWMXggJBbW8CFvdKVIhQHMVKBCA0cgVDQE/ozNScwS63TXSSIE7iyHMAbFxoOw6hZMd9oQuaujnFt2lYda0yLmOSq1CKR+xUbLOsDqOPtQRaKw7hdYL99QzX8rMu7CAdPJkbnvb8ki/r/hkzqj0HikoBM02XZycdArMHq9MQPT6M7XKgRur/1AfMkaIFMTTGDVcIMQiWBY10I7UGui/hWm2jnIBjJrI/bvN5VRBeTxeoSaFSxQfZ1YJpLfuGjBY4XitD1W7UL11Z6BTI63VVIdW6L7vYm/4pRek/AAEfwa/cmEQelM44pvj3Yk/9/RWoZ0J+Sb/v6VX96apDmHk30pRDSx0gWrBXf9DGW56VFtiklR2edZI7OgGtfNcu83S2fmVZoxYO5zCEejbNj9tI7W2eY8Qmoqwo7J6OlfJWc3Ng/ucHBqlVR/T3sxnsyOE24BjvqPM349eyas079dzGc8PlYyvMj6RXtjX/Jz9clFdAXw94zENzvUltPNxcJgj9Xt41/9L7oEcEn9okM5kCqzfJXIAvZQmiZSv3rxYNg6TEoCY1r+eVRwRJMDTgefOpcs="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MDE1NjgzNjkxNCwKICAicHJvZmlsZUlkIiA6ICI2NDU4Mjc0MjEyNDg0MDY0YTRkMDBlNDdjZWM4ZjcyZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaDNtMXMiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWE0NTAzZTdmMTYxOTg1ZDAyNzMxYTMwNjczNWFlOTRlNDA3Yzc5MGY1ZWI0N2I2MzExOTA3N2RkODgzNDc2YiIKICAgIH0KICB9Cn0="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(6.5, 72, 4.5, 135, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + HypixelPlayer player = event.player(); + if (isInDialogue(player)) { + return; + } + + setDialogue(player, "intro").thenRun(() -> player.openView(new GUIJunkerJoel())); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("intro").lines(new String[]{ + "People dump all sorts of junk in these waters, and I make sure none of it goes to waste.", + "Bring me your scraps and I'll trade you something useful.", + "If you're planning to fish up a mountain of junk, you'll want a §9Junk Sinker§f." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCRoddy.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCRoddy.java new file mode 100644 index 000000000..3c26b83b3 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCRoddy.java @@ -0,0 +1,74 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.backwaterbayou.gui.GUIFishingRodParts; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; + +public class NPCRoddy extends HypixelNPC { + + public NPCRoddy() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§6§lROD MECHANIC", "§2Roddy", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "m9YzKGb9O5Hs5mLECUJS6JmzLBDBQy9J768PK8lwNBEmF5a9J8Xdy93EWCAtCGCAFMar9CWRmyqt9Ees7u/3PHNtUVg9EkmvG27cPEIMUB2lqVir0U62pfNcR+5JkjjqaleDLhcOBgXdN9iVHJUcZq2tTY3t1eVX5OKI8K9SVjGvxgGMKxFmR1758eqwh9Krvb7AXI1/zRaRdFRsdXs2SgrvI/HcD4GN4vrjl6ZteOprTY4vB9oHZZSBLffkL28psxckC6JwvpiEahEtHKo1lS43qMpKtqKX9qwSs8WZ8/9A+/dXwB6g0+b1C/JSFWkyETFfFs1dUSdVsThkqGstRmt6c6Ko4xdvS61WQYLS4pbEbPN4kk0WapdqrWrrqNvjjcBUd94mnqNgvA0N+qPVOD/QkLGLvZDfXC5Iyv2BlpdeQHosTgn9ZPDjotESMwWrGwhm/uLLxNc2Z/rAGke5zTjz4v1JDSha7uyXT1yZ3oCckUqhbGFzmx5YOQoT/PbWr/mONQbYWTJ5GnSeWIIEs616Icwn+Rlw0qF+3EPUeR7QRO1bt5aqpmCUcZvrYoMyS1pvLDjS66MyuK5mEsQDEY5Uufux4iB3J0rrSGSgoC/XP1s6kGlz+jFRbDT9VPv/m72msPS35uAB6nCnI3o6uXKr0GrUGX9BiHB68Us0Pfs="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MTI3MjI2NDk0NiwKICAicHJvZmlsZUlkIiA6ICIzOWEzOTMzZWE4MjU0OGU3ODQwNzQ1YzBjNGY3MjU2ZCIsCiAgInByb2ZpbGVOYW1lIiA6ICJkZW1pbmVjcmFmdGVybG9sIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzE3Y2FkOWYyN2Q3NGRlM2U1OWYyYTUxN2QwNGEyODJlMmNmODZlNGM1ZTQwNjM5ZGFlY2E3YjFhYWU3ZjVhNzEiCiAgICB9CiAgfQp9"; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(21.5, 78, -23.5, 135, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) { + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_RODDY)) { + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_RODDY, true); + player.openView(new GUIFishingRodParts()); + }); + return; + } + + player.openView(new GUIFishingRodParts()); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "If your rod's missing some punch, you've come to the right mechanic.", + "Hooks, lines, and sinkers can change what your rod is best at catching.", + "Put a §aFishing Rod §fin the slot and I'll show you what parts fit." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/tab/BackwaterBayouServerModule.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/tab/BackwaterBayouServerModule.java deleted file mode 100644 index 3c7bd7024..000000000 --- a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/tab/BackwaterBayouServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.backwaterbayou.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class BackwaterBayouServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.backwater_bayou", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/TypeBedWarsConfiguratorLoader.java b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/TypeBedWarsConfiguratorLoader.java index dbc62a348..94457fa4e 100644 --- a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/TypeBedWarsConfiguratorLoader.java +++ b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/TypeBedWarsConfiguratorLoader.java @@ -9,7 +9,7 @@ import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; import net.swofty.commons.bedwars.map.BedWarsMapsConfig; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.HypixelTypeLoader; import net.swofty.type.generic.command.HypixelCommand; @@ -135,7 +135,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataLoad.java b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataLoad.java index d888024e5..d48a3bc16 100644 --- a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataLoad.java +++ b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataLoad.java @@ -5,8 +5,9 @@ import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import org.bson.Document; import org.tinylog.Logger; @@ -16,7 +17,7 @@ public class ActionBedWarsLobbyDataLoad implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, phase = EventPhase.LOAD_DATA, order = 10) public void run(AsyncPlayerConfigurationEvent event) { Logger.info("Loading BedWars data for player: " + event.getPlayer().getUsername() + "..."); @@ -38,4 +39,4 @@ public void run(AsyncPlayerConfigurationEvent event) { Logger.info("Successfully loaded BedWars data for player: " + player.getUsername()); } -} \ No newline at end of file +} diff --git a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataSave.java b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataSave.java index 45decca71..13e20d4f8 100644 --- a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataSave.java +++ b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionBedWarsLobbyDataSave.java @@ -5,8 +5,9 @@ import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import org.tinylog.Logger; @@ -14,7 +15,7 @@ public class ActionBedWarsLobbyDataSave implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.PERSIST, order = 10) public void run(PlayerDisconnectEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); UUID uuid = player.getUuid(); @@ -36,4 +37,4 @@ public void run(PlayerDisconnectEvent event) { Logger.info("Successfully saved BedWars account data for: " + player.getUsername()); } -} \ No newline at end of file +} diff --git a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerBreak.java b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerBreak.java index 0025f6908..bcf8b49ec 100644 --- a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerBreak.java +++ b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerBreak.java @@ -3,13 +3,14 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerBreak implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER , requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER , requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockBreakEvent event) { event.setCancelled(true); } diff --git a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerDataSpawn.java b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerDataSpawn.java index 0b83de168..447bb9eeb 100644 --- a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerDataSpawn.java +++ b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerDataSpawn.java @@ -5,14 +5,15 @@ import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; if (!(HypixelConst.getTypeLoader().getType() == ServerType.BEDWARS_CONFIGURATOR)) return; @@ -25,4 +26,4 @@ public void run(PlayerSpawnEvent event) { BedWarsDataHandler handler = BedWarsDataHandler.getUser(player.getUuid()); handler.runOnLoad(player); } -} \ No newline at end of file +} diff --git a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerJoin.java b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerJoin.java index 9b316ab7c..5622fd508 100644 --- a/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerJoin.java +++ b/type.bedwarsconfigurator/src/main/java/net/swofty/type/bedwarsconfigurator/events/ActionPlayerJoin.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/TypeBedWarsGameLoader.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/TypeBedWarsGameLoader.java index 683844e13..a9c83c265 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/TypeBedWarsGameLoader.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/TypeBedWarsGameLoader.java @@ -21,10 +21,9 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocol; import net.swofty.proxyapi.ProxyService; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.pvp.MinestomPvP; import net.swofty.pvp.feature.CombatFeatureSet; import net.swofty.pvp.feature.CombatFeatures; @@ -246,7 +245,7 @@ public void afterInitialize(MinecraftServer server) { commonsGames.add(commonsGame); } - var heartbeat = new GameHeartbeatProtocolObject.HeartbeatMessage( + var heartbeat = new GameHeartbeatProtocol.HeartbeatMessage( uuid, shortName, getType(), @@ -322,19 +321,19 @@ public List getNPCs() { @Override @SuppressWarnings("unchecked") - public List> getTypedServiceHandlers() { + public List> getServiceHandlers() { return (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.bedwarsgame.redis.service", - TypedServiceHandler.class + RedisMessageHandler.class ).toList(); } @Override @SuppressWarnings("unchecked") - public List> getTypedProxyHandlers() { - return (List>) (List) HypixelGenericLoader.loopThroughPackage( + public List> getProxyHandlers() { + return (List>) (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.bedwarsgame.redis", - TypedProxyHandler.class + RedisMessageHandler.class ).toList(); } diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionEntityAttack.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionEntityAttack.java index ec8123da2..915ea4190 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionEntityAttack.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionEntityAttack.java @@ -7,12 +7,13 @@ import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionEntityAttack implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PrepareAttackEvent event) { if (event.getEntity() instanceof BedWarsPlayer player) { Game game = player.getGame(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameBreak.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameBreak.java index 59e52345c..b415738a3 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameBreak.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameBreak.java @@ -16,15 +16,16 @@ import net.swofty.type.bedwarsgame.stats.BedWarsStatsRecorder; import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import java.util.Map; import java.util.Objects; public class ActionGameBreak implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockBreakEvent event) { BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); Block blockBeingBroken = event.getBlock(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCombatTrack.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCombatTrack.java index c9bfa0323..dac83263e 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCombatTrack.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCombatTrack.java @@ -7,12 +7,13 @@ import net.swofty.type.bedwarsgame.game.GameStatus; import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionGameCombatTrack implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ENTITY, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ENTITY, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(FinalDamageEvent event) { if (!(event.getEntity() instanceof BedWarsPlayer victim)) { return; diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCustomItems.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCustomItems.java index 1f7fff373..d2d06946b 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCustomItems.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameCustomItems.java @@ -19,8 +19,9 @@ import net.swofty.type.bedwarsgame.game.GameStatus; import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import java.util.UUID; @@ -64,14 +65,14 @@ private static void handleFireballExplosion(FireballProjectile fireball) { fireball.remove(); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(ProjectileCollideWithBlockEvent event) { if (event.getEntity().getEntityType() == EntityType.FIREBALL) { handleFireballExplosion((FireballProjectile) event.getEntity()); } } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(ProjectileCollideWithEntityEvent event) { if (event.getEntity().getEntityType() != EntityType.FIREBALL) { return; @@ -97,22 +98,22 @@ public void run(ProjectileCollideWithEntityEvent event) { handleFireballExplosion(fireball); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemOnBlockEvent event) { TypeBedWarsGameLoader.getItemHandler().onItemUseOnBlock(event); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerFinishItemUseEvent event) { TypeBedWarsGameLoader.getItemHandler().onItemFinishUse(event); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemEvent event) { TypeBedWarsGameLoader.getItemHandler().onItemUse(event); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockPlaceEvent event) { TypeBedWarsGameLoader.getItemHandler().onBlockPlace(event); } diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameDeath.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameDeath.java index 51e723331..a6fe9d52a 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameDeath.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameDeath.java @@ -30,8 +30,9 @@ import net.swofty.type.bedwarsgame.stats.BedWarsStatsRecorder; import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import org.tinylog.Logger; import java.time.Duration; @@ -41,7 +42,7 @@ public class ActionGameDeath implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerDeathEvent event) { BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameMove.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameMove.java index 5a272d88b..c6fb88df9 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameMove.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGameMove.java @@ -14,15 +14,16 @@ import net.swofty.type.bedwarsgame.game.GameStatus; import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import java.util.List; import java.util.Map; public class ActionGameMove implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePickup.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePickup.java index 4d557a9bb..60aceab6c 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePickup.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePickup.java @@ -9,13 +9,14 @@ import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.bedwarsgame.user.ExperienceCause; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import org.jetbrains.annotations.Nullable; public class ActionGamePickup implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PickupItemEvent event) { ItemStack itemStack = event.getItemEntity().getItemStack(); if (event.getLivingEntity() instanceof BedWarsPlayer player) { diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlace.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlace.java index fb8034568..87acc11ce 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlace.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlace.java @@ -15,14 +15,15 @@ import net.swofty.type.bedwarsgame.game.GameStatus; import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.utility.MathUtility; import org.tinylog.Logger; public class ActionGamePlace implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockPlaceEvent event) { BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); Game game = player.getGame(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlayerEvent.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlayerEvent.java index 0ee3904a3..210fee9c9 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlayerEvent.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionGamePlayerEvent.java @@ -20,8 +20,9 @@ import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.bedwarsgame.util.BedWarsInventoryManipulator; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import org.tinylog.Logger; import java.time.Duration; @@ -32,7 +33,7 @@ public class ActionGamePlayerEvent implements HypixelEventClass { public static final ConcurrentHashMap ACTIVE_TEAM_CHESTS = new ConcurrentHashMap<>(); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(InventoryPreClickEvent event) { if (!(event.getInventory() instanceof PlayerInventory)) { return; @@ -53,30 +54,33 @@ public void run(InventoryPreClickEvent event) { } } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + private static final java.util.Set UNDROPPABLE_TOOLS = java.util.Set.of( + "wooden_sword", + "wooden_pickaxe", + "wooden_axe", + "stone_axe", + "iron_pickaxe", + "iron_axe", + "diamond_pickaxe", + "diamond_axe" + ); + + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(ItemDropEvent event) { - switch (event.getItemStack().material().name()) { - case "wooden_sword": - case "wooden_pickaxe": - case "wooden_axe": - case "stone_axe": - case "iron_pickaxe": - case "iron_axe": - case "diamond_pickaxe": - case "diamond_axe": - event.setCancelled(true); - event.getPlayer().sendMessage("§cYou cannot drop your tools!"); - break; - default: - ItemEntity itemEntity = new ItemEntity(event.getItemStack()); - itemEntity.setInstance(event.getPlayer().getInstance(), event.getPlayer().getPosition().add(0, event.getPlayer().getEyeHeight(), 0)); - itemEntity.setVelocity(event.getPlayer().getPosition().add(0, 0.3, 0).direction().mul(6)); - itemEntity.setPickupDelay(Duration.ofMillis(500)); - break; + if (UNDROPPABLE_TOOLS.contains(event.getItemStack().material().name())) { + event.setCancelled(true); + event.getPlayer().sendMessage("§cYou cannot drop your tools!"); + return; } + + ItemEntity itemEntity = new ItemEntity(event.getItemStack()); + itemEntity.setInstance(event.getPlayer().getInstance(), + event.getPlayer().getPosition().add(0, event.getPlayer().getEyeHeight(), 0)); + itemEntity.setVelocity(event.getPlayer().getPosition().add(0, 0.3, 0).direction().mul(6)); + itemEntity.setPickupDelay(Duration.ofMillis(500)); } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { Block block = event.getBlock(); BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); @@ -146,7 +150,7 @@ public void run(PlayerBlockInteractEvent event) { } } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerStartDiggingEvent event) { Block block = event.getBlock(); BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerChat.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerChat.java index a1eba9d36..e0764f85b 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerChat.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerChat.java @@ -12,8 +12,9 @@ import net.swofty.type.generic.data.datapoints.DatapointLeaderboardLong; import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.categories.Rank; @@ -21,7 +22,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { final BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDataSpawn.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDataSpawn.java index 4b8d9a8e0..6ae7713c7 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDataSpawn.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDataSpawn.java @@ -6,13 +6,14 @@ import net.swofty.pvp.projectile.entities.ArrowProjectile; import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); @@ -23,4 +24,4 @@ public void run(PlayerSpawnEvent event) { // Registers the bow module, which creates event nodes for the player for bow behavior new BowModule(player.eventNode(), (p, i) -> new ArrowProjectile(EntityType.ARROW, p)); } -} \ No newline at end of file +} diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDisconnect.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDisconnect.java index c266a5140..d60d3471e 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDisconnect.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerDisconnect.java @@ -7,13 +7,14 @@ import net.swofty.type.bedwarsgame.game.GameStatus; import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerDisconnect implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void run(PlayerDisconnectEvent event) { final BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); Game game = player.getGame(); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerJoin.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerJoin.java index e878f3ff7..e386341dd 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerJoin.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/events/ActionPlayerJoin.java @@ -9,16 +9,17 @@ import net.swofty.type.bedwarsgame.user.BedWarsPlayer; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.generic.redis.service.TypedGameInformationHandler; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.generic.redis.service.GameInformationHandler; import net.swofty.type.generic.utility.MathUtility; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final BedWarsPlayer player = (BedWarsPlayer) event.getPlayer(); Logger.info("Player " + player.getUsername() + " joined the server from origin server " + player.getOriginServer()); @@ -31,7 +32,7 @@ public void run(AsyncPlayerConfigurationEvent event) { private void tryJoinGame(BedWarsPlayer player, boolean isRetry) { if (!player.isOnline()) return; - String preferredGameId = TypedGameInformationHandler.game.remove(player.getUuid()); + String preferredGameId = GameInformationHandler.game.remove(player.getUuid()); if (preferredGameId == null) { if (!isRetry) { Logger.info("No game assignment found for " + player.getUsername() + ", retrying in 1 second..."); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/game/Game.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/game/Game.java index 30a1209cf..9ad0cb975 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/game/Game.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/game/Game.java @@ -40,7 +40,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -110,7 +109,7 @@ public void join(BedWarsPlayer player) { int maxPlayers = getMaxPlayers(); String randomLetters = UUID.randomUUID().toString().replaceAll("-", "") - .substring(0, new Random().nextInt(10) + 4); + .substring(0, java.util.concurrent.ThreadLocalRandom.current().nextInt(10) + 4); for (BedWarsPlayer p : players) { String name = p.getUuid().compareTo(player.getUuid()) == 0 ? player.getUsername() : "§k" + randomLetters; p.sendMessage(name + " §ehas joined (§b" + players.size() + "§e/§b" + maxPlayers + "§e)"); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/item/SimpleInteractableItem.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/item/SimpleInteractableItem.java index a1a0c7881..b50ad4a18 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/item/SimpleInteractableItem.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/item/SimpleInteractableItem.java @@ -28,27 +28,15 @@ public ItemStack getItemStack() { new CustomData(CompoundBinaryTag.builder().putString("item", id).build())); } - public void onItemFinishUse(PlayerFinishItemUseEvent event) { - // stub - } + public void onItemFinishUse(PlayerFinishItemUseEvent event) {} - public void onItemUseOnBlock(PlayerUseItemOnBlockEvent event) { - // stub - } + public void onItemUseOnBlock(PlayerUseItemOnBlockEvent event) {} - public void onItemUse(PlayerUseItemEvent event) { - // stub - } + public void onItemUse(PlayerUseItemEvent event) {} - public void onItemDrop(ItemDropEvent event) { - // stub - } + public void onItemDrop(ItemDropEvent event) {} - public void onItemInteract(PlayerInstanceEvent event) { - // stub - } + public void onItemInteract(PlayerInstanceEvent event) {} - public void onBlockPlace(PlayerBlockPlaceEvent event) { - // stub - } + public void onBlockPlace(PlayerBlockPlaceEvent event) {} } diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/redis/service/TypedInstantiateGameHandler.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/redis/service/InstantiateGameHandler.java similarity index 85% rename from type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/redis/service/TypedInstantiateGameHandler.java rename to type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/redis/service/InstantiateGameHandler.java index 6310515b7..b53952246 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/redis/service/TypedInstantiateGameHandler.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/redis/service/InstantiateGameHandler.java @@ -2,25 +2,26 @@ import net.swofty.commons.bedwars.BedwarsGameType; import net.swofty.commons.bedwars.map.BedWarsMapsConfig; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol.Request; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.bedwarsgame.TypeBedWarsGameLoader; import net.swofty.type.bedwarsgame.game.Game; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedInstantiateGameHandler implements TypedServiceHandler { +public class InstantiateGameHandler implements RedisMessageHandler { private static final InstantiateGamePushProtocol PROTOCOL = new InstantiateGamePushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request request) { + public Response handle(Request request, RedisMessageContext context) { try { BedwarsGameType gameType = BedwarsGameType.valueOf(request.gameType().toUpperCase()); diff --git a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/util/ColorUtil.java b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/util/ColorUtil.java index c7a5c878e..9d044c604 100644 --- a/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/util/ColorUtil.java +++ b/type.bedwarsgame/src/main/java/net/swofty/type/bedwarsgame/util/ColorUtil.java @@ -1,5 +1,8 @@ package net.swofty.type.bedwarsgame.util; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import org.jetbrains.annotations.Nullable; @@ -7,7 +10,9 @@ import java.awt.*; import java.lang.reflect.Field; -public class ColorUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ColorUtil { + @Nullable public static Color getColorByName(String name) { diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/TypeBedWarsLobbyLoader.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/TypeBedWarsLobbyLoader.java index b11bef5af..83334b7f3 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/TypeBedWarsLobbyLoader.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/TypeBedWarsLobbyLoader.java @@ -7,8 +7,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.bedwarslobby.hologram.LeaderboardHologramManager; import net.swofty.type.bedwarslobby.item.impl.BedWarsMenu; import net.swofty.type.bedwarslobby.item.impl.Collectibles; @@ -190,15 +189,15 @@ public List getNPCs() { @Override @SuppressWarnings("unchecked") - public List> getTypedServiceHandlers() { + public List> getServiceHandlers() { return (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.bedwarslobby.redis.service", - TypedServiceHandler.class + RedisMessageHandler.class ).toList(); } @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/commands/RejoinCommand.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/commands/RejoinCommand.java index 3cf6020ad..90f4b435e 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/commands/RejoinCommand.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/commands/RejoinCommand.java @@ -1,8 +1,8 @@ package net.swofty.type.bedwarslobby.commands; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.RejoinGameProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocol; +import net.swofty.commons.protocol.objects.orchestrator.RejoinGameProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.command.CommandParameters; import net.swofty.type.generic.command.HypixelCommand; @@ -26,18 +26,18 @@ public void registerUsage(MinestomCommand command) { HypixelPlayer player = (HypixelPlayer) sender; // Query orchestrator for active game - RejoinGameProtocolObject.RejoinGameRequest request = - new RejoinGameProtocolObject.RejoinGameRequest(player.getUuid()); + RejoinGameProtocol.RejoinGameRequest request = + new RejoinGameProtocol.RejoinGameRequest(player.getUuid()); ORCHESTRATOR.handleRequest(request).thenAccept(response -> { - if (response instanceof RejoinGameProtocolObject.RejoinGameResponse resp) { + if (response instanceof RejoinGameProtocol.RejoinGameResponse resp) { if (resp.hasActiveGame() && resp.server() != null) { // Send the player to the game player.sendMessage("§aRejoining your game..."); // Notify the game server about this player - ChooseGameProtocolObject.ChooseGameMessage chooseMsg = - new ChooseGameProtocolObject.ChooseGameMessage( + ChooseGameProtocol.ChooseGameMessage chooseMsg = + new ChooseGameProtocol.ChooseGameMessage( player.getUuid(), resp.server(), resp.gameId() diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerChat.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerChat.java index ec5500b25..5c7f62d8e 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerChat.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerChat.java @@ -11,8 +11,9 @@ import net.swofty.type.generic.data.datapoints.DatapointLeaderboardLong; import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; @@ -21,7 +22,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER , requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER , requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDataSpawn.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDataSpawn.java index a246e477c..9deece03b 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDataSpawn.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDataSpawn.java @@ -11,8 +11,9 @@ import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.quest.QuestData; import net.swofty.type.generic.quest.QuestDefinition; import net.swofty.type.generic.quest.QuestRegistry; @@ -22,7 +23,7 @@ public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; if (!(HypixelConst.getTypeLoader().getType() == ServerType.BEDWARS_LOBBY)) return; @@ -79,4 +80,4 @@ private void autoAcceptQuests(HypixelPlayer player, AchievementCategory category " " + category.getDisplayName() + " quest" + (startedCount > 1 ? "s" : "") + "!"); } } -} \ No newline at end of file +} diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDisconnect.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDisconnect.java index d894b267e..b590cd78c 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDisconnect.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerDisconnect.java @@ -3,13 +3,14 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.bedwarslobby.BedWarsLobbyScoreboard; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerDisconnect implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void run(PlayerDisconnectEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); BedWarsLobbyScoreboard.removeCache(player); diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerSpawn.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerSpawn.java index 8910be21a..1ec3d8511 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerSpawn.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionPlayerSpawn.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.bedwarslobby.TypeBedWarsLobbyLoader; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.minestom.server.entity.GameMode; public class ActionPlayerSpawn implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.SPAWN) public void run(PlayerSpawnEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); player.setGameMode(GameMode.SURVIVAL); //noticed stayed in Spectator after Bedwars game end. This is Hacky, but I don't see a reason why gamemode shouldn't be enforced on lobby join. -petethepossum diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionRejoinCheck.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionRejoinCheck.java index 77d539c7e..b54536780 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionRejoinCheck.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/events/ActionRejoinCheck.java @@ -5,29 +5,30 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.RejoinGameProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.RejoinGameProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.utility.MathUtility; public class ActionRejoinCheck implements HypixelEventClass { private static final ProxyService ORCHESTRATOR = new ProxyService(ServiceType.ORCHESTRATOR); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); // Delay slightly to ensure player is fully spawned MathUtility.delay(() -> { // Check if player has an active game to rejoin - RejoinGameProtocolObject.RejoinGameRequest request = - new RejoinGameProtocolObject.RejoinGameRequest(player.getUuid()); + RejoinGameProtocol.RejoinGameRequest request = + new RejoinGameProtocol.RejoinGameRequest(player.getUuid()); ORCHESTRATOR.handleRequest(request).thenAccept(response -> { - if (response instanceof RejoinGameProtocolObject.RejoinGameResponse resp + if (response instanceof RejoinGameProtocol.RejoinGameResponse resp && resp.hasActiveGame()) { // Show rejoin message Component message = Component.text("You have a game currently ongoing! ", NamedTextColor.RED) diff --git a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/gui/GUIMapSelection.java b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/gui/GUIMapSelection.java index 283df8b17..c2800cdbc 100644 --- a/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/gui/GUIMapSelection.java +++ b/type.bedwarslobby/src/main/java/net/swofty/type/bedwarslobby/gui/GUIMapSelection.java @@ -9,7 +9,7 @@ import net.swofty.commons.bedwars.BedwarsGameType; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.data.handlers.BedWarsDataHandler; import net.swofty.type.lobby.LobbyOrchestratorConnector; @@ -69,12 +69,12 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { private void loadMaps(HypixelPlayer player) { ProxyService orchestratorService = new ProxyService(ServiceType.ORCHESTRATOR); - GetMapsProtocolObject.GetMapsMessage message = - new GetMapsProtocolObject.GetMapsMessage(ServerType.BEDWARS_GAME, gameType.toString()); + GetMapsProtocol.GetMapsMessage message = + new GetMapsProtocol.GetMapsMessage(ServerType.BEDWARS_GAME, gameType.toString()); orchestratorService.handleRequest(message) .thenAccept(response -> { - if (response instanceof GetMapsProtocolObject.GetMapsResponse mapsResponse) { + if (response instanceof GetMapsProtocol.GetMapsResponse mapsResponse) { maps = mapsResponse.maps(); mapsLoaded = true; diff --git a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java b/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java index e8e3dc589..510ae0db6 100644 --- a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java +++ b/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java @@ -5,8 +5,8 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.type.crimsonisle.tab.CrimsonIsleServerModule; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.HypixelEventClass; @@ -41,9 +41,7 @@ public void afterInitialize(MinecraftServer server) { @Override public LoaderValues getLoaderValues() { return new LoaderValues( - (type) -> switch (type) { - default -> new Pos(-360.5, 80, -430.5, -180, 0); - }, // Spawn position + (type) -> new Pos(-360.5, 80, -430.5, -180, 0), // Spawn position true // Announce death messages ); } @@ -55,7 +53,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new CrimsonIsleServerModule(), + new AreaServerModule("tablist.server_info.area.crimson_isle"), new AccountInformationModule() )); } @@ -85,7 +83,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/events/ActionPlayerJoin.java b/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/events/ActionPlayerJoin.java index c2345763d..42cdfb306 100644 --- a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/events/ActionPlayerJoin.java +++ b/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/tab/CrimsonIsleServerModule.java b/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/tab/CrimsonIsleServerModule.java deleted file mode 100644 index 1f4002568..000000000 --- a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/tab/CrimsonIsleServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.crimsonisle.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class CrimsonIsleServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.crimson_isle", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/TypeDeepCavernsLoader.java b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/TypeDeepCavernsLoader.java index ef8c2cf61..41b402a6a 100644 --- a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/TypeDeepCavernsLoader.java +++ b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/TypeDeepCavernsLoader.java @@ -5,8 +5,8 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.type.deepcaverns.tab.DeepCavernsServerModule; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; @@ -57,7 +57,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new DeepCavernsServerModule(), + new AreaServerModule("tablist.server_info.area.deep_caverns"), new AccountInformationModule() )); } @@ -87,7 +87,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/events/ActionPlayerJoin.java b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/events/ActionPlayerJoin.java index f0a580201..1ea029ff4 100644 --- a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/events/ActionPlayerJoin.java +++ b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/tab/DeepCavernsServerModule.java b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/tab/DeepCavernsServerModule.java deleted file mode 100644 index 5be8972ce..000000000 --- a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/tab/DeepCavernsServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.deepcaverns.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class DeepCavernsServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.deep_caverns", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/TypeDungeonHubLoader.java b/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/TypeDungeonHubLoader.java index 7d9425623..72a76bf09 100644 --- a/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/TypeDungeonHubLoader.java +++ b/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/TypeDungeonHubLoader.java @@ -5,8 +5,8 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.type.dungeonhub.tab.DungeonServerModule; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.HypixelEventClass; @@ -57,7 +57,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new DungeonServerModule(), + new AreaServerModule("tablist.server_info.area.dungeon_hub"), new AccountInformationModule() )); } @@ -87,7 +87,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/events/ActionPlayerJoin.java b/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/events/ActionPlayerJoin.java index a5b97d44d..600c7f9de 100644 --- a/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/events/ActionPlayerJoin.java +++ b/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/events/ActionPlayerJoin.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/tab/DungeonServerModule.java b/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/tab/DungeonServerModule.java deleted file mode 100644 index abf6e8034..000000000 --- a/type.dungeonhub/src/main/java/net/swofty/type/dungeonhub/tab/DungeonServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.dungeonhub.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class DungeonServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.dungeon_hub", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/TypeDwarvenMinesLoader.java b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/TypeDwarvenMinesLoader.java index 8445cda5d..e85957a20 100644 --- a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/TypeDwarvenMinesLoader.java +++ b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/TypeDwarvenMinesLoader.java @@ -12,9 +12,9 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.dwarvenmines.gui.GUIGemstoneGrinder; -import net.swofty.type.dwarvenmines.tab.DwarvenMinesServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.InteractionEntity; @@ -74,7 +74,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new DwarvenMinesServerModule(), + new AreaServerModule("tablist.server_info.area.dwarven_mines"), new AccountInformationModule() )); } @@ -104,7 +104,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerCommissions.java b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerCommissions.java index af9c1d81b..b1582ffb4 100644 --- a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerCommissions.java +++ b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerCommissions.java @@ -7,8 +7,9 @@ import net.swofty.type.dwarvenmines.commission.Objective; import net.swofty.type.dwarvenmines.commission.ObjectiveType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointCommissions; import net.swofty.type.skyblockgeneric.region.RegionType; @@ -23,7 +24,7 @@ public class ActionPlayerCommissions implements HypixelEventClass { private static final Set TITANIUM_BLOCKS = Set.of(Material.POLISHED_DIORITE); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockBreakEvent event) { if (!(event.getPlayer() instanceof SkyBlockPlayer player)) return; diff --git a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerJoin.java b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerJoin.java index 1a8d7d7a5..51a62b68c 100644 --- a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerJoin.java +++ b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/tab/DwarvenMinesServerModule.java b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/tab/DwarvenMinesServerModule.java deleted file mode 100644 index f56bdc9be..000000000 --- a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/tab/DwarvenMinesServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.dwarvenmines.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class DwarvenMinesServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.dwarven_mines", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.galatea/src/main/java/net/swofty/type/galatea/TypeGalateaLoader.java b/type.galatea/src/main/java/net/swofty/type/galatea/TypeGalateaLoader.java index 16abe65c1..9d656f852 100644 --- a/type.galatea/src/main/java/net/swofty/type/galatea/TypeGalateaLoader.java +++ b/type.galatea/src/main/java/net/swofty/type/galatea/TypeGalateaLoader.java @@ -6,8 +6,8 @@ import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; import net.swofty.commons.Songs; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.type.galatea.tab.GalateaServerModule; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.HypixelEventClass; @@ -61,7 +61,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new GalateaServerModule(), + new AreaServerModule("tablist.server_info.area.galatea"), new AccountInformationModule() )); } @@ -91,7 +91,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.galatea/src/main/java/net/swofty/type/galatea/events/ActionPlayerJoin.java b/type.galatea/src/main/java/net/swofty/type/galatea/events/ActionPlayerJoin.java index 322539e91..8807402e1 100644 --- a/type.galatea/src/main/java/net/swofty/type/galatea/events/ActionPlayerJoin.java +++ b/type.galatea/src/main/java/net/swofty/type/galatea/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.galatea/src/main/java/net/swofty/type/galatea/tab/GalateaServerModule.java b/type.galatea/src/main/java/net/swofty/type/galatea/tab/GalateaServerModule.java deleted file mode 100644 index 0cf7ae892..000000000 --- a/type.galatea/src/main/java/net/swofty/type/galatea/tab/GalateaServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.galatea.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class GalateaServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.galatea", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.generic/src/main/java/net/swofty/type/generic/HypixelTypeLoader.java b/type.generic/src/main/java/net/swofty/type/generic/HypixelTypeLoader.java index 4ef484fe6..9a234a8d6 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/HypixelTypeLoader.java +++ b/type.generic/src/main/java/net/swofty/type/generic/HypixelTypeLoader.java @@ -7,8 +7,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.data.GameDataHandler; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.HypixelEventClass; @@ -37,7 +36,7 @@ public interface HypixelTypeLoader { List getNPCs(); - List> getTypedProxyHandlers(); + List> getProxyHandlers(); record LoaderValues(Function spawnPosition, boolean announceDeathMessages) {} @@ -48,7 +47,7 @@ record LoaderValues(Function spawnPosition, boolean announceDea * These handlers will be automatically loaded/saved on player join/quit. * @return List of GameDataHandler classes to load */ - default List> getTypedServiceHandlers() { + default List> getServiceHandlers() { return List.of(); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/achievement/AchievementTier.java b/type.generic/src/main/java/net/swofty/type/generic/achievement/AchievementTier.java index f7ab403ac..c6bd06db0 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/achievement/AchievementTier.java +++ b/type.generic/src/main/java/net/swofty/type/generic/achievement/AchievementTier.java @@ -2,6 +2,17 @@ public record AchievementTier(int tier, int goal, int points) { public String getRomanNumeral() { + return toRomanNumeral(tier); + } + + /** + * Tier-friendly Roman numeral converter. Tiers in this codebase don't + * exceed V in practice, so the higher-order rules of + * {@link net.swofty.commons.StringUtility#getAsRomanNumeral} aren't + * needed — and a value outside 1-5 should fall back to its decimal form + * (which the StringUtility variant doesn't do). + */ + public static String toRomanNumeral(int tier) { return switch (tier) { case 1 -> "I"; case 2 -> "II"; diff --git a/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java b/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java index 2d64055b4..2c507be65 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java @@ -182,13 +182,6 @@ private void onAchievementUnlocked(AchievementDefinition def, AchievementData.Ac } private String toRoman(int tier) { - return switch (tier) { - case 1 -> "I"; - case 2 -> "II"; - case 3 -> "III"; - case 4 -> "IV"; - case 5 -> "V"; - default -> String.valueOf(tier); - }; + return AchievementTier.toRomanNumeral(tier); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/chat/StaffChat.java b/type.generic/src/main/java/net/swofty/type/generic/chat/StaffChat.java index da9f39fea..18e7a3ae7 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/chat/StaffChat.java +++ b/type.generic/src/main/java/net/swofty/type/generic/chat/StaffChat.java @@ -1,11 +1,14 @@ package net.swofty.type.generic.chat; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.swofty.commons.protocol.objects.proxy.to.StaffChatProtocol; -import net.swofty.proxyapi.redis.ServerOutboundMessage; +import net.swofty.commons.redis.RedisClient; import net.swofty.type.generic.user.HypixelPlayer; +@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class StaffChat { - private StaffChat() {} private static final StaffChatProtocol PROTOCOL = new StaffChatProtocol(); @@ -20,8 +23,6 @@ public static void sendNotification(String message) { } private static void broadcastViaProxy(String formattedMessage) { - ServerOutboundMessage.sendToProxy(PROTOCOL, - new StaffChatProtocol.Request("message", formattedMessage, null), - response -> {}); + RedisClient.requestProxy(PROTOCOL, new StaffChatProtocol.Request("message", formattedMessage, null)); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/BanCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/BanCommand.java index 81b11f8af..2fe0dec90 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/command/commands/BanCommand.java +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/BanCommand.java @@ -8,7 +8,7 @@ import net.minestom.server.utils.mojang.MojangUtils; import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; -import net.swofty.commons.protocol.objects.punishment.PunishPlayerProtocolObject; +import net.swofty.commons.protocol.objects.punishment.PunishPlayerServiceProtocol; import net.swofty.commons.punishment.PunishmentReason; import net.swofty.commons.punishment.PunishmentTag; import net.swofty.commons.punishment.PunishmentType; @@ -145,7 +145,7 @@ private void banPlayer(HypixelPlayer sender, UUID targetUuid, BanType type, UUID ProxyService punishmentService = new ProxyService(ServiceType.PUNISHMENT); PunishmentReason reason = new PunishmentReason(type); ArrayList tagList = (tags != null) ? new ArrayList<>(tags) : new ArrayList<>(); - PunishPlayerProtocolObject.PunishPlayerMessage message = new PunishPlayerProtocolObject.PunishPlayerMessage( + PunishPlayerServiceProtocol.PunishPlayerMessage message = new PunishPlayerServiceProtocol.PunishPlayerMessage( targetUuid, PunishmentType.BAN.name(), reason, @@ -155,14 +155,14 @@ private void banPlayer(HypixelPlayer sender, UUID targetUuid, BanType type, UUID ); punishmentService.handleRequest(message).thenAccept(result -> { - if (result instanceof PunishPlayerProtocolObject.PunishPlayerResponse( - boolean success, String punishmentId, PunishPlayerProtocolObject.ErrorCode errorCode, + if (result instanceof PunishPlayerServiceProtocol.PunishPlayerResponse( + boolean success, String punishmentId, PunishPlayerServiceProtocol.ErrorCode errorCode, String errorMessage )) { if (success) { new ProxyPlayer(targetUuid).transferToLimbo(); sender.sendTranslated("commands.ban.success", Component.text(playerName), Component.text(punishmentId)); - } else if (errorCode == PunishPlayerProtocolObject.ErrorCode.ALREADY_PUNISHED) { + } else if (errorCode == PunishPlayerServiceProtocol.ErrorCode.ALREADY_PUNISHED) { sender.sendTranslated("commands.ban.already_banned", Component.text(errorMessage)); } else { sender.sendTranslated("commands.ban.failed", Component.text(errorMessage)); diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/MuteCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/MuteCommand.java index a88983781..31f9aedd1 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/command/commands/MuteCommand.java +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/MuteCommand.java @@ -7,7 +7,7 @@ import net.minestom.server.command.builder.suggestion.SuggestionEntry; import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; -import net.swofty.commons.protocol.objects.punishment.PunishPlayerProtocolObject; +import net.swofty.commons.protocol.objects.punishment.PunishPlayerServiceProtocol; import net.swofty.commons.punishment.PunishmentReason; import net.swofty.commons.punishment.PunishmentType; import net.swofty.commons.punishment.template.MuteType; @@ -94,7 +94,7 @@ private void mutePlayer(HypixelPlayer sender, UUID targetUuid, MuteType type, UU long actualTime, long expiryTime, String playerName) { ProxyService punishmentService = new ProxyService(ServiceType.PUNISHMENT); PunishmentReason reason = new PunishmentReason(type); - PunishPlayerProtocolObject.PunishPlayerMessage message = new PunishPlayerProtocolObject.PunishPlayerMessage( + PunishPlayerServiceProtocol.PunishPlayerMessage message = new PunishPlayerServiceProtocol.PunishPlayerMessage( targetUuid, PunishmentType.MUTE.name(), reason, @@ -104,10 +104,10 @@ private void mutePlayer(HypixelPlayer sender, UUID targetUuid, MuteType type, UU ); punishmentService.handleRequest(message).thenAccept(result -> { - if (result instanceof PunishPlayerProtocolObject.PunishPlayerResponse response) { + if (result instanceof PunishPlayerServiceProtocol.PunishPlayerResponse response) { if (response.success()) { sender.sendTranslated("commands.mute.success", Component.text(playerName), Component.text(response.punishmentId())); - } else if (response.errorCode() == PunishPlayerProtocolObject.ErrorCode.ALREADY_PUNISHED) { + } else if (response.errorCode() == PunishPlayerServiceProtocol.ErrorCode.ALREADY_PUNISHED) { sender.sendTranslated("commands.mute.already_muted", Component.text(response.errorMessage())); } else { sender.sendTranslated("commands.mute.failed", Component.text(response.errorMessage())); diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/SignGUICommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/SignGUICommand.java index 3aad2fc4b..aaac19079 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/command/commands/SignGUICommand.java +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/SignGUICommand.java @@ -7,6 +7,7 @@ import net.swofty.type.generic.gui.HypixelSignGUI; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; +import org.tinylog.Logger; @CommandParameters(aliases = "signgraphicaluserinterface", description = "Opens a graphical user interface", @@ -26,12 +27,12 @@ public void registerUsage(MinestomCommand command) { new HypixelSignGUI(player).open(new String[]{"Test1", "Test2"}).thenAccept(line -> { if (line == null) { - System.out.println(player.getDisplayName().toString() + " left server while GUI was open"); + Logger.debug("{} left server while sign GUI was open", player.getDisplayName()); return; } player.sendMessage("§7You wrote: §a" + line); - System.out.println(line); + Logger.debug("Sign GUI input: {}", line); }); }, text); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnBanCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnBanCommand.java index 83b63449f..50bcb104e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnBanCommand.java +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnBanCommand.java @@ -3,7 +3,7 @@ import net.minestom.server.command.builder.arguments.ArgumentType; import net.minestom.server.utils.mojang.MojangUtils; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.punishment.UnpunishPlayerProtocolObject; +import net.swofty.commons.protocol.objects.punishment.UnpunishPlayerProtocol; import net.swofty.commons.punishment.PunishmentType; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.command.CommandParameters; @@ -39,12 +39,12 @@ public void registerUsage(MinestomCommand command) { try { UUID targetUuid = MojangUtils.getUUID(playerName); ProxyService punishmentService = new ProxyService(ServiceType.PUNISHMENT); - UnpunishPlayerProtocolObject.UnpunishPlayerMessage message = new UnpunishPlayerProtocolObject.UnpunishPlayerMessage( + UnpunishPlayerProtocol.UnpunishPlayerMessage message = new UnpunishPlayerProtocol.UnpunishPlayerMessage( targetUuid, player.getUuid(), PunishmentType.BAN.name() ); punishmentService.handleRequest(message).thenAccept(result -> { - if (result instanceof UnpunishPlayerProtocolObject.UnpunishPlayerResponse response) { + if (result instanceof UnpunishPlayerProtocol.UnpunishPlayerResponse response) { if (response.success()) { player.sendMessage("§aSuccessfully unbanned player: " + playerName); } else { diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnMuteCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnMuteCommand.java index 43e3a8fa2..5af84e38b 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnMuteCommand.java +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/UnMuteCommand.java @@ -3,7 +3,7 @@ import net.minestom.server.command.builder.arguments.ArgumentType; import net.minestom.server.utils.mojang.MojangUtils; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.punishment.UnpunishPlayerProtocolObject; +import net.swofty.commons.protocol.objects.punishment.UnpunishPlayerProtocol; import net.swofty.commons.punishment.PunishmentType; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.command.CommandParameters; @@ -39,12 +39,12 @@ public void registerUsage(MinestomCommand command) { try { UUID targetUuid = MojangUtils.getUUID(playerName); ProxyService punishmentService = new ProxyService(ServiceType.PUNISHMENT); - UnpunishPlayerProtocolObject.UnpunishPlayerMessage message = new UnpunishPlayerProtocolObject.UnpunishPlayerMessage( + UnpunishPlayerProtocol.UnpunishPlayerMessage message = new UnpunishPlayerProtocol.UnpunishPlayerMessage( targetUuid, player.getUuid(), PunishmentType.MUTE.name() ); punishmentService.handleRequest(message).thenAccept(result -> { - if (result instanceof UnpunishPlayerProtocolObject.UnpunishPlayerResponse response) { + if (result instanceof UnpunishPlayerProtocol.UnpunishPlayerResponse response) { if (response.success()) { player.sendMessage("§aSuccessfully unmuted player: " + playerName); } else { diff --git a/type.generic/src/main/java/net/swofty/type/generic/data/DataHandler.java b/type.generic/src/main/java/net/swofty/type/generic/data/DataHandler.java index 862f4e7a4..eecd31351 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/data/DataHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/data/DataHandler.java @@ -7,8 +7,10 @@ import org.jetbrains.annotations.Nullable; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.LockSupport; @Getter public abstract class DataHandler { @@ -23,12 +25,51 @@ protected DataHandler() {} public Datapoint getDatapoint(String key) { return this.datapoints.get(key); } public static @NonNull DataHandler getUser(UUID uuid) { - if (!userCache.containsKey(uuid)) throw new RuntimeException("User " + uuid + " does not exist!"); - return userCache.get(uuid); + DataHandler handler = userCache.get(uuid); + if (handler == null) throw new RuntimeException("User " + uuid + " does not exist!"); + return handler; } public static DataHandler getUser(HypixelPlayer player) { return getUser(player.getUuid()); } + /** + * Non-throwing lookup. Prefer this in code paths that may run before + * {@code ActionPlayerDataLoad} has populated the cache, e.g. early + * disconnect handling or events flagged {@code requireDataLoaded = false}. + */ + public static Optional findUser(UUID uuid) { + return Optional.ofNullable(userCache.get(uuid)); + } + + public static Optional findUser(HypixelPlayer player) { + return findUser(player.getUuid()); + } + + /** + * Brief polling wait for the cache entry to appear. Addresses the race + * where a downstream listener fires between {@code AsyncPlayerConfiguration} + * and the moment {@code ActionPlayerDataLoad} writes into {@code userCache}. + * Returns empty if the data is still missing after the timeout. + */ + public static Optional awaitUser(UUID uuid, long timeoutMillis) { + DataHandler handler = userCache.get(uuid); + if (handler != null) return Optional.of(handler); + + final long deadline = System.nanoTime() + timeoutMillis * 1_000_000L; + long sleepNanos = 1_000_000L; // 1ms, grows up to ~16ms + while (System.nanoTime() < deadline) { + LockSupport.parkNanos(sleepNanos); + if (Thread.currentThread().isInterrupted()) { + Thread.currentThread().interrupt(); + return Optional.empty(); + } + handler = userCache.get(uuid); + if (handler != null) return Optional.of(handler); + sleepNanos = Math.min(sleepNanos * 2, 16_000_000L); + } + return Optional.empty(); + } + public abstract DataHandler fromDocument(Document document); public abstract Document toDocument(); public abstract void runOnLoad(HypixelPlayer player); diff --git a/type.generic/src/main/java/net/swofty/type/generic/data/HypixelDataHandler.java b/type.generic/src/main/java/net/swofty/type/generic/data/HypixelDataHandler.java index 4b4740c26..c869e598f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/data/HypixelDataHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/data/HypixelDataHandler.java @@ -32,12 +32,21 @@ public class HypixelDataHandler extends DataHandler { public HypixelDataHandler(UUID uuid) { super(uuid); } public static HypixelDataHandler getUser(UUID uuid) { - if (!userCache.containsKey(uuid)) throw new RuntimeException("User " + uuid + " does not exist!"); - return (HypixelDataHandler) userCache.get(uuid); + HypixelDataHandler handler = (HypixelDataHandler) userCache.get(uuid); + if (handler == null) throw new RuntimeException("User " + uuid + " does not exist!"); + return handler; } public static @Nullable HypixelDataHandler getUser(Player player) { - try { return getUser(player.getUuid()); } catch (Exception e) { return null; } + return (HypixelDataHandler) userCache.get(player.getUuid()); + } + + public static java.util.Optional findHypixelUser(UUID uuid) { + return java.util.Optional.ofNullable((HypixelDataHandler) userCache.get(uuid)); + } + + public static java.util.Optional awaitHypixelUser(UUID uuid, long timeoutMillis) { + return awaitUser(uuid, timeoutMillis).map(h -> (HypixelDataHandler) h); } @Override diff --git a/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java b/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java index 03b5d9d04..1d669f73b 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java +++ b/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java @@ -79,6 +79,8 @@ public enum ToggleType { HAS_SPOKEN_TO_TIA(false), HAS_SPOKEN_TO_LIFT_OPERATOR(false), HAS_SPOKEN_TO_LAZY_MINER(false), + HAS_SPOKEN_TO_BAKER(false), + HAS_SPOKEN_TO_FISHERMAN_GERALD(false), HAS_SPOKEN_TO_RUSTY(false), HAS_SPOKEN_TO_RUSTY_ABOUT_PICKAXE(false), HAS_SPOKEN_TO_RUSTY_ABOUT_ABIPHONE(false), @@ -117,6 +119,12 @@ public enum ToggleType { AUTO_ACCEPT_QUESTS(false), RUSTY_PURCHASE_CONFIRMATION(false), RUSTY_SORT_BY_RARITY(false), + HAS_SPOKEN_TO_FISHERWOMAN_ENID(false), + HAS_SPOKEN_TO_CAPTAIN_BAHA(false), + HAS_SPOKEN_TO_RODDY(false), + HAS_CAUGHT_FIRST_FISH(false), + HAS_UNLOCKED_SHIP(false), + HAS_VISITED_BACKWATER_BAYOU(false), ; private final boolean defaultValue; diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java b/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java index 62fb02282..222901224 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java @@ -6,23 +6,28 @@ public enum EventNodes { - // Overarching eventnodes - CUSTOM(EventNode.all("custom-listener")), - MISSION(EventNode.type("mission-listener", EventFilter.ENTITY)), - ENTITY(EventNode.type("entity-listener", EventFilter.ENTITY)), - PLAYER(EventNode.type("player-listener", EventFilter.PLAYER).setPriority(2)), - PLAYER_DATA(EventNode.type("player-data", EventFilter.PLAYER).setPriority(1)), - ITEM(EventNode.type("item-listener", EventFilter.PLAYER)), - PING(EventNode.type("ping-listener", EventFilter.ALL)), - INVENTORY(EventNode.type("inventory-listener", EventFilter.INVENTORY)), - ALL(EventNode.all("all-listener")), - // Player nodes - - ; + CUSTOM("custom-listener", EventFilter.ALL), + MISSION("mission-listener", EventFilter.ENTITY), + ENTITY("entity-listener", EventFilter.ENTITY), + PLAYER("player-listener", EventFilter.PLAYER), + PLAYER_DATA("player-data", EventFilter.PLAYER), + ITEM("item-listener", EventFilter.PLAYER), + PING("ping-listener", EventFilter.ALL), + INVENTORY("inventory-listener", EventFilter.INVENTORY), + ALL("all-listener", EventFilter.ALL); public final EventNode eventNode; + private final String nodeName; + private final EventFilter filter; + + EventNodes(String nodeName, EventFilter filter) { + this.nodeName = nodeName; + this.filter = filter; + this.eventNode = EventNode.event(nodeName, filter, (_) -> true); + } - EventNodes(EventNode eventNode) { - this.eventNode = eventNode; + @SuppressWarnings("unchecked") + public EventNode newNode(String name, int priority) { + return EventNode.event(nodeName + "-" + name, (EventFilter) filter, (_) -> true).setPriority(priority); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/HypixelEventHandler.java b/type.generic/src/main/java/net/swofty/type/generic/event/HypixelEventHandler.java index 92d7cdf64..f875d1ed6 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/HypixelEventHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/HypixelEventHandler.java @@ -12,6 +12,8 @@ import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.data.HypixelDataHandler; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.PlayerHookManager; import org.tinylog.Logger; @@ -19,116 +21,53 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class HypixelEventHandler { - private static final HashMap, List> cachedEvents = new HashMap<>(); - private static final ArrayList cachedCustomEvents = new ArrayList<>(); - private static final EventNode customEventNode = (EventNode) EventNodes.CUSTOM.eventNode; + private static final ArrayList cachedEvents = new ArrayList<>(); + private static final EventNode rootNode = EventNode.all("hypixel-phased-events"); + private static boolean registered = false; private record EventMethodEntry(Method method, Object instance, - HypixelEvent hypixelEvent) { } + EventNodes node, + EventPhase phase, + int order, + boolean requireDataLoaded, + boolean isAsync) { } public static void registerEventMethods(Object instance) { Class clazz = instance.getClass(); for (Method method : clazz.getDeclaredMethods()) { - if (method.isAnnotationPresent(HypixelEvent.class)) { - HypixelEvent hypixelEvent = method.getAnnotation(HypixelEvent.class); - EventNodes paramNode = hypixelEvent.node(); - - if (paramNode == EventNodes.CUSTOM) { - if (cachedCustomEvents.contains(new EventMethodEntry(method, instance, hypixelEvent))) { - continue; - } - cachedCustomEvents.add(new EventMethodEntry(method, instance, hypixelEvent)); - continue; - } - - if (!cachedEvents.containsKey(method.getParameterTypes()[0])) { - cachedEvents.put(method.getParameterTypes()[0], new ArrayList<>()); - } - cachedEvents.get(method.getParameterTypes()[0]).add(new EventMethodEntry(method, instance, hypixelEvent)); + EventMethodEntry entry = eventMethodEntry(instance, method); + if (entry != null && !cachedEvents.contains(entry)) { + cachedEvents.add(entry); } } } public static void register(GlobalEventHandler eventHandler) { - cachedCustomEvents.forEach(skyBlockEvent -> { - try { - Class eventType = (Class) skyBlockEvent.method.getParameterTypes()[0]; - customEventNode.addListener(eventType, (event) -> { - try { - skyBlockEvent.method.invoke(skyBlockEvent.instance, event); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - }); - } catch (Exception e) { - Logger.error(e, "Error occurred while registering custom event: {}", skyBlockEvent.getClass().getSimpleName()); - } - }); - - eventHandler.addChild(customEventNode); - - Map, List> eventNodes = new HashMap<>(); - cachedEvents.forEach((eventTypeUncasted, methodPair) -> { - Class eventType = (Class) eventTypeUncasted; - - methodPair.forEach(eventMethod -> { - EventNodes paramNode = eventMethod.hypixelEvent().node(); - - ((EventNode) paramNode.eventNode).addListener(eventType, rawEvent -> { - Event concreteEvent = eventType.cast(rawEvent); - - if (concreteEvent instanceof PlayerEvent event - && eventMethod.hypixelEvent().requireDataLoaded() - && (HypixelDataHandler.getUser(event.getPlayer()) == null - || (HypixelConst.isIslandServer() && - !((HypixelPlayer) event.getPlayer()).isReadyForEvents()))) { - Scheduler scheduler = MinecraftServer.getSchedulerManager(); - - scheduler.submitTask(() -> { - Player player = event.getPlayer(); - if (!player.isOnline()) return TaskSchedule.stop(); - if (HypixelDataHandler.getUser(player) == null) return TaskSchedule.millis(2); - if (HypixelConst.isIslandServer() && - !((HypixelPlayer) player).isReadyForEvents()) return TaskSchedule.millis(2); - - runEvent(eventMethod.hypixelEvent(), eventMethod.method, eventMethod.instance, concreteEvent); - return TaskSchedule.stop(); - }); - } else { - // Now run the event with the properly cast type - try { - runEvent(eventMethod.hypixelEvent(), eventMethod.method, eventMethod.instance, concreteEvent); - } catch (Exception ex) { - Logger.error(ex, "Exception occurred while running event {} with event type {}", - eventMethod.method.getClass().getSimpleName(), - concreteEvent.getClass().getSimpleName()); - } - } - }); - - if (eventNodes.containsKey(paramNode.eventNode)) { - eventNodes.get(paramNode.eventNode).add(eventMethod); - } else { - eventNodes.put(paramNode.eventNode, new ArrayList<>()); - eventNodes.get(paramNode.eventNode).add(eventMethod); - } - }); - }); + if (registered) return; - for (EventNode paramNode : eventNodes.keySet()) { - eventHandler.addChild(paramNode); + for (EventPhase phase : EventPhase.values()) { + rootNode.addChild(phase.node()); } + + cachedEvents.stream() + .sorted((first, second) -> { + int phaseCompare = Integer.compare(first.phase().priority(), second.phase().priority()); + if (phaseCompare != 0) return phaseCompare; + return Integer.compare(first.order(), second.order()); + }) + .forEach(HypixelEventHandler::registerEntry); + + eventHandler.addChild(rootNode); + registered = true; } @SneakyThrows - private static void runEvent(HypixelEvent event, Method method, Object eventClassInstance, Event concreteEvent) { + private static void runEvent(EventMethodEntry entry, Event concreteEvent) { PlayerHookManager hookManager = null; if (concreteEvent instanceof PlayerEvent) @@ -138,40 +77,101 @@ private static void runEvent(HypixelEvent event, Method method, Object eventClas if (hookManager != null) hookManager.callAndClearHooks( - eventClassInstance.getClass(), true); + entry.instance().getClass(), true); - if (event.isAsync()) { + if (entry.isAsync()) { PlayerHookManager finalHookManager = hookManager; Thread.startVirtualThread(() -> { try { - method.invoke(eventClassInstance, concreteEvent); + entry.method().invoke(entry.instance(), concreteEvent); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } if (finalHookManager != null) finalHookManager.callAndClearHooks( - eventClassInstance.getClass(), false); + entry.instance().getClass(), false); }); } else { - method.invoke(eventClassInstance, concreteEvent); + entry.method().invoke(entry.instance(), concreteEvent); if (hookManager != null) hookManager.callAndClearHooks( - eventClassInstance.getClass(), false); + entry.instance().getClass(), false); } } public static void callCustomEvent(Event event) { - if (customEventNode != null) { - if (event instanceof PlayerEvent playerEvent) { - if (HypixelDataHandler.getUser(playerEvent.getPlayer()) == null) { - Logger.warn("Tried to call custom event {} for player {} but their data is not loaded.", - event.getClass().getSimpleName(), - playerEvent.getPlayer().getUsername()); - return; - } + if (event instanceof PlayerEvent playerEvent) { + if (HypixelDataHandler.getUser(playerEvent.getPlayer()) == null) { + Logger.warn("Tried to call custom event {} for player {} but their data is not loaded.", + event.getClass().getSimpleName(), + playerEvent.getPlayer().getUsername()); + return; } - customEventNode.call(event); + } + rootNode.call(event); + } + + private static EventMethodEntry eventMethodEntry(Object instance, Method method) { + if (method.isAnnotationPresent(PhasedEvent.class)) { + PhasedEvent phasedEvent = method.getAnnotation(PhasedEvent.class); + return new EventMethodEntry( + method, + instance, + phasedEvent.node(), + phasedEvent.phase(), + phasedEvent.order(), + phasedEvent.requireDataLoaded(), + phasedEvent.isAsync()); + } + + return null; + } + + @SuppressWarnings("unchecked") + private static void registerEntry(EventMethodEntry entry) { + try { + Class eventType = (Class) entry.method().getParameterTypes()[0]; + EventNode listenerNode = (EventNode) entry.node().newNode( + entry.phase().name().toLowerCase() + "-" + entry.instance().getClass().getName().replace('.', '-') + "-" + entry.method().getName(), + entry.order()); + + listenerNode.addListener(eventType, rawEvent -> { + Event concreteEvent = eventType.cast(rawEvent); + runOrWaitForData(entry, concreteEvent); + }); + + entry.phase().node().addChild(listenerNode); + } catch (Exception e) { + Logger.error(e, "Error occurred while registering event: {}", entry.instance().getClass().getSimpleName()); + } + } + + private static void runOrWaitForData(EventMethodEntry entry, Event concreteEvent) { + if (concreteEvent instanceof PlayerEvent event + && entry.requireDataLoaded() + && (HypixelDataHandler.getUser(event.getPlayer()) == null + || (HypixelConst.isIslandServer() && !((HypixelPlayer) event.getPlayer()).isReadyForEvents()))) { + Scheduler scheduler = MinecraftServer.getSchedulerManager(); + + scheduler.submitTask(() -> { + Player player = event.getPlayer(); + if (!player.isOnline()) return TaskSchedule.stop(); + if (HypixelDataHandler.getUser(player) == null) return TaskSchedule.millis(2); + if (HypixelConst.isIslandServer() && !((HypixelPlayer) player).isReadyForEvents()) return TaskSchedule.millis(2); + + runEvent(entry, concreteEvent); + return TaskSchedule.stop(); + }); + return; + } + + try { + runEvent(entry, concreteEvent); + } catch (Exception ex) { + Logger.error(ex, "Exception occurred while running event {} with event type {}", + entry.method().getClass().getSimpleName(), + concreteEvent.getClass().getSimpleName()); } } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerClickedInteractionEntity.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerClickedInteractionEntity.java index 81be34bed..73922fd49 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerClickedInteractionEntity.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerClickedInteractionEntity.java @@ -4,13 +4,14 @@ import net.minestom.server.event.player.PlayerEntityInteractEvent; import net.swofty.type.generic.entity.InteractionEntity; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerClickedInteractionEntity implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerEntityInteractEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); if (event.getHand() != PlayerHand.MAIN) return; diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerMute.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerMute.java index b23220cb7..9f92a0488 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerMute.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/ActionPlayerMute.java @@ -3,7 +3,7 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerChatEvent; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.punishment.GetActivePunishmentProtocolObject; +import net.swofty.commons.protocol.objects.punishment.GetActivePunishmentProtocol; import net.swofty.commons.punishment.ActivePunishment; import net.swofty.commons.punishment.PunishmentMessages; import net.swofty.commons.punishment.PunishmentReason; @@ -11,25 +11,26 @@ import net.swofty.commons.punishment.PunishmentType; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import java.util.List; import java.util.concurrent.TimeUnit; public class ActionPlayerMute implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerChat(PlayerChatEvent event) { Player player = event.getPlayer(); try { Object response = new ProxyService(ServiceType.PUNISHMENT) - .handleRequest(new GetActivePunishmentProtocolObject.GetActivePunishmentMessage( + .handleRequest(new GetActivePunishmentProtocol.GetActivePunishmentMessage( player.getUuid(), PunishmentType.MUTE.name())) .orTimeout(2, TimeUnit.SECONDS) .join(); - if (response instanceof GetActivePunishmentProtocolObject.GetActivePunishmentResponse( + if (response instanceof GetActivePunishmentProtocol.GetActivePunishmentResponse( boolean found, String type, String banId, PunishmentReason reason, long expiresAt, List tags, boolean success, String error ) && found) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerClearCache.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerClearCache.java index e1b843122..3ee7f17fe 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerClearCache.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerClearCache.java @@ -6,8 +6,9 @@ import net.swofty.type.generic.entity.hologram.PlayerHolograms; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.HypixelAnvilGUI; import net.swofty.type.generic.gui.HypixelSignGUI; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; @@ -17,7 +18,7 @@ public class ActionPlayerClearCache implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void run(PlayerDisconnectEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); @@ -51,4 +52,4 @@ public void run(PlayerDisconnectEvent event) { return false; }); } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataLoad.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataLoad.java index e4e051ee3..fd4143479 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataLoad.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataLoad.java @@ -2,79 +2,20 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.data.DataHandler; -import net.swofty.type.generic.data.GameDataHandler; -import net.swofty.type.generic.data.GameDataHandlerRegistry; -import net.swofty.type.generic.data.HypixelDataHandler; -import net.swofty.type.generic.data.datapoints.DatapointLocale; -import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; -import org.bson.Document; -import org.tinylog.Logger; - -import java.util.List; -import java.util.Locale; -import java.util.UUID; +import net.swofty.type.generic.user.flow.GenericPlayerDataFlow; +import net.swofty.type.generic.user.flow.PlayerFlow; public class ActionPlayerDataLoad implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, phase = EventPhase.LOAD_DATA) public void run(AsyncPlayerConfigurationEvent event) { - Logger.info("Loading Hypixel account data for player: " + event.getPlayer().getUsername() + "..."); - - final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); - UUID playerUuid = player.getUuid(); - - UserDatabase userDatabase = new UserDatabase(playerUuid); - HypixelDataHandler handler; - Document userDocument = null; - - if (userDatabase.exists()) { - userDocument = userDatabase.getHypixelData(); - handler = HypixelDataHandler.createFromDocument(userDocument); - HypixelDataHandler.userCache.put(playerUuid, handler); - } else { - handler = HypixelDataHandler.initUserWithDefaultData(playerUuid); - HypixelDataHandler.userCache.put(playerUuid, handler); - userDatabase.saveData(handler); - } - - Locale loc = handler.get(HypixelDataHandler.Data.LOCALE, DatapointLocale.class).getValue().getCurrentLocale().getLocale(); - player.setLocale(loc); - - // Load additional game handlers based on TypeLoader configuration - List> additionalHandlers = - HypixelConst.getTypeLoader().getAdditionalDataHandlers(); - - for (Class handlerClass : additionalHandlers) { - GameDataHandler gameHandler = GameDataHandlerRegistry.get(handlerClass); - if (gameHandler == null) { - Logger.warn("GameDataHandler not registered: " + handlerClass.getSimpleName()); - continue; - } - - Logger.info("Loading " + gameHandler.getHandlerId() + " data for: " + player.getUsername()); - - DataHandler gameDataHandler; - if (userDocument != null && gameHandler.hasDataInDocument(userDocument)) { - gameDataHandler = gameHandler.createFromDocument(playerUuid, userDocument); - } else { - gameDataHandler = gameHandler.initWithDefaults(playerUuid); - } - - gameHandler.cacheHandler(playerUuid, gameDataHandler); - - // Save if this is new data - if (userDocument == null || !gameHandler.hasDataInDocument(userDocument)) { - userDatabase.saveData(gameDataHandler); - } - } - - Logger.info("Successfully loaded all data for player: " + player.getUsername()); + HypixelPlayer player = (HypixelPlayer) event.getPlayer(); + PlayerFlow.run(player, "generic-data/load", () -> GenericPlayerDataFlow.load(player)); } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSave.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSave.java index d67a5f71f..9491d2cf9 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSave.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSave.java @@ -2,120 +2,19 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerDisconnectEvent; -import net.swofty.commons.protocol.objects.proxy.to.FinishedWithPlayerProtocol; -import net.swofty.proxyapi.redis.ServerOutboundMessage; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.data.DataHandler; -import net.swofty.type.generic.data.Datapoint; -import net.swofty.type.generic.data.GameDataHandler; -import net.swofty.type.generic.data.GameDataHandlerRegistry; -import net.swofty.type.generic.data.HypixelDataHandler; -import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.generic.leaderboard.LeaderboardService; -import net.swofty.type.generic.leaderboard.LeaderboardTracked; -import net.swofty.type.generic.leaderboard.MapLeaderboardTracked; -import net.swofty.type.generic.resourcepack.ResourcePackManager; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.MathUtility; -import org.tinylog.Logger; - -import java.util.List; -import java.util.Map; -import java.util.UUID; +import net.swofty.type.generic.user.flow.GenericPlayerDataFlow; +import net.swofty.type.generic.user.flow.PlayerFlow; public class ActionPlayerDataSave implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.PERSIST) public void run(PlayerDisconnectEvent event) { - final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); - UUID uuid = player.getUuid(); - - ResourcePackManager packManager = HypixelConst.getResourcePackManager(); - if (packManager != null) { - packManager.getActivePack().onPlayerQuit(player); - } - - Logger.info("Saving Hypixel account data for: " + player.getUsername() + "..."); - - HypixelDataHandler handler = player.getDataHandler(); - - // Run onSave callbacks for basic Hypixel functionality - handler.runOnSave(player); - - // Save Hypixel data to UserDatabase (account-wide data) - UserDatabase userDatabase = new UserDatabase(uuid); - userDatabase.saveData(handler); - - // Sync all leaderboard-tracked datapoints for Hypixel data - syncLeaderboards(uuid, handler); - - // Remove from cache - HypixelDataHandler.userCache.remove(uuid); - - // Save additional game handlers - List> additionalHandlers = - HypixelConst.getTypeLoader().getAdditionalDataHandlers(); - - for (Class handlerClass : additionalHandlers) { - GameDataHandler gameHandler = GameDataHandlerRegistry.get(handlerClass); - if (gameHandler == null) continue; - - DataHandler gameDataHandler = gameHandler.getHandler(uuid); - if (gameDataHandler == null) continue; - - Logger.info("Saving " + gameHandler.getHandlerId() + " data for: " + player.getUsername()); - - gameDataHandler.runOnSave(player); - userDatabase.saveData(gameDataHandler); - - // Sync leaderboards for this game handler - syncLeaderboards(uuid, gameDataHandler); - - gameHandler.removeFromCache(uuid); - } - - ServerOutboundMessage.sendToProxy(new FinishedWithPlayerProtocol(), - new FinishedWithPlayerProtocol.Request(uuid.toString()), - response -> {}); - - // Clean up tablist entries - MathUtility.delay(() -> { - HypixelConst.getTypeLoader().getTablistManager().deleteTablistEntries(player); - }, 5); - - Logger.info("Successfully saved all data for: " + player.getUsername()); - } - - /** - * Syncs all leaderboard-tracked datapoints in a handler to Redis. - * This ensures the final values are persisted to leaderboards on disconnect. - */ - private void syncLeaderboards(UUID uuid, DataHandler handler) { - if (!LeaderboardService.isInitialized()) return; - - for (Datapoint dp : handler.getDatapoints().values()) { - // Simple leaderboard (single value like XP, coins) - if (dp instanceof LeaderboardTracked tracked) { - String key = tracked.getLeaderboardKey(); - if (key != null) { - LeaderboardService.updateScore(key, uuid, tracked.getLeaderboardScore()); - } - } - - // Map-based leaderboard (collections, skills) - if (dp instanceof MapLeaderboardTracked mapTracked) { - Map scores = mapTracked.getAllLeaderboardScores(); - for (Map.Entry entry : scores.entrySet()) { - LeaderboardService.updateScore( - mapTracked.getLeaderboardKeyFor(entry.getKey()), - uuid, - entry.getValue() - ); - } - } - } + HypixelPlayer player = (HypixelPlayer) event.getPlayer(); + PlayerFlow.run(player, "generic-data/save", () -> GenericPlayerDataFlow.save(player)); } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSpawn.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSpawn.java index 983647724..867cf68a0 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSpawn.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/data/ActionPlayerDataSpawn.java @@ -1,52 +1,21 @@ package net.swofty.type.generic.event.actions.data; import net.minestom.server.event.player.PlayerSpawnEvent; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.data.GameDataHandler; -import net.swofty.type.generic.data.GameDataHandlerRegistry; -import net.swofty.type.generic.data.HypixelDataHandler; -import net.swofty.type.generic.entity.hologram.PlayerHolograms; -import net.swofty.type.generic.entity.npc.HypixelNPC; -import net.swofty.type.generic.resourcepack.ResourcePackManager; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.List; -import java.util.UUID; +import net.swofty.type.generic.user.flow.GenericPlayerDataFlow; +import net.swofty.type.generic.user.flow.PlayerFlow; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; - final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); - UUID uuid = player.getUuid(); - - HypixelDataHandler handler = player.getDataHandler(); - handler.runOnLoad(player); - - // Run onLoad for additional game handlers - List> additionalHandlers = - HypixelConst.getTypeLoader().getAdditionalDataHandlers(); - - for (Class handlerClass : additionalHandlers) { - GameDataHandler gameHandler = GameDataHandlerRegistry.get(handlerClass); - if (gameHandler != null) { - gameHandler.runOnLoad(uuid, player); - } - } - - ResourcePackManager packManager = HypixelConst.getResourcePackManager(); - if (packManager != null) { - packManager.sendPack(player); - packManager.getActivePack().onPlayerJoin(player); - } - - HypixelNPC.updateForPlayer(player); - if (HypixelConst.isIslandServer()) return; - PlayerHolograms.spawnAll(player); + HypixelPlayer player = (HypixelPlayer) event.getPlayer(); + PlayerFlow.run(player, "generic-data/post-spawn", () -> GenericPlayerDataFlow.postSpawn(player)); } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClick.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClick.java index 89af1717e..6b42aa29e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClick.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClick.java @@ -10,8 +10,9 @@ import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.HypixelSignGUI; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; @@ -21,7 +22,7 @@ public class ActionPlayerInventoryClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(InventoryPreClickEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); try { diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClickAnvil.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClickAnvil.java index 4a4fdb346..42ae59f3f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClickAnvil.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClickAnvil.java @@ -6,14 +6,15 @@ import net.minestom.server.network.packet.server.play.WindowPropertyPacket; import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.HypixelAnvilGUI; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerInventoryClickAnvil implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(InventoryPreClickEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClose.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClose.java index bad7de827..780cec211 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClose.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryClose.java @@ -2,14 +2,15 @@ import net.minestom.server.event.inventory.InventoryCloseEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerInventoryClose implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(InventoryCloseEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryCloseAnvil.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryCloseAnvil.java index 0309f31f6..1944f560d 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryCloseAnvil.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryCloseAnvil.java @@ -3,14 +3,15 @@ import net.minestom.server.event.inventory.InventoryCloseEvent; import net.minestom.server.inventory.type.AnvilInventory; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.HypixelAnvilGUI; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerInventoryCloseAnvil implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(InventoryCloseEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryPostClick.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryPostClick.java index 9e06119e7..775c9bb20 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryPostClick.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/gui/ActionPlayerInventoryPostClick.java @@ -2,8 +2,9 @@ import net.minestom.server.event.inventory.InventoryClickEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; import net.swofty.type.generic.gui.inventory.item.GUIItem; @@ -11,7 +12,7 @@ public class ActionPlayerInventoryPostClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(InventoryClickEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/npc/ActionPlayerClickedNPC.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/npc/ActionPlayerClickedNPC.java index d01deab86..6cda53860 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/npc/ActionPlayerClickedNPC.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/npc/ActionPlayerClickedNPC.java @@ -8,8 +8,9 @@ import net.swofty.type.generic.entity.npc.impl.NPCEntityImpl; import net.swofty.type.generic.entity.npc.impl.NPCVillagerEntityImpl; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.event.HypixelEventHandler; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; @@ -17,7 +18,7 @@ public class ActionPlayerClickedNPC implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerEntityInteractEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/actions/party/ActionPlayerRejoinParty.java b/type.generic/src/main/java/net/swofty/type/generic/event/actions/party/ActionPlayerRejoinParty.java index 9dfce91c7..a474a94b8 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/actions/party/ActionPlayerRejoinParty.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/actions/party/ActionPlayerRejoinParty.java @@ -5,15 +5,16 @@ import net.swofty.commons.ServiceType; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerRejoinParty implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(AsyncPlayerConfigurationEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/phase/EventPhase.java b/type.generic/src/main/java/net/swofty/type/generic/event/phase/EventPhase.java new file mode 100644 index 000000000..326ea4311 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/event/phase/EventPhase.java @@ -0,0 +1,31 @@ +package net.swofty.type.generic.event.phase; + +import net.minestom.server.event.Event; +import net.minestom.server.event.EventNode; + +public enum EventPhase { + CONNECT(10), + LOAD_DATA(20), + POST_DATA(30), + SPAWN(40), + POST_SPAWN(50), + GAMEPLAY(60), + PERSIST(80), + DISCONNECT(90); + + private final int priority; + private final EventNode node; + + EventPhase(int priority) { + this.priority = priority; + this.node = EventNode.all("phase-" + name().toLowerCase()).setPriority(priority); + } + + public int priority() { + return priority; + } + + public EventNode node() { + return node; + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/HypixelEvent.java b/type.generic/src/main/java/net/swofty/type/generic/event/phase/PhasedEvent.java similarity index 52% rename from type.generic/src/main/java/net/swofty/type/generic/event/HypixelEvent.java rename to type.generic/src/main/java/net/swofty/type/generic/event/phase/PhasedEvent.java index 1a8c0576e..84bea0b9b 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/HypixelEvent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/phase/PhasedEvent.java @@ -1,4 +1,6 @@ -package net.swofty.type.generic.event; +package net.swofty.type.generic.event.phase; + +import net.swofty.type.generic.event.EventNodes; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -7,8 +9,10 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface HypixelEvent { +public @interface PhasedEvent { EventNodes node(); - boolean requireDataLoaded(); + EventPhase phase() default EventPhase.GAMEPLAY; + int order() default 0; + boolean requireDataLoaded() default false; boolean isAsync() default false; -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/experience/LevelRewardRegistry.java b/type.generic/src/main/java/net/swofty/type/generic/experience/LevelRewardRegistry.java index 3b7668067..4bddd91aa 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/experience/LevelRewardRegistry.java +++ b/type.generic/src/main/java/net/swofty/type/generic/experience/LevelRewardRegistry.java @@ -1,6 +1,7 @@ package net.swofty.type.generic.experience; import net.swofty.commons.YamlFileUtils; +import org.tinylog.Logger; import java.io.File; import java.util.*; @@ -14,7 +15,7 @@ public static void initialize(File configRoot) { File rewardsFile = new File(configRoot, "leveling/rewards.yml"); if (!rewardsFile.exists()) { - System.out.println("[LevelRewardRegistry] rewards.yml not found at: " + rewardsFile.getAbsolutePath()); + Logger.warn("rewards.yml not found at: {}", rewardsFile.getAbsolutePath()); initialized = true; return; } @@ -23,19 +24,19 @@ public static void initialize(File configRoot) { try { yaml = YamlFileUtils.loadYaml(rewardsFile); } catch (java.io.IOException e) { - System.out.println("[LevelRewardRegistry] Failed to load rewards.yml: " + e.getMessage()); + Logger.error(e, "Failed to load rewards.yml"); initialized = true; return; } if (yaml == null) { - System.out.println("[LevelRewardRegistry] Failed to load rewards.yml"); + Logger.warn("rewards.yml parsed to null — empty file?"); initialized = true; return; } loadRewards(yaml); initialized = true; - System.out.println("[LevelRewardRegistry] Loaded " + REWARDS.size() + " level rewards"); + Logger.info("Loaded {} level rewards", REWARDS.size()); } @SuppressWarnings("unchecked") @@ -66,7 +67,7 @@ private static void loadRewards(Map yaml) { LevelReward reward = builder.build(); REWARDS.put(level, reward); } catch (Exception e) { - System.err.println("[LevelRewardRegistry] Error loading reward: " + e.getMessage()); + Logger.error(e, "Error loading level reward entry"); } } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/friend/FriendManager.java b/type.generic/src/main/java/net/swofty/type/generic/friend/FriendManager.java index d21585c38..e1de742dd 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/friend/FriendManager.java +++ b/type.generic/src/main/java/net/swofty/type/generic/friend/FriendManager.java @@ -7,11 +7,11 @@ import net.swofty.commons.friend.PendingFriendRequest; import net.swofty.commons.friend.events.*; import net.swofty.commons.presence.PresenceInfo; -import net.swofty.commons.protocol.objects.friend.AreFriendsProtocolObject; -import net.swofty.commons.protocol.objects.friend.GetFriendDataProtocolObject; -import net.swofty.commons.protocol.objects.friend.GetPendingFriendRequestsProtocolObject; -import net.swofty.commons.protocol.objects.friend.SendFriendEventToServiceProtocolObject; -import net.swofty.commons.protocol.objects.presence.GetPresenceBulkProtocolObject; +import net.swofty.commons.protocol.objects.friend.AreFriendsProtocol; +import net.swofty.commons.protocol.objects.friend.GetFriendDataProtocol; +import net.swofty.commons.protocol.objects.friend.GetPendingFriendRequestsProtocol; +import net.swofty.commons.protocol.objects.friend.SendFriendEventToServiceProtocol; +import net.swofty.commons.protocol.objects.presence.GetPresenceBulkProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.data.HypixelDataHandler; import net.swofty.type.generic.user.HypixelPlayer; @@ -25,40 +25,40 @@ public class FriendManager { public static boolean areFriends(HypixelPlayer player, UUID targetUuid) { if (!friendService.isOnline().join()) return false; - AreFriendsProtocolObject.AreFriendsMessage message = new AreFriendsProtocolObject.AreFriendsMessage(player.getUuid(), targetUuid); - return friendService.handleRequest(message) - .thenApply(AreFriendsProtocolObject.AreFriendsResponse::areFriends) + AreFriendsProtocol.AreFriendsMessage message = new AreFriendsProtocol.AreFriendsMessage(player.getUuid(), targetUuid); + return friendService.handleRequest(message) + .thenApply(AreFriendsProtocol.AreFriendsResponse::areFriends) .join(); } public static @Nullable FriendData getFriendData(HypixelPlayer player) { if (!friendService.isOnline().join()) return null; - GetFriendDataProtocolObject.GetFriendDataMessage message = new GetFriendDataProtocolObject.GetFriendDataMessage(player.getUuid()); - return friendService.handleRequest(message) - .thenApply(GetFriendDataProtocolObject.GetFriendDataResponse::friendData) + GetFriendDataProtocol.GetFriendDataMessage message = new GetFriendDataProtocol.GetFriendDataMessage(player.getUuid()); + return friendService.handleRequest(message) + .thenApply(GetFriendDataProtocol.GetFriendDataResponse::friendData) .join(); } public static List getPendingRequests(HypixelPlayer player) { if (!friendService.isOnline().join()) return List.of(); - GetPendingFriendRequestsProtocolObject.GetPendingRequestsMessage message = - new GetPendingFriendRequestsProtocolObject.GetPendingRequestsMessage(player.getUuid()); - return friendService.handleRequest(message) - .thenApply(GetPendingFriendRequestsProtocolObject.GetPendingRequestsResponse::requests) + GetPendingFriendRequestsProtocol.GetPendingRequestsMessage message = + new GetPendingFriendRequestsProtocol.GetPendingRequestsMessage(player.getUuid()); + return friendService.handleRequest(message) + .thenApply(GetPendingFriendRequestsProtocol.GetPendingRequestsResponse::requests) .join(); } public static List getPresenceBulk(List uuids) { if (!friendService.isOnline().join()) return List.of(); if (uuids.isEmpty()) return List.of(); - GetPresenceBulkProtocolObject.GetPresenceBulkMessage message = - new GetPresenceBulkProtocolObject.GetPresenceBulkMessage(uuids); - return friendService.handleRequest(message) - .thenApply(GetPresenceBulkProtocolObject.GetPresenceBulkResponse::presence) + GetPresenceBulkProtocol.GetPresenceBulkMessage message = + new GetPresenceBulkProtocol.GetPresenceBulkMessage(uuids); + return friendService.handleRequest(message) + .thenApply(GetPresenceBulkProtocol.GetPresenceBulkResponse::presence) .join(); } @@ -159,7 +159,7 @@ public static void listRequests(HypixelPlayer player, int page) { } private static void sendEventToService(FriendEvent event) { - var message = new SendFriendEventToServiceProtocolObject.SendFriendEventToServiceMessage(event); + var message = new SendFriendEventToServiceProtocol.SendFriendEventToServiceMessage(event); friendService.handleRequest(message); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java index 183940c26..6cfd003bf 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java @@ -2,15 +2,16 @@ import net.minestom.server.event.inventory.InventoryCloseEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.v2.ViewNavigator; import net.swofty.type.generic.gui.v2.ViewSession; import net.swofty.type.generic.user.HypixelPlayer; public class ActionInventoryClose implements HypixelEventClass { - @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.INVENTORY, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerInventoryClose(InventoryCloseEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); ViewNavigator.find(player).ifPresent(navigator -> { @@ -26,4 +27,4 @@ public void onPlayerInventoryClose(InventoryCloseEvent event) { }); } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java index de70b4c71..185c6e621 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java @@ -3,15 +3,16 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.event.inventory.InventoryOpenEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.v2.ViewNavigator; import net.swofty.type.generic.user.HypixelPlayer; import org.tinylog.Logger; public class ActionInventoryOpen implements HypixelEventClass { - @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.INVENTORY, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerInventoryOpen(InventoryOpenEvent event) { MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); @@ -26,4 +27,4 @@ public void onPlayerInventoryOpen(InventoryOpenEvent event) { } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java index 5d111577e..acf0083be 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java @@ -2,14 +2,15 @@ import net.minestom.server.event.inventory.InventoryClickEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.v2.ViewNavigator; import net.swofty.type.generic.user.HypixelPlayer; public class ActionInventoryPostClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.INVENTORY, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onInventoryPostClick(InventoryClickEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); ViewNavigator.find(player).ifPresent(navigator -> { @@ -20,4 +21,4 @@ public void onInventoryPostClick(InventoryClickEvent event) { }); } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java index f5f2d5bd5..af1fc7bda 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java @@ -2,14 +2,15 @@ import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.v2.ViewNavigator; import net.swofty.type.generic.user.HypixelPlayer; public class ActionInventoryPreClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.INVENTORY, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onActionPlayerInventoryPreClick(InventoryPreClickEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); ViewNavigator.find(player).ifPresent(navigator -> { @@ -20,4 +21,4 @@ public void onActionPlayerInventoryPreClick(InventoryPreClickEvent event) { }); } -} \ No newline at end of file +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/leaderboard/LeaderboardService.java b/type.generic/src/main/java/net/swofty/type/generic/leaderboard/LeaderboardService.java index 4ca436d2d..31afc144c 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/leaderboard/LeaderboardService.java +++ b/type.generic/src/main/java/net/swofty/type/generic/leaderboard/LeaderboardService.java @@ -1,13 +1,11 @@ package net.swofty.type.generic.leaderboard; +import net.swofty.commons.redis.RedisConnectionPool; import org.tinylog.Logger; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.resps.Tuple; -import java.net.URI; -import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -31,23 +29,7 @@ private static synchronized void connectSync(String redisUri) { connecting = true; try { - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMaxTotal(20); - poolConfig.setMaxIdle(5); - poolConfig.setMinIdle(1); - poolConfig.setMaxWait(Duration.ofSeconds(2)); - poolConfig.setTestOnBorrow(true); - poolConfig.setTestWhileIdle(true); - poolConfig.setBlockWhenExhausted(false); - - URI uri = URI.create(redisUri); - jedisPool = new JedisPool(poolConfig, uri); - - // Test connection - try (Jedis jedis = jedisPool.getResource()) { - jedis.ping(); - } - + jedisPool = RedisConnectionPool.connect(redisUri, RedisConnectionPool.Settings.standard()); initialized = true; Logger.info("LeaderboardService connected to Redis"); } catch (Exception e) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/party/PartyManager.java b/type.generic/src/main/java/net/swofty/type/generic/party/PartyManager.java index 6b4b8c566..de7dec2b7 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/party/PartyManager.java +++ b/type.generic/src/main/java/net/swofty/type/generic/party/PartyManager.java @@ -4,9 +4,9 @@ import net.swofty.commons.party.FullParty; import net.swofty.commons.party.PartyAction; import net.swofty.commons.party.PendingParty; -import net.swofty.commons.protocol.objects.party.GetPartyProtocolObject; -import net.swofty.commons.protocol.objects.party.IsPlayerInPartyProtocolObject; -import net.swofty.commons.protocol.objects.party.SendPartyActionProtocolObject; +import net.swofty.commons.protocol.objects.party.GetPartyProtocol; +import net.swofty.commons.protocol.objects.party.IsPlayerInPartyProtocol; +import net.swofty.commons.protocol.objects.party.SendPartyActionProtocol; import net.swofty.proxyapi.ProxyPlayer; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.data.HypixelDataHandler; @@ -21,19 +21,19 @@ public class PartyManager { public static boolean isInParty(HypixelPlayer player) { if (!partyService.isOnline().join()) return false; - return partyService.handleRequest( - new IsPlayerInPartyProtocolObject.IsPlayerInPartyMessage(player.getUuid())) - .thenApply(IsPlayerInPartyProtocolObject.IsPlayerInPartyResponse::isInParty) + return partyService.handleRequest( + new IsPlayerInPartyProtocol.IsPlayerInPartyMessage(player.getUuid())) + .thenApply(IsPlayerInPartyProtocol.IsPlayerInPartyResponse::isInParty) .join(); } public static @Nullable FullParty getPartyFromPlayer(HypixelPlayer player) { if (!partyService.isOnline().join()) return null; - return (FullParty) partyService.handleRequest( - new GetPartyProtocolObject.GetPartyMessage(player.getUuid())) - .thenApply(GetPartyProtocolObject.GetPartyResponse::party) + return (FullParty) partyService.handleRequest( + new GetPartyProtocol.GetPartyMessage(player.getUuid())) + .thenApply(GetPartyProtocol.GetPartyResponse::party) .join(); } @@ -155,7 +155,7 @@ public static void hijackParty(HypixelPlayer hijacker, String targetName) { } private static void send(PartyAction action) { - partyService.handleRequest(new SendPartyActionProtocolObject.Request(action)); + partyService.handleRequest(new SendPartyActionProtocol.Request(action)); } private static void sendError(HypixelPlayer player, String message) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/presence/PresenceHeartbeat.java b/type.generic/src/main/java/net/swofty/type/generic/presence/PresenceHeartbeat.java index 8b200b7bf..9f77b400f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/presence/PresenceHeartbeat.java +++ b/type.generic/src/main/java/net/swofty/type/generic/presence/PresenceHeartbeat.java @@ -1,11 +1,14 @@ package net.swofty.type.generic.presence; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.minestom.server.MinecraftServer; import net.minestom.server.timer.TaskSchedule; import net.swofty.commons.ServiceType; import net.swofty.commons.presence.PresenceInfo; -import net.swofty.commons.protocol.objects.presence.UpdatePresenceProtocolObject; -import net.swofty.proxyapi.redis.ServerOutboundMessage; +import net.swofty.commons.protocol.objects.presence.UpdatePresenceProtocol; +import net.swofty.commons.redis.RedisClient; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.user.HypixelPlayer; @@ -13,8 +16,8 @@ /** * Periodically refreshes player presence to the friend service to avoid stale status. */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class PresenceHeartbeat { - private PresenceHeartbeat() {} public static void start() { MinecraftServer.getSchedulerManager().buildTask(PresenceHeartbeat::pulse) @@ -45,13 +48,11 @@ private static void pulse() { System.currentTimeMillis() ); - ServerOutboundMessage.sendMessageToService( + RedisClient.publishService( ServiceType.FRIEND, - new UpdatePresenceProtocolObject(), - new UpdatePresenceProtocolObject.UpdatePresenceMessage(info), - (ignored) -> {} + new UpdatePresenceProtocol(), + new UpdatePresenceProtocol.UpdatePresenceMessage(info) ); } } } - diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisOriginServer.java b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisOriginServer.java index 621b116ab..f9c6d3ed2 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisOriginServer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisOriginServer.java @@ -1,24 +1,25 @@ package net.swofty.type.generic.redis; import net.swofty.commons.ServerType; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.GivePlayersOriginTypeProtocol; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisOriginServer implements TypedProxyHandler { +public class RedisOriginServer implements RedisMessageHandler { public static Map origin = new HashMap<>(); @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new GivePlayersOriginTypeProtocol(); } @Override - public GivePlayersOriginTypeProtocol.Response onMessage(GivePlayersOriginTypeProtocol.Request message) { + public GivePlayersOriginTypeProtocol.Response handle(GivePlayersOriginTypeProtocol.Request message, RedisMessageContext context) { UUID uuid = UUID.fromString(message.uuid()); ServerType originType = ServerType.valueOf(message.originType()); origin.put(uuid, originType); diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisPing.java b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisPing.java index 17319c1b1..e0198b192 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisPing.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisPing.java @@ -1,17 +1,18 @@ package net.swofty.type.generic.redis; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.PingServerProtocol; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisPing implements TypedProxyHandler { +public class RedisPing implements RedisMessageHandler { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new PingServerProtocol(); } @Override - public PingServerProtocol.Response onMessage(PingServerProtocol.Request message) { + public PingServerProtocol.Response handle(PingServerProtocol.Request message, RedisMessageContext context) { return new PingServerProtocol.Response(); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisStaffChatBroadcast.java b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisStaffChatBroadcast.java index ac4469fb2..55d9fdec9 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisStaffChatBroadcast.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisStaffChatBroadcast.java @@ -1,8 +1,8 @@ package net.swofty.type.generic.redis; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.BroadcastStaffChatProtocol; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.command.commands.ChatCommand; import net.swofty.type.generic.data.HypixelDataHandler; @@ -11,15 +11,16 @@ import net.swofty.type.generic.user.categories.Rank; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisStaffChatBroadcast implements TypedProxyHandler { +public class RedisStaffChatBroadcast implements RedisMessageHandler { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new BroadcastStaffChatProtocol(); } @Override - public BroadcastStaffChatProtocol.Response onMessage(BroadcastStaffChatProtocol.Request message) { + public BroadcastStaffChatProtocol.Response handle(BroadcastStaffChatProtocol.Request message, RedisMessageContext context) { String type = message.type(); switch (type) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTeleport.java b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTeleport.java index 3e849a452..7be7dae43 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTeleport.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTeleport.java @@ -1,22 +1,23 @@ package net.swofty.type.generic.redis; import net.minestom.server.coordinate.Pos; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.TeleportProtocol; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.user.HypixelPlayer; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisTeleport implements TypedProxyHandler { +public class RedisTeleport implements RedisMessageHandler { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new TeleportProtocol(); } @Override - public TeleportProtocol.Response onMessage(TeleportProtocol.Request message) { + public TeleportProtocol.Response handle(TeleportProtocol.Request message, RedisMessageContext context) { UUID uuid = UUID.fromString(message.uuid()); HypixelPlayer player = HypixelGenericLoader.getFromUUID(uuid); if (player == null) return new TeleportProtocol.Response(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTransferredFromThisServer.java b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTransferredFromThisServer.java index abb45804e..9af0a100d 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTransferredFromThisServer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/RedisTransferredFromThisServer.java @@ -1,22 +1,23 @@ package net.swofty.type.generic.redis; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.PlayerSwitchedProtocol; import net.swofty.proxyapi.ProxyPlayer; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisTransferredFromThisServer implements TypedProxyHandler { +public class RedisTransferredFromThisServer implements RedisMessageHandler { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new PlayerSwitchedProtocol(); } @Override - public PlayerSwitchedProtocol.Response onMessage(PlayerSwitchedProtocol.Request message) { + public PlayerSwitchedProtocol.Response handle(PlayerSwitchedProtocol.Request message, RedisMessageContext context) { UUID uuid = UUID.fromString(message.uuid()); if (!ProxyPlayer.waitingForTransferComplete.containsKey(uuid)) { return new PlayerSwitchedProtocol.Response(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedFriendEventHandler.java b/type.generic/src/main/java/net/swofty/type/generic/redis/service/FriendEventHandler.java similarity index 97% rename from type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedFriendEventHandler.java rename to type.generic/src/main/java/net/swofty/type/generic/redis/service/FriendEventHandler.java index 749cfc514..930060cdb 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedFriendEventHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/service/FriendEventHandler.java @@ -8,11 +8,11 @@ import net.swofty.commons.friend.FriendEvent; import net.swofty.commons.friend.FriendSettingType; import net.swofty.commons.friend.events.response.*; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.friend.FriendEventPushProtocol; import net.swofty.commons.protocol.objects.friend.FriendEventPushProtocol.Request; import net.swofty.commons.protocol.objects.friend.FriendEventPushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.user.HypixelPlayer; import org.tinylog.Logger; @@ -20,18 +20,19 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedFriendEventHandler implements TypedServiceHandler { +public class FriendEventHandler implements RedisMessageHandler { private static final FriendEventPushProtocol PROTOCOL = new FriendEventPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { try { FriendEvent event = parseEvent(message.eventType(), message.eventData()); if (event == null) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedGameInformationHandler.java b/type.generic/src/main/java/net/swofty/type/generic/redis/service/GameInformationHandler.java similarity index 64% rename from type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedGameInformationHandler.java rename to type.generic/src/main/java/net/swofty/type/generic/redis/service/GameInformationHandler.java index 4892f8d9f..e0804e323 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedGameInformationHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/service/GameInformationHandler.java @@ -1,28 +1,29 @@ package net.swofty.type.generic.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.game.GameInformationPushProtocol; import net.swofty.commons.protocol.objects.game.GameInformationPushProtocol.Request; import net.swofty.commons.protocol.objects.game.GameInformationPushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedGameInformationHandler implements TypedServiceHandler { +public class GameInformationHandler implements RedisMessageHandler { public static Map game = new HashMap<>(); private static final GameInformationPushProtocol PROTOCOL = new GameInformationPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { game.put(message.uuid(), message.gameId()); return new Response(); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedKickFromGUIHandler.java b/type.generic/src/main/java/net/swofty/type/generic/redis/service/KickFromGUIHandler.java similarity index 80% rename from type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedKickFromGUIHandler.java rename to type.generic/src/main/java/net/swofty/type/generic/redis/service/KickFromGUIHandler.java index f8c316e20..9121b39b2 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedKickFromGUIHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/service/KickFromGUIHandler.java @@ -1,10 +1,10 @@ package net.swofty.type.generic.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.gui.KickFromGUIPushProtocol; import net.swofty.commons.protocol.objects.gui.KickFromGUIPushProtocol.Request; import net.swofty.commons.protocol.objects.gui.KickFromGUIPushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.user.HypixelPlayer; @@ -12,18 +12,19 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedKickFromGUIHandler implements TypedServiceHandler { +public class KickFromGUIHandler implements RedisMessageHandler { private static final KickFromGUIPushProtocol PROTOCOL = new KickFromGUIPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { List kickedPlayers = new ArrayList<>(); for (UUID playerUUID : message.playerUUIDs()) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/service/PartyBroadcastHandler.java b/type.generic/src/main/java/net/swofty/type/generic/redis/service/PartyBroadcastHandler.java index 4779a8c51..1515b2149 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/service/PartyBroadcastHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/service/PartyBroadcastHandler.java @@ -8,12 +8,12 @@ import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.party.FullParty; import net.swofty.commons.party.PartyBroadcast; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.party.PartyBroadcastPushProtocol; import net.swofty.commons.protocol.objects.party.PartyBroadcastPushProtocol.Request; import net.swofty.commons.protocol.objects.party.PartyBroadcastPushProtocol.Response; import net.swofty.proxyapi.ProxyPlayer; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.user.HypixelPlayer; @@ -25,19 +25,20 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; +import net.swofty.commons.redis.RedisMessageContext; -public class PartyBroadcastHandler implements TypedServiceHandler { +public class PartyBroadcastHandler implements RedisMessageHandler { private static final String SEPARATOR = "§9§m-----------------------------------------------------"; private static final PartyBroadcastPushProtocol PROTOCOL = new PartyBroadcastPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { try { PartyBroadcast broadcast = message.broadcast(); List handled = new ArrayList<>(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedSendMessageHandler.java b/type.generic/src/main/java/net/swofty/type/generic/redis/service/SendMessageHandler.java similarity index 75% rename from type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedSendMessageHandler.java rename to type.generic/src/main/java/net/swofty/type/generic/redis/service/SendMessageHandler.java index 6ca48f328..3628d3990 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/redis/service/TypedSendMessageHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/service/SendMessageHandler.java @@ -1,24 +1,25 @@ package net.swofty.type.generic.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.messaging.SendMessagePushProtocol; import net.swofty.commons.protocol.objects.messaging.SendMessagePushProtocol.Request; import net.swofty.commons.protocol.objects.messaging.SendMessagePushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedSendMessageHandler implements TypedServiceHandler { +public class SendMessageHandler implements RedisMessageHandler { private static final SendMessagePushProtocol PROTOCOL = new SendMessagePushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { try { HypixelPlayer player = HypixelGenericLoader.getLoadedPlayers().stream() .filter(p -> p.getUuid().equals(message.playerUUID())) diff --git a/type.generic/src/main/java/net/swofty/type/generic/tab/AreaServerModule.java b/type.generic/src/main/java/net/swofty/type/generic/tab/AreaServerModule.java new file mode 100644 index 000000000..8e6ce13b6 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/tab/AreaServerModule.java @@ -0,0 +1,51 @@ +package net.swofty.type.generic.tab; + +import net.kyori.adventure.text.Component; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.generic.i18n.I18n; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * Generic 'Server Info' tablist module that displays: + *
+ *   {area name}
+ *   Server: {server identifier}
+ * 
+ * Most type.* loaders previously held a hand-written subclass that differed + * only in the i18n area key (spiders_den, crimson_isle, gold_mine, ...). + * Those have been collapsed to a single shared module; callers pass the + * area key when registering. + * + *

Modules that need extra rows (e.g. private-island minion summary) still + * extend {@link TablistModule} directly; this is only for the plain + * area/server pair. + */ +public class AreaServerModule extends TablistModule { + + private final String areaI18nKey; + + public AreaServerModule(String areaI18nKey) { + this.areaI18nKey = areaI18nKey; + } + + @Override + public List getEntries(HypixelPlayer player) { + Locale l = player.getLocale(); + ArrayList entries = new ArrayList<>(List.of( + new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) + )); + + entries.add(new TablistEntry(I18n.string(areaI18nKey, l), TablistSkinRegistry.GRAY)); + entries.add(new TablistEntry( + I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), + TablistSkinRegistry.GRAY + )); + + fillRestWithGray(entries); + return entries; + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/tab/TablistManager.java b/type.generic/src/main/java/net/swofty/type/generic/tab/TablistManager.java index 5762a885d..75138cba8 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/tab/TablistManager.java +++ b/type.generic/src/main/java/net/swofty/type/generic/tab/TablistManager.java @@ -69,10 +69,11 @@ public void runScheduler(Scheduler scheduler) { String fakeProfileName = getFakeProfileName(slotIndex); List properties = new ArrayList<>(); + net.minestom.server.entity.PlayerSkin skin = entry.registry().getSkin(); properties.add(new PlayerInfoUpdatePacket.Property( "textures", - entry.registry().getTexture(), - entry.registry().getSignature())); + skin.textures(), + skin.signature())); if (cache.createdTeams.add(teamName)) { TeamsPacket teamPacket = new TeamsPacket(teamName, new TeamsPacket.CreateTeamAction( diff --git a/type.generic/src/main/java/net/swofty/type/generic/tab/TablistSkinRegistry.java b/type.generic/src/main/java/net/swofty/type/generic/tab/TablistSkinRegistry.java index ff8d722c2..562718d4f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/tab/TablistSkinRegistry.java +++ b/type.generic/src/main/java/net/swofty/type/generic/tab/TablistSkinRegistry.java @@ -1,6 +1,7 @@ package net.swofty.type.generic.tab; import lombok.Getter; +import net.minestom.server.entity.PlayerSkin; @Getter public enum TablistSkinRegistry { @@ -12,11 +13,17 @@ public enum TablistSkinRegistry { ORANGE("ewogICJ0aW1lc3RhbXAiIDogMTYwMjg1MDU1NTI0NCwKICAicHJvZmlsZUlkIiA6ICIwZjczMDA3NjEyNGU0NGM3YWYxMTE1NDY5YzQ5OTY3OSIsCiAgInByb2ZpbGVOYW1lIiA6ICJPcmVfTWluZXIxMjMiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTEzMmIxYzY5NzQxMzEwM2QxNjkyN2IyMTRkYTY5MmY3ZmZmZjg1MjdkYThkMzg2NDg1ZThkOGZkMmUyYTNiOSIKICAgIH0KICB9Cn0=", "dY6A5XFXhA5wF9D5hROJmUnyBt8eYTGIB2i6W1+ffLfT7uebBbFw8ucafgWM6nFEzZ1hhdNRm6oFe0D9DLAedvo8ZY6yQklxtZ56U3hQUyiWiyQLHQk62JyFN2024cDhgt7XIvPGWIlsWMjHXYXxV5xA04JoHb+OqyTM64QCZa0SM0E5Kxq3vXs3aMLOC14XPkWxMMFGsUOccIDgIujEx8c1tZDzBUuJH/+KVS5GKrx/YsqNTJk7q1qOVTFXOtCCnvoIG3A6YMn5i2x162PUIxXyQK9aDk+DJs9zig/QhEr9coaOyoRUR9eRuHREsh/A18Fba7wSK7XPp+9XCZy4pPYfUEOmVWWzsMVPyG9UYwh79fM8r2zAcZIZdY3PqfbqbGftluQDVEKNfWRq79ZXuxLKIHHLeLzMNJCx1b0ud6nK0lER/1fvcNy5DRYMmH+GP1iW3+xcT29MYSPT+QTn27V24nrgG4vljDA7HhhQ5zJVMN/k2kB3L8wbdj8WYg2YoDWR2y+DMDsxazhXVFPzMjz55DHRnKBsygn1TTZzqNnBWYeDnh638TyYGp1Z12ATyRvT0XzjTPoWknNQaG8azz/XW7SOH9B2bL/lsFZ0pwoY6HwaccvjWjJoMc7cKlsR1LkIUIjyFq17GYrXfFeSRwR7pYFobHT/IfcxT5IHmkY="), ; - private final String texture; - private final String signature; + private final PlayerSkin skin; TablistSkinRegistry(String texture, String signature) { - this.texture = texture; - this.signature = signature; + this.skin = new PlayerSkin(texture, signature); + } + + public String getTexture() { + return skin.textures(); + } + + public String getSignature() { + return skin.signature(); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java index a5a2882c1..6d2f22220 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java @@ -181,12 +181,6 @@ public void sendTo(ServerType type, boolean force) { HypixelConst.getTypeLoader().getTablistManager().nullifyCache(this); - /*showTitle(Title.title( - Component.text(HypixelTexture.FULL_SCREEN_BLACK.toString()), - Component.empty(), - Title.Times.times(Duration.ofSeconds(1), Duration.ofMillis(300), Duration.ZERO) - ));*/ - player.transferTo(type); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/flow/GenericPlayerDataFlow.java b/type.generic/src/main/java/net/swofty/type/generic/user/flow/GenericPlayerDataFlow.java new file mode 100644 index 000000000..137661a40 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/user/flow/GenericPlayerDataFlow.java @@ -0,0 +1,170 @@ +package net.swofty.type.generic.user.flow; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.commons.protocol.objects.proxy.to.FinishedWithPlayerProtocol; +import net.swofty.commons.redis.RedisClient; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.generic.data.DataHandler; +import net.swofty.type.generic.data.Datapoint; +import net.swofty.type.generic.data.GameDataHandler; +import net.swofty.type.generic.data.GameDataHandlerRegistry; +import net.swofty.type.generic.data.HypixelDataHandler; +import net.swofty.type.generic.data.datapoints.DatapointLocale; +import net.swofty.type.generic.data.mongodb.UserDatabase; +import net.swofty.type.generic.entity.hologram.PlayerHolograms; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.leaderboard.LeaderboardService; +import net.swofty.type.generic.leaderboard.LeaderboardTracked; +import net.swofty.type.generic.leaderboard.MapLeaderboardTracked; +import net.swofty.type.generic.resourcepack.ResourcePackManager; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.utility.MathUtility; +import org.bson.Document; +import org.tinylog.Logger; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class GenericPlayerDataFlow { + + public static void load(HypixelPlayer player) { + UUID playerUuid = player.getUuid(); + UserDatabase userDatabase = new UserDatabase(playerUuid); + HypixelDataHandler handler; + Document userDocument = null; + + if (userDatabase.exists()) { + userDocument = userDatabase.getHypixelData(); + handler = HypixelDataHandler.createFromDocument(userDocument); + } else { + handler = HypixelDataHandler.initUserWithDefaultData(playerUuid); + userDatabase.saveData(handler); + } + + HypixelDataHandler.userCache.put(playerUuid, handler); + + Locale locale = handler.get(HypixelDataHandler.Data.LOCALE, DatapointLocale.class) + .getValue() + .getCurrentLocale() + .getLocale(); + player.setLocale(locale); + + loadAdditionalHandlers(player, userDatabase, userDocument); + } + + public static void postSpawn(HypixelPlayer player) { + UUID uuid = player.getUuid(); + + player.getDataHandler().runOnLoad(player); + + for (Class handlerClass : HypixelConst.getTypeLoader().getAdditionalDataHandlers()) { + GameDataHandler gameHandler = GameDataHandlerRegistry.get(handlerClass); + if (gameHandler != null) { + gameHandler.runOnLoad(uuid, player); + } + } + + ResourcePackManager packManager = HypixelConst.getResourcePackManager(); + if (packManager != null) { + packManager.sendPack(player); + packManager.getActivePack().onPlayerJoin(player); + } + + HypixelNPC.updateForPlayer(player); + if (!HypixelConst.isIslandServer()) { + PlayerHolograms.spawnAll(player); + } + } + + public static void save(HypixelPlayer player) { + UUID uuid = player.getUuid(); + + ResourcePackManager packManager = HypixelConst.getResourcePackManager(); + if (packManager != null) { + packManager.getActivePack().onPlayerQuit(player); + } + + HypixelDataHandler handler = player.getDataHandler(); + handler.runOnSave(player); + + UserDatabase userDatabase = new UserDatabase(uuid); + userDatabase.saveData(handler); + syncLeaderboards(uuid, handler); + HypixelDataHandler.userCache.remove(uuid); + + for (Class handlerClass : HypixelConst.getTypeLoader().getAdditionalDataHandlers()) { + GameDataHandler gameHandler = GameDataHandlerRegistry.get(handlerClass); + if (gameHandler == null) continue; + + DataHandler gameDataHandler = gameHandler.getHandler(uuid); + if (gameDataHandler == null) continue; + + Logger.info("Saving {} data for {}", gameHandler.getHandlerId(), player.getUsername()); + gameDataHandler.runOnSave(player); + userDatabase.saveData(gameDataHandler); + syncLeaderboards(uuid, gameDataHandler); + gameHandler.removeFromCache(uuid); + } + + RedisClient.requestProxy(new FinishedWithPlayerProtocol(), new FinishedWithPlayerProtocol.Request(uuid.toString())); + + MathUtility.delay(() -> HypixelConst.getTypeLoader().getTablistManager().deleteTablistEntries(player), 5); + } + + private static void loadAdditionalHandlers(HypixelPlayer player, UserDatabase userDatabase, Document userDocument) { + UUID playerUuid = player.getUuid(); + List> additionalHandlers = HypixelConst.getTypeLoader().getAdditionalDataHandlers(); + + for (Class handlerClass : additionalHandlers) { + GameDataHandler gameHandler = GameDataHandlerRegistry.get(handlerClass); + if (gameHandler == null) { + Logger.warn("GameDataHandler not registered: {}", handlerClass.getSimpleName()); + continue; + } + + Logger.info("Loading {} data for {}", gameHandler.getHandlerId(), player.getUsername()); + + DataHandler gameDataHandler; + if (userDocument != null && gameHandler.hasDataInDocument(userDocument)) { + gameDataHandler = gameHandler.createFromDocument(playerUuid, userDocument); + } else { + gameDataHandler = gameHandler.initWithDefaults(playerUuid); + } + + gameHandler.cacheHandler(playerUuid, gameDataHandler); + + if (userDocument == null || !gameHandler.hasDataInDocument(userDocument)) { + userDatabase.saveData(gameDataHandler); + } + } + } + + private static void syncLeaderboards(UUID uuid, DataHandler handler) { + if (!LeaderboardService.isInitialized()) return; + + for (Datapoint datapoint : handler.getDatapoints().values()) { + if (datapoint instanceof LeaderboardTracked tracked) { + String key = tracked.getLeaderboardKey(); + if (key != null) { + LeaderboardService.updateScore(key, uuid, tracked.getLeaderboardScore()); + } + } + + if (datapoint instanceof MapLeaderboardTracked mapTracked) { + Map scores = mapTracked.getAllLeaderboardScores(); + for (Map.Entry entry : scores.entrySet()) { + LeaderboardService.updateScore( + mapTracked.getLeaderboardKeyFor(entry.getKey()), + uuid, + entry.getValue() + ); + } + } + } + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/flow/PlayerFlow.java b/type.generic/src/main/java/net/swofty/type/generic/user/flow/PlayerFlow.java new file mode 100644 index 000000000..cb19945b5 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/user/flow/PlayerFlow.java @@ -0,0 +1,34 @@ +package net.swofty.type.generic.user.flow; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.type.generic.user.HypixelPlayer; +import org.tinylog.Logger; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class PlayerFlow { + + public static void run(HypixelPlayer player, String stage, Runnable action) { + long started = System.currentTimeMillis(); + Logger.info("[{}] Starting {} for {}", player.getUuid(), stage, player.getUsername()); + + try { + action.run(); + Logger.info("[{}] Completed {} for {} in {}ms", + player.getUuid(), + stage, + player.getUsername(), + System.currentTimeMillis() - started); + } catch (Throwable throwable) { + Logger.error(throwable, "[{}] Failed {} for {} after {}ms", + player.getUuid(), + stage, + player.getUsername(), + System.currentTimeMillis() - started); + if (throwable instanceof RuntimeException runtimeException) throw runtimeException; + if (throwable instanceof Error error) throw error; + throw new RuntimeException(throwable); + } + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/utility/BlockUtility.java b/type.generic/src/main/java/net/swofty/type/generic/utility/BlockUtility.java index 185113478..c9980a1bf 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/utility/BlockUtility.java +++ b/type.generic/src/main/java/net/swofty/type/generic/utility/BlockUtility.java @@ -1,10 +1,15 @@ package net.swofty.type.generic.utility; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.minestom.server.coordinate.Pos; import net.minestom.server.instance.block.Block; import org.json.JSONObject; -public class BlockUtility { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class BlockUtility { + public static Block applyTexture(Block block, String texture) { JSONObject json = new JSONObject(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/utility/BufferUtility.java b/type.generic/src/main/java/net/swofty/type/generic/utility/BufferUtility.java index c0b32448f..b7437469f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/utility/BufferUtility.java +++ b/type.generic/src/main/java/net/swofty/type/generic/utility/BufferUtility.java @@ -1,9 +1,14 @@ package net.swofty.type.generic.utility; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -public class BufferUtility { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class BufferUtility { + public static int getUnsignedShort(ByteBuffer buffer) { byte[] bytes = new byte[2]; buffer.get(bytes); diff --git a/type.generic/src/main/java/net/swofty/type/generic/utility/ChestUtility.java b/type.generic/src/main/java/net/swofty/type/generic/utility/ChestUtility.java index 84ba5137c..47334d823 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/utility/ChestUtility.java +++ b/type.generic/src/main/java/net/swofty/type/generic/utility/ChestUtility.java @@ -1,11 +1,16 @@ package net.swofty.type.generic.utility; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; -public class ChestUtility { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ChestUtility { + public static Point[] getDoubleChestPositions(Instance instance, Point point) { Point[] positions = new Point[2]; diff --git a/type.generic/src/main/java/net/swofty/type/generic/utility/GameCountCache.java b/type.generic/src/main/java/net/swofty/type/generic/utility/GameCountCache.java index db57377e6..2bc4c6c12 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/utility/GameCountCache.java +++ b/type.generic/src/main/java/net/swofty/type/generic/utility/GameCountCache.java @@ -2,7 +2,7 @@ import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.GetGameCountsProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.GetGameCountsProtocol; import net.swofty.proxyapi.ProxyService; import java.util.Map; @@ -97,10 +97,10 @@ private static String buildCacheKey(ServerType type, String gameTypeName, String } private static void refreshAsync(ServerType type, String gameTypeName, String mapName, String cacheKey) { - var message = new GetGameCountsProtocolObject.GetGameCountsMessage(type, gameTypeName, mapName); + var message = new GetGameCountsProtocol.GetGameCountsMessage(type, gameTypeName, mapName); new ProxyService(ServiceType.ORCHESTRATOR) - .handleRequest(message) + .handleRequest(message) .thenAccept(response -> { if (response != null) { cache.put(cacheKey, new CachedCount( diff --git a/type.generic/src/main/java/net/swofty/type/generic/utility/MathUtility.java b/type.generic/src/main/java/net/swofty/type/generic/utility/MathUtility.java index 106cbfe53..76cf9d1f8 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/utility/MathUtility.java +++ b/type.generic/src/main/java/net/swofty/type/generic/utility/MathUtility.java @@ -1,5 +1,8 @@ package net.swofty.type.generic.utility; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; import net.minestom.server.instance.Instance; @@ -7,11 +10,14 @@ import net.minestom.server.inventory.InventoryType; import net.minestom.server.timer.TaskSchedule; import net.minestom.server.utils.Direction; +import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; -public class MathUtility { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class MathUtility { + public static double normalizeAngle(double angle, double maximum) { return (angle % maximum + maximum) % maximum - (maximum / 2); } @@ -108,8 +114,7 @@ public static List getNearbyBlocks(Instance instance, Pos pos, int range, B blocks.add(new Pos(x, y, z)); } } catch (Exception e) { - System.out.println("Threw an error for " + x + " " + y + " " + z); - continue; + Logger.debug(e, "Block read failed at {} {} {} during getBlocksInRadius", x, y, z); } } } diff --git a/type.goldmine/src/main/java/net/swofty/type/goldmine/TypeGoldMineLoader.java b/type.goldmine/src/main/java/net/swofty/type/goldmine/TypeGoldMineLoader.java index d3f9d7f8c..1ebbc09dd 100644 --- a/type.goldmine/src/main/java/net/swofty/type/goldmine/TypeGoldMineLoader.java +++ b/type.goldmine/src/main/java/net/swofty/type/goldmine/TypeGoldMineLoader.java @@ -8,7 +8,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.SkyBlockTypeLoader; @@ -18,7 +18,7 @@ import net.swofty.type.generic.tab.TablistManager; import net.swofty.type.generic.tab.TablistModule; import net.swofty.type.goldmine.entity.EntityLostPickaxe; -import net.swofty.type.goldmine.tab.GoldMineServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.tabmodules.AccountInformationModule; import net.swofty.type.skyblockgeneric.tabmodules.SkyBlockPlayersOnlineModule; @@ -76,7 +76,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new GoldMineServerModule(), + new AreaServerModule("tablist.server_info.area.gold_mine"), new AccountInformationModule() )); } @@ -106,7 +106,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.goldmine/src/main/java/net/swofty/type/goldmine/events/ActionPlayerJoin.java b/type.goldmine/src/main/java/net/swofty/type/goldmine/events/ActionPlayerJoin.java index 83264f0ca..1de6c2347 100644 --- a/type.goldmine/src/main/java/net/swofty/type/goldmine/events/ActionPlayerJoin.java +++ b/type.goldmine/src/main/java/net/swofty/type/goldmine/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.goldmine/src/main/java/net/swofty/type/goldmine/tab/GoldMineServerModule.java b/type.goldmine/src/main/java/net/swofty/type/goldmine/tab/GoldMineServerModule.java deleted file mode 100644 index cffa6ba95..000000000 --- a/type.goldmine/src/main/java/net/swofty/type/goldmine/tab/GoldMineServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.goldmine.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class GoldMineServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.gold_mine", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.hub/src/main/java/net/swofty/type/hub/TypeHubLoader.java b/type.hub/src/main/java/net/swofty/type/hub/TypeHubLoader.java index ed6a5433c..0466668e4 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/TypeHubLoader.java +++ b/type.hub/src/main/java/net/swofty/type/hub/TypeHubLoader.java @@ -20,7 +20,7 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.proxyapi.ProxyService; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.InteractionEntity; @@ -30,7 +30,7 @@ import net.swofty.type.generic.tab.TablistManager; import net.swofty.type.generic.tab.TablistModule; import net.swofty.type.hub.darkauction.DarkAuctionDisplay; -import net.swofty.type.hub.tab.HubServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.hub.util.HubMap; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.calendar.CalendarEvent; @@ -207,7 +207,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new HubServerModule(), + new AreaServerModule("tablist.server_info.area.hub"), new AccountInformationModule() )); } @@ -254,7 +254,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClickMuseumDisplay.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClickMuseumDisplay.java index a701ac671..f45dd6ca2 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClickMuseumDisplay.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClickMuseumDisplay.java @@ -2,8 +2,9 @@ import net.minestom.server.event.player.PlayerEntityInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.gui.inventories.museum.GUIMuseumEmptyDisplay; import net.swofty.type.skyblockgeneric.gui.inventories.museum.GUIMuseumNonEmptyDisplay; import net.swofty.type.skyblockgeneric.museum.MuseumDisplayEntityImpl; @@ -11,7 +12,7 @@ public class ActionPlayerClickMuseumDisplay implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerEntityInteractEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksMuseumNPCDisplay.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksMuseumNPCDisplay.java index b3090656e..852e1a588 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksMuseumNPCDisplay.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksMuseumNPCDisplay.java @@ -3,15 +3,16 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.gui.inventories.museum.GUIYourMuseum; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerClicksMuseumNPCDisplay implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); Pos displayPosition = new Pos(-23, 67, 80); diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksOnRunePedestal.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksOnRunePedestal.java index 5d676b97d..fbb81cf6d 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksOnRunePedestal.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerClicksOnRunePedestal.java @@ -3,15 +3,16 @@ import net.minestom.server.coordinate.BlockVec; import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.hub.gui.GUIRunicPedestal; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerClicksOnRunePedestal implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { if (!event.getBlockPosition().equals(new BlockVec(23, 64, -135))) return; diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerDisplayMuseum.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerDisplayMuseum.java index 151a7cc3a..a4fc83151 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerDisplayMuseum.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerDisplayMuseum.java @@ -2,8 +2,9 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.museum.MuseumDisplays; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -12,7 +13,7 @@ public class ActionPlayerDisplayMuseum implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!event.isFirstSpawn()) return; diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerHandleTargetArchery.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerHandleTargetArchery.java index da9e25669..04b49036e 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerHandleTargetArchery.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerHandleTargetArchery.java @@ -10,8 +10,9 @@ import net.minestom.server.tag.Tag; import net.swofty.commons.StringUtility; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.utility.TimedActivityHandler; import net.swofty.type.skyblockgeneric.targetpractice.PracticeTargets; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointArcheryPractice; @@ -33,7 +34,7 @@ public class ActionPlayerHandleTargetArchery implements HypixelEventClass { public ActionPlayerHandleTargetArchery() {} - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void handleOnJoin(PlayerSpawnEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!event.isFirstSpawn()) return; @@ -42,7 +43,7 @@ public void handleOnJoin(PlayerSpawnEvent event) { } - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void handleOnArrowHit(ArrowHitBlockEvent event) { if (!event.isSkyBlockPlayer()) return; final SkyBlockPlayer player = (SkyBlockPlayer) event.getShooter(); @@ -69,7 +70,7 @@ public void handleOnArrowHit(ArrowHitBlockEvent event) { } } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void handleOnMove(PlayerMoveEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); boolean isNearArchery = event.getNewPosition().distance(ARCHERY_POSITION) < 0.5; diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerJoin.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerJoin.java index 6e1cafb45..c235e177a 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerJoin.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerJoin.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerQuitDarkAuction.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerQuitDarkAuction.java index c7904823b..32c068881 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerQuitDarkAuction.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerQuitDarkAuction.java @@ -2,8 +2,9 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.darkauction.DarkAuctionHandler; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -13,7 +14,7 @@ */ public class ActionPlayerQuitDarkAuction implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerDisconnectEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerSpawn.java b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerSpawn.java index 76135c1bc..f43bbf74a 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerSpawn.java +++ b/type.hub/src/main/java/net/swofty/type/hub/events/ActionPlayerSpawn.java @@ -3,15 +3,16 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.hub.util.HubMap; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerSpawn implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.SPAWN) public void run(PlayerSpawnEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java new file mode 100644 index 000000000..2b97b2735 --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java @@ -0,0 +1,4 @@ +package net.swofty.type.hub.gui.fishing; + +public class GUIGFishingShip extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIFishingShip { +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java new file mode 100644 index 000000000..e85d9e93c --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java @@ -0,0 +1,4 @@ +package net.swofty.type.hub.gui.fishing; + +public class GUINavigator extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUINavigator { +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java new file mode 100644 index 000000000..b5eddb236 --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java @@ -0,0 +1,116 @@ +package net.swofty.type.hub.npcs; + +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.NPCOption; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.fishing.GUIGFishingShip; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.ship.FishingShipService; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; + +public class NPCCaptainBaha extends HypixelNPC { + + public NPCCaptainBaha() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§6Captain Baha", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "A9Wh529RWV2HEMvVnPzQEPfvT7p8m2GU8IB5FowBVYRash8GUSC6OvO88v5eBXAsCJvAauOnCFkp0DrxNTHUTS6E8rcGpo5ieHTr+QYglXIlA8S+rgA5eGODgI3LEtOZucHJ6H64a23Bu41lNMpN2c+LzQbisqC9WBnfVBxYo6qrzgh5JBGsRDIg2h3UKmTnNgJPuhN2cwRDDlHG8/k+xES5ZqyEFvdjGn6O5HHL6xyMkCukjZN0E8s03NkpkKxZXEm1M/Eg8EWtwGqZIa3DHNmxchYok4mDPMst8iRy4pGRlJN+VBCmGLIV7pq4QZlGzuXWplrX/PAOb+B36Rg67SHvmIk23tpnu+7uvB3rw9NedWY1+xLp8W4gPKpynOobSCbKiJ6bX0mCQfURVh2svFT5nG/VnKCL0TE8CUiTxOuxJR8QWwWRI4BMRMJQfQxy0mofvPnR5g1XUnHzvGWr4m44dmooqyCgB4W9iysADAEgc9CVtizjroopAJLXCtfsxwIuioHaZsBKQU1NpvpH55bPqf//RI9FyJJwOXTgX7fbF49z0eAgjnRAyF9VE9VYI2hFZwa3BIFnvdGxlZhE63QPB+nmKQMT0WzTz15lm77lxvvpQsurkm2gKr6FlL9+SokbTUuQmisyzS84s2EocpRscgc9JF1Dv/NjK7T+3GU="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MDQxOTU1NzI0NiwKICAicHJvZmlsZUlkIiA6ICIzY2I3YTA3YWY3ZjM0ZWZiYTlkNGI4ODQ3NDM4Mzc0ZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJBUkJVWklLMTIwMTMiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzcxYzQ0YWQ0MDdjMDIxNzM3YWQ3ODkwN2I1MDY4ZDdiY2MwYzY1OGIyYTJmYmFiZjAxNzA2NTYzYmQ5NDQ3ZCIKICAgIH0KICB9Cn0="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(162.5, 69, -65.5, 105, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) return; + + if (player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + new GUIGFishingShip().open(player); + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_CAPTAIN_BAHA)) { + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_CAPTAIN_BAHA, true); + }); + return; + } + + if (player.countItem(ItemType.RUSTY_SHIP_ENGINE) > 0) { + setDialogue(player, "rust-ship-engine").thenRun(() -> + NPCOption.sendOption(player, "captain_baha_engine", true, java.util.List.of( + NPCOption.Option.builder() + .key("yes") + .color(NamedTextColor.GREEN) + .bold(false) + .name("Yes!") + .action(ignored -> handleRustyShipEngine(player)) + .build() + ))); + return; + } + + setDialogue(player, "first-interaction"); + } + + private void handleRustyShipEngine(SkyBlockPlayer player) { + setDialogue(player, "dialogue-yes").thenRun(() -> { + var definition = FishingItemSupport.getShipPart(ItemType.RUSTY_SHIP_ENGINE.name()); + if (definition != null) { + FishingShipService.installPart(player, ItemType.RUSTY_SHIP_ENGINE.name(), definition); + } + player.takeItem(ItemType.RUSTY_SHIP_ENGINE, 1); + FishingShipService.unlockDestination(player, "BACKWATER_BAYOU"); + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP, true); + new GUIGFishingShip().open(player); + }); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "I was about to set sail, but this §6Ship §fis missing its §cengine§f!", + "Maybe §3Fisherman §fGerald knows where it is?", + }).build(), + DialogueSet.builder() + .key("rust-ship-engine").lines(new String[]{ + "Ahoy, is that the §cRusty Ship Engine§f?" + }).build(), + DialogueSet.builder() + .key("dialogue-yes").lines(new String[]{ + "Excellent! I'm the captain of this §6Ship§f, which means I oversee everything from repairs to navigation.", + "Apply that §cRusty Ship Engine §fin the §6Engine §fslot by clicking the engine in your inventory!" + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java index b49e95aec..5be734429 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java @@ -1,6 +1,8 @@ package net.swofty.type.hub.npcs; import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; @@ -31,7 +33,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(118.500, 71.000, -32.500, 145, 0); + return new Pos(118.5, 71, -32.5, 180, 0); } @Override @@ -52,7 +54,29 @@ public void onClick(NPCInteractEvent event) { return; } - // TODO: finish this quest + if(!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERMAN_GERALD)) { + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERMAN_GERALD, true); + }); + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID)) { + setDialogue(player, "talk-to-enid-again"); + return; + } + + if (player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + setDialogue(player, Math.random() < 0.5D ? "after-bringing-engine-to-baha" : "idle-" + (1 + (int) (Math.random() * 3))); + return; + } + + if (player.countItem(ItemType.RUSTY_SHIP_ENGINE) > 0 || "RUSTY_SHIP_ENGINE".equals(player.getShipState().getEngine())) { + setDialogue(player, "after-fishing-engine"); + return; + } + + setDialogue(player, "after-talking-to-enid"); } @Override @@ -69,7 +93,46 @@ protected DialogueSet[] dialogues(HypixelPlayer player) { "Keep the noise down, kid!", "If you want to learn about §aFishing§f, go talk to my wife, Fisherwoman Enid.", "She's fishing a bit §bupstream§f. Once she's shown you the ropes, come back and talk to me!", + }).build(), + DialogueSet.builder() + .key("talk-to-enid-again").lines(new String[]{ + "If you want to learn about §aFishing§f, go talk to my wife, Fisherwoman Enid.", + "She's fishing a bit §bupstream§f. Once she's shown you the ropes, come back and talk to me!" + }).build(), + DialogueSet.builder() + .key("after-talking-to-enid").lines(new String[]{ + "Can you fish up the §cRusty Ship Engine §ffor me?", + "It's somewhere in this pond here.", + "Once you fish it out, you can set sail to the §2Backwater Bayou§f!" + }).build(), + DialogueSet.builder() + .key("after-fishing-engine").lines(new String[]{ + "Ah! The §cRusty Ship Engine§f! Perfect!", + "Bring that to §6Captain Baha §fand he'll be able to help you set sail!", + "He's just behind the Fisherman's Hut, waiting by the §6Ship§f!", + "Just leave out the part about me dropping it, will ya?" + }).build(), + DialogueSet.builder() + .key("after-bringing-engine-to-baha").lines(new String[]{ + "Thanks for helping me find the §cRusty Ship Engine§f, " + (player == null ? "kid" : player.getUsername()) + "!", + "You can use the §6Ship Navigator §fto set sail to the §2Backwater Bayou§f!", + "Safe travels!" + }).build(), + DialogueSet.builder() + .key("idle-1").lines(new String[]{ + "Fishing is the family business.", + "Enid and I are thrilled that our two children love it as much as we do!" + }).build(), + DialogueSet.builder() + .key("idle-2").lines(new String[]{ + "I met Captain Baha when i was marooned on a distant pirate cove.", + "He saved my skin then, and I'm forever grateful to him." + }).build(), + DialogueSet.builder() + .key("idle-3").lines(new String[]{ + "I've only gone lava fishing a few times in my life.", + "I prefer the open water. More peaceful, less ghasts!" }).build() ).toArray(DialogueSet[]::new); } -} \ No newline at end of file +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java index 722208ae8..d9a35d276 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java @@ -1,10 +1,14 @@ package net.swofty.type.hub.npcs; import net.minestom.server.coordinate.Pos; +import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; public class NPCFisherwomanEnid extends HypixelNPC { @@ -39,6 +43,66 @@ public boolean looking(HypixelPlayer player) { @Override public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) { + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID)) { + setDialogue(player, "first-interaction").thenRun(() -> + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID, true)); + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_CAUGHT_FIRST_FISH)) { + setDialogue(player, "first-interaction"); + return; + } + + if (player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + setDialogue(player, Math.random() < 0.5D ? "after-gerald" : "idle-" + (1 + (int) (Math.random() * 3))); + return; + } + setDialogue(player, "after-catching-fish"); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "To fish, cast your rod into the water and wait for a fish to bite!" + }).build(), + DialogueSet.builder() + .key("after-catching-fish").lines(new String[]{ + "This part of the hub is a popular area for fishing because of the Fishing Outpost!", + "If you follow the river that flows under the bridge downstream, you'll find your way to it.", + "And tell Gerald I won't be home tonight! I'm tired of him making salmon." + }).build(), + DialogueSet.builder() + .key("after-gerald").lines(new String[]{ + "If you like fishin', you'll love the Backwater Bayou!", + "You should go there sometime soon!" + }).build(), + DialogueSet.builder() + .key("idle-1").lines(new String[]{ + "Using Bait is important to get better results!", + "My favorite kind of bait is Dark Bait because I prefer fishing at night.", + "Angler Angus knows a lot more about Bait than I do. I think he's fishing somewhere along this river if you're interested in learning more." + }).build(), + DialogueSet.builder() + .key("idle-2").lines(new String[]{ + "I know that Gavin uses /scg instead of looking in his Fishing Skill menu.", + "He thinks he's being sneaky, but everyone knows about it.", + "Little does he know, I use it too!" + }).build(), + DialogueSet.builder() + .key("idle-3").lines(new String[]{ + "The Backwater Bayou has all sorts of wild Sea Creatures native to the area.", + "I've heard stories of Frog Man, but I've never quite worked out if he's a frog or a man.", + "Perhaps he is both, perhaps neither." + }).build() + ).toArray(DialogueSet[]::new); } } diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java index 67d5ac678..49e07821c 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java @@ -30,7 +30,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(147.5, 69.9, -59.5, -90, 0); + return new Pos(161.5, 69.900, 43.5, 203, 17); } @Override @@ -46,7 +46,9 @@ public void onClick(NPCInteractEvent event) { if (isInDialogue(player)) return; if(!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_GAVIN)) { - setDialogue(player, "first-interaction").thenRun(() -> player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_GAVIN, true)); + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_GAVIN, true); + }); return; } @@ -73,4 +75,4 @@ protected DialogueSet[] dialogues(HypixelPlayer player) { }).build() ).toArray(DialogueSet[]::new); } -} \ No newline at end of file +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/tab/HubServerModule.java b/type.hub/src/main/java/net/swofty/type/hub/tab/HubServerModule.java deleted file mode 100644 index 17f1c7473..000000000 --- a/type.hub/src/main/java/net/swofty/type/hub/tab/HubServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.hub.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class HubServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.hub", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/TypeIslandLoader.java b/type.island/src/main/java/net/swofty/type/island/TypeIslandLoader.java index 99cb82e1b..735d8f216 100644 --- a/type.island/src/main/java/net/swofty/type/island/TypeIslandLoader.java +++ b/type.island/src/main/java/net/swofty/type/island/TypeIslandLoader.java @@ -5,7 +5,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelTypeLoader; import net.swofty.type.generic.SkyBlockTypeLoader; @@ -14,6 +14,7 @@ import net.swofty.type.generic.event.HypixelEventClass; import net.swofty.type.generic.tab.TablistManager; import net.swofty.type.generic.tab.TablistModule; +import net.swofty.type.island.lifecycle.IslandLifecycleSteps; import net.swofty.type.island.tab.IslandGuestsModule; import net.swofty.type.island.tab.IslandMemberModule; import net.swofty.type.island.tab.IslandServerModule; @@ -39,9 +40,7 @@ public ServerType getType() { public void onInitialize(MinecraftServer server) { Logger.info("TypeIslandLoader initialized!"); - /** - * Initialize Minions - */ + IslandLifecycleSteps.register(); new MinionHandler(MinecraftServer.getSchedulerManager()).start(); } @@ -83,10 +82,7 @@ public List getTraditionalEvents() { @Override public List getCustomEvents() { - return SkyBlockGenericLoader.loopThroughPackage( - "net.swofty.type.island.events.custom", - HypixelEventClass.class - ).collect(Collectors.toList()); + return List.of(); } @Override @@ -96,7 +92,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionCreateStarterChest.java b/type.island/src/main/java/net/swofty/type/island/events/custom/ActionCreateStarterChest.java deleted file mode 100644 index e202308e3..000000000 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionCreateStarterChest.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.swofty.type.island.events.custom; - -import net.minestom.server.coordinate.Pos; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.generic.utility.MathUtility; -import net.swofty.type.skyblockgeneric.block.placement.states.state.Facing; -import net.swofty.type.skyblockgeneric.chest.ChestBuilder; -import net.swofty.type.skyblockgeneric.chest.ChestType; -import net.swofty.type.skyblockgeneric.event.custom.IslandFirstCreatedEvent; - -public class ActionCreateStarterChest implements HypixelEventClass { - - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) - public void run(IslandFirstCreatedEvent event) { - MathUtility.delay(() -> new ChestBuilder(event.getIsland().getIslandInstance(), new Pos(10, 93, 38), ChestType.SINGLE, Facing.WEST) - .setItem(0, ItemStack.of(Material.DIRT, 5)) - .setItem(1, ItemStack.of(Material.GRASS_BLOCK, 7)) - .setItem(2, ItemStack.of(Material.COBBLESTONE, 8)) - .setItem(3, ItemStack.of(Material.WATER_BUCKET)) - .setItem(4, ItemStack.of(Material.LAVA_BUCKET)) - .setItem(5, ItemStack.of(Material.BONE_MEAL, 3)) - .build(), 60); - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandCreatePortals.java b/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandCreatePortals.java deleted file mode 100644 index ddbb8835b..000000000 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandCreatePortals.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.swofty.type.island.events.custom; - -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.event.custom.IslandFetchedFromDatabaseEvent; -import net.swofty.type.skyblockgeneric.structure.structures.IslandPortal; - -public class ActionIslandCreatePortals implements HypixelEventClass { - - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) - public void run(IslandFetchedFromDatabaseEvent event) { - IslandPortal portal = new IslandPortal(0, 6, 100, 43); - portal.setType(IslandPortal.PortalType.HUB); - - portal.build(event.getIsland().getIslandInstance()); - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandInitJerry.java b/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandInitJerry.java deleted file mode 100644 index faf9ff212..000000000 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandInitJerry.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.swofty.type.island.events.custom; - -import net.minestom.server.coordinate.Pos; -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.event.custom.IslandFirstCreatedEvent; -import net.swofty.type.skyblockgeneric.utility.JerryInformation; - -public class ActionIslandInitJerry implements HypixelEventClass { - - - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) - public void run(IslandFirstCreatedEvent event) { - event.getIsland().setJerryInformation( - new JerryInformation(null, new Pos(9.5, 100, 33.5, 145, 0), null) - ); - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandLoadMinions.java b/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandLoadMinions.java deleted file mode 100644 index 376216187..000000000 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandLoadMinions.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.swofty.type.island.events.custom; - -import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.event.custom.IslandFetchedFromDatabaseEvent; -import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.minion.IslandMinionData; -import net.swofty.type.skyblockgeneric.minion.MinionAction; -import net.swofty.type.skyblockgeneric.minion.SkyBlockMinion; -import net.swofty.type.skyblockgeneric.minion.extension.MinionExtensionData; -import net.swofty.type.skyblockgeneric.minion.extension.extensions.MinionFuelExtension; -import org.bson.Document; - -import java.util.List; -import java.util.Map; - -public class ActionIslandLoadMinions implements HypixelEventClass { - - - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) - public void run(IslandFetchedFromDatabaseEvent event) { - Document document = event.getIsland().getDatabase().getDocument(); - - if (document == null) { - event.getIsland().setMinionData(new IslandMinionData(event.getIsland())); - return; - } - - Map rawData = (Map) document.get("minions"); - IslandMinionData minionData = IslandMinionData.deserialize( - rawData, - event.getIsland() - ); - - event.getIsland().setMinionData(minionData); - - long lastSaved = event.getIsland().getLastSaved(); - long currentTime = System.currentTimeMillis(); - - minionData.getMinions().forEach((data) -> { - int tierIndex = data.getTier(); - SkyBlockMinion.MinionTier tier = data.getMinion().asSkyBlockMinion().getTiers().get(tierIndex - 1); - MinionExtensionData extensionData = data.getExtensionData(); - - long timeBetweenActions = (long) tier.timeBetweenActions(); - ItemType minionFuel = extensionData.getOfType(MinionFuelExtension.class).getItemTypePassedIn(); - - // Handle percentage speed increase from both fuels and minion upgrades - double percentageSpeedIncrease = data.getSpeedPercentage(); - - // Decrease timeBetweenActions by the percentage speed increase, so if above is 300, then it's 3x faster - timeBetweenActions = (long) (timeBetweenActions / (1 + (percentageSpeedIncrease / 100))); - - int amountOfActions = Math.round((float) (currentTime - lastSaved) / (timeBetweenActions * 1000L)); - - data.spawnMinion(event.getIsland().getIslandInstance()); - if (lastSaved != 0) { - Thread.startVirtualThread(() -> { - for (int i = 0; i < amountOfActions; i++) { - MinionAction action = data.getMinion().asSkyBlockMinion().getAction(); - List items = action.onAction( - new MinionAction.MinionActionEvent(), - data, - event.getIsland().getIslandInstance()); - - if (!items.isEmpty()) - MinionAction.onMinionIteration(data, data.getMinionEntity().getMinion(), items); - } - }); - } - }); - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandSaveJerry.java b/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandSaveJerry.java deleted file mode 100644 index adb222885..000000000 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandSaveJerry.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.swofty.type.island.events.custom; - -import net.swofty.type.generic.entity.hologram.ServerHolograms; -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.event.custom.IslandSavedIntoDatabaseEvent; -import net.swofty.type.skyblockgeneric.utility.JerryInformation; - -public class ActionIslandSaveJerry implements HypixelEventClass { - - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) - public void run(IslandSavedIntoDatabaseEvent event) { - JerryInformation jerryInformation = event.getIsland().getJerryInformation(); - - if (jerryInformation == null) return; - - if (jerryInformation.getJerry() != null) { - jerryInformation.getJerry().remove(); - } - if (jerryInformation.getHologram() != null) { - ServerHolograms.removeExternalHologram(jerryInformation.getHologram()); - } - - if (jerryInformation.getJerryPosition() == null) return; - - event.getIsland().getDatabase().insertOrUpdate("jerry_position_x", jerryInformation.getJerryPosition().x()); - event.getIsland().getDatabase().insertOrUpdate("jerry_position_y", jerryInformation.getJerryPosition().y()); - event.getIsland().getDatabase().insertOrUpdate("jerry_position_z", jerryInformation.getJerryPosition().z()); - event.getIsland().getDatabase().insertOrUpdate("jerry_position_yaw", (double) jerryInformation.getJerryPosition().yaw()); - event.getIsland().getDatabase().insertOrUpdate("jerry_position_pitch", (double) jerryInformation.getJerryPosition().pitch()); - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandSaveMinions.java b/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandSaveMinions.java deleted file mode 100644 index 1b7573206..000000000 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandSaveMinions.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.swofty.type.island.events.custom; - -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.event.custom.IslandSavedIntoDatabaseEvent; -import net.swofty.type.skyblockgeneric.minion.IslandMinionData; - -public class ActionIslandSaveMinions implements HypixelEventClass { - - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) - public void run(IslandSavedIntoDatabaseEvent event) { - IslandMinionData minionData = event.getIsland().getMinionData(); - minionData.getMinions().forEach(IslandMinionData.IslandMinion::removeMinion); - - event.getIsland().getDatabase().insertOrUpdate("minions", event.getIsland().getMinionData().serialize()); - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionPlayerSpawnFirstMinion.java b/type.island/src/main/java/net/swofty/type/island/events/custom/ActionPlayerSpawnFirstMinion.java deleted file mode 100644 index c27937cd8..000000000 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionPlayerSpawnFirstMinion.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.swofty.type.island.events.custom; - -import net.minestom.server.coordinate.Pos; -import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributeMinionData; -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.generic.utility.MathUtility; -import net.swofty.type.skyblockgeneric.event.custom.IslandFirstCreatedEvent; -import net.swofty.type.skyblockgeneric.minion.IslandMinionData; -import net.swofty.type.skyblockgeneric.minion.MinionRegistry; - -public class ActionPlayerSpawnFirstMinion implements HypixelEventClass { - - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) - public void run(IslandFirstCreatedEvent event) { - MathUtility.delay(() -> { - IslandMinionData.IslandMinion minion = event.getIsland().getMinionData().initializeMinion( - new Pos(3, 100, 36), // Default Cobble Minion position - MinionRegistry.COBBLESTONE, - new ItemAttributeMinionData.MinionData(1, 0), - false - ); - - event.getIsland().getMinionData().spawn(minion); - }, 40); // delay to let island load properly - } -} diff --git a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionIslandSave.java b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionIslandSave.java index dcf86acf1..5f3d8d7ce 100644 --- a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionIslandSave.java +++ b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionIslandSave.java @@ -3,15 +3,16 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.skyblockgeneric.user.island.SkyBlockIsland; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionIslandSave implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.PERSIST, order = 20) public void run(PlayerDisconnectEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); SkyBlockIsland island = player.getSkyBlockIsland(); diff --git a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickMinion.java b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickMinion.java index 6ec6b6844..994dbfe3b 100644 --- a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickMinion.java +++ b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickMinion.java @@ -2,8 +2,9 @@ import net.minestom.server.event.player.PlayerEntityInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.entity.MinionEntityImpl; import net.swofty.type.skyblockgeneric.gui.inventories.GUIMinion; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -11,7 +12,7 @@ public class ActionPlayerClickMinion implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerEntityInteractEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickedJerryNPC.java b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickedJerryNPC.java index 8635407ed..f75363aed 100644 --- a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickedJerryNPC.java +++ b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerClickedJerryNPC.java @@ -4,8 +4,9 @@ import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.player.PlayerEntityInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.event.HypixelEventHandler; import net.swofty.type.island.gui.GUIJerry; import net.swofty.type.skyblockgeneric.event.custom.JerryClickedEvent; @@ -13,7 +14,7 @@ public class ActionPlayerClickedJerryNPC implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerEntityInteractEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerJoin.java b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerJoin.java index 14d930be4..01d736e32 100644 --- a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerJoin.java +++ b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerJoin.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.island.TypeIslandLoader; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); event.setSpawningInstance(HypixelConst.getEmptyInstance()); diff --git a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerTeleport.java b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerTeleport.java index 5223ad7e1..a1ed5333f 100644 --- a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerTeleport.java +++ b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionPlayerTeleport.java @@ -3,20 +3,24 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.minestom.server.instance.SharedInstance; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.generic.user.flow.PlayerFlow; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerTeleport implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.SPAWN, order = -50) public void run(PlayerSpawnEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!event.isFirstSpawn()) return; - SharedInstance instance = player.getSkyBlockIsland().getSharedInstance().join(); - player.setInstance(instance, player.getRespawnPoint()); - player.teleport(player.getRespawnPoint()); + PlayerFlow.run(player, "island-instance/load-and-teleport", () -> { + SharedInstance instance = player.getSkyBlockIsland().getSharedInstance().join(); + player.setInstance(instance, player.getRespawnPoint()); + player.teleport(player.getRespawnPoint()); + }); } } diff --git a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionStartIslandMission.java b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionStartIslandMission.java index 042c4a1a5..392066348 100644 --- a/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionStartIslandMission.java +++ b/type.island/src/main/java/net/swofty/type/island/events/traditional/ActionStartIslandMission.java @@ -2,15 +2,16 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.missions.MissionBreakLog; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionStartIslandMission implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.POST_DATA) public void run(AsyncPlayerConfigurationEvent event) { MissionData data = ((SkyBlockPlayer) event.getPlayer()).getMissionData(); diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/FirstMinionStep.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/FirstMinionStep.java new file mode 100644 index 000000000..5d9a6e4b3 --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/FirstMinionStep.java @@ -0,0 +1,36 @@ +package net.swofty.type.island.lifecycle; + +import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributeMinionData; +import net.swofty.type.generic.utility.MathUtility; +import net.swofty.type.skyblockgeneric.minion.IslandMinionData; +import net.swofty.type.skyblockgeneric.minion.MinionRegistry; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; + +public class FirstMinionStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.CREATE; + } + + @Override + public int order() { + return 20; + } + + @Override + public void run(IslandLifecycleContext context) { + MathUtility.delay(() -> { + IslandMinionData.IslandMinion minion = context.island().getMinionData().initializeMinion( + new Pos(3, 100, 36), + MinionRegistry.COBBLESTONE, + new ItemAttributeMinionData.MinionData(1, 0), + false + ); + + context.island().getMinionData().spawn(minion); + }, 40); + } +} diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/IslandLifecycleSteps.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/IslandLifecycleSteps.java new file mode 100644 index 000000000..716dd68eb --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/IslandLifecycleSteps.java @@ -0,0 +1,26 @@ +package net.swofty.type.island.lifecycle; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycle; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class IslandLifecycleSteps { + private static boolean registered = false; + + public static void register() { + if (registered) return; + + IslandLifecycle.register(new JerryDefaultsStep()); + IslandLifecycle.register(new StarterChestStep()); + IslandLifecycle.register(new FirstMinionStep()); + IslandLifecycle.register(new JerryLoadStep()); + IslandLifecycle.register(new MinionLoadStep()); + IslandLifecycle.register(new PortalBuildStep()); + IslandLifecycle.register(new MinionSaveStep()); + IslandLifecycle.register(new JerrySaveStep()); + + registered = true; + } +} diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/JerryDefaultsStep.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/JerryDefaultsStep.java new file mode 100644 index 000000000..52a12c5bc --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/JerryDefaultsStep.java @@ -0,0 +1,19 @@ +package net.swofty.type.island.lifecycle; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; +import net.swofty.type.skyblockgeneric.utility.JerryInformation; + +public class JerryDefaultsStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.CREATE; + } + + @Override + public void run(IslandLifecycleContext context) { + context.island().setJerryInformation(new JerryInformation(null, new Pos(9.5, 100, 33.5, 145, 0), null)); + } +} diff --git a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandLoadJerry.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/JerryLoadStep.java similarity index 58% rename from type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandLoadJerry.java rename to type.island/src/main/java/net/swofty/type/island/lifecycle/JerryLoadStep.java index 20c1964c7..f712ff3cb 100644 --- a/type.island/src/main/java/net/swofty/type/island/events/custom/ActionIslandLoadJerry.java +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/JerryLoadStep.java @@ -1,24 +1,26 @@ -package net.swofty.type.island.events.custom; +package net.swofty.type.island.lifecycle; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityType; import net.swofty.type.generic.entity.hologram.ServerHolograms; -import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; -import net.swofty.type.generic.event.HypixelEventClass; import net.swofty.type.generic.utility.MathUtility; -import net.swofty.type.skyblockgeneric.event.custom.IslandFetchedFromDatabaseEvent; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; import net.swofty.type.skyblockgeneric.utility.JerryInformation; import org.bson.Document; -public class ActionIslandLoadJerry implements HypixelEventClass { - +public class JerryLoadStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.LOAD; + } - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) - public void run(IslandFetchedFromDatabaseEvent event) { - Document document = event.getIsland().getDatabase().getDocument(); - JerryInformation jerryInformation = event.getIsland().getJerryInformation(); + @Override + public void run(IslandLifecycleContext context) { + Document document = context.island().getDatabase().getDocument(); + JerryInformation jerryInformation = context.island().getJerryInformation(); if (jerryInformation == null) { jerryInformation = new JerryInformation(null, null, null); @@ -35,31 +37,25 @@ public void run(IslandFetchedFromDatabaseEvent event) { ) ); } else { - jerryInformation.setJerryPosition( - new Pos(9.5, 100, 33.5, 145, 0) - ); + jerryInformation.setJerryPosition(new Pos(9.5, 100, 33.5, 145, 0)); } Entity jerry = new Entity(EntityType.VILLAGER); jerry.setAutoViewable(true); - jerry.setInstance( - event.getIsland().getIslandInstance(), - jerryInformation.getJerryPosition() - ); + jerry.setInstance(context.island().getIslandInstance(), jerryInformation.getJerryPosition()); jerry.setNoGravity(true); jerryInformation.setJerry(jerry); ServerHolograms.ExternalHologram hologram = ServerHolograms.ExternalHologram.builder() .text(new String[]{"§6§lNEW UPDATE", "Jerry", "§e§lCLICK"}) - .instance(event.getIsland().getIslandInstance()) - .pos(jerryInformation.getJerryPosition().add(0, 1.8, 0)) + .instance(context.island().getIslandInstance()) + .pos(jerryInformation.getJerryPosition().add(0, 1.8, 0)) .build(); ServerHolograms.addExternalHologram(hologram); jerryInformation.setHologram(hologram); - - event.getIsland().setJerryInformation(jerryInformation); + context.island().setJerryInformation(jerryInformation); } } diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/JerrySaveStep.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/JerrySaveStep.java new file mode 100644 index 000000000..c5bc97efa --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/JerrySaveStep.java @@ -0,0 +1,41 @@ +package net.swofty.type.island.lifecycle; + +import net.swofty.type.generic.entity.hologram.ServerHolograms; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; +import net.swofty.type.skyblockgeneric.utility.JerryInformation; + +public class JerrySaveStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.SAVE; + } + + @Override + public int order() { + return 10; + } + + @Override + public void run(IslandLifecycleContext context) { + JerryInformation jerryInformation = context.island().getJerryInformation(); + + if (jerryInformation == null) return; + + if (jerryInformation.getJerry() != null) { + jerryInformation.getJerry().remove(); + } + if (jerryInformation.getHologram() != null) { + ServerHolograms.removeExternalHologram(jerryInformation.getHologram()); + } + + if (jerryInformation.getJerryPosition() == null) return; + + context.island().getDatabase().insertOrUpdate("jerry_position_x", jerryInformation.getJerryPosition().x()); + context.island().getDatabase().insertOrUpdate("jerry_position_y", jerryInformation.getJerryPosition().y()); + context.island().getDatabase().insertOrUpdate("jerry_position_z", jerryInformation.getJerryPosition().z()); + context.island().getDatabase().insertOrUpdate("jerry_position_yaw", (double) jerryInformation.getJerryPosition().yaw()); + context.island().getDatabase().insertOrUpdate("jerry_position_pitch", (double) jerryInformation.getJerryPosition().pitch()); + } +} diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/MinionLoadStep.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/MinionLoadStep.java new file mode 100644 index 000000000..df3a23d12 --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/MinionLoadStep.java @@ -0,0 +1,69 @@ +package net.swofty.type.island.lifecycle; + +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.minion.IslandMinionData; +import net.swofty.type.skyblockgeneric.minion.MinionAction; +import net.swofty.type.skyblockgeneric.minion.SkyBlockMinion; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; +import org.bson.Document; + +import java.util.List; +import java.util.Map; + +public class MinionLoadStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.LOAD; + } + + @Override + public int order() { + return 10; + } + + @Override + public void run(IslandLifecycleContext context) { + Document document = context.island().getDatabase().getDocument(); + Map rawData = document == null ? null : (Map) document.get("minions"); + + IslandMinionData minionData = rawData == null + ? new IslandMinionData(context.island()) + : IslandMinionData.deserialize(rawData, context.island()); + + context.island().setMinionData(minionData); + + long lastSaved = context.island().getLastSaved(); + long currentTime = System.currentTimeMillis(); + + minionData.getMinions().forEach(data -> { + int tierIndex = data.getTier(); + SkyBlockMinion.MinionTier tier = data.getMinion().asSkyBlockMinion().getTiers().get(tierIndex - 1); + + long timeBetweenActions = (long) tier.timeBetweenActions(); + double percentageSpeedIncrease = data.getSpeedPercentage(); + + timeBetweenActions = (long) (timeBetweenActions / (1 + (percentageSpeedIncrease / 100))); + + int amountOfActions = Math.round((float) (currentTime - lastSaved) / (timeBetweenActions * 1000L)); + + data.spawnMinion(context.island().getIslandInstance()); + if (lastSaved != 0) { + Thread.startVirtualThread(() -> { + for (int i = 0; i < amountOfActions; i++) { + MinionAction action = data.getMinion().asSkyBlockMinion().getAction(); + List items = action.onAction( + new MinionAction.MinionActionEvent(), + data, + context.island().getIslandInstance()); + + if (!items.isEmpty()) { + MinionAction.onMinionIteration(data, data.getMinionEntity().getMinion(), items); + } + } + }); + } + }); + } +} diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/MinionSaveStep.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/MinionSaveStep.java new file mode 100644 index 000000000..a20dfc49b --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/MinionSaveStep.java @@ -0,0 +1,20 @@ +package net.swofty.type.island.lifecycle; + +import net.swofty.type.skyblockgeneric.minion.IslandMinionData; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; + +public class MinionSaveStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.SAVE; + } + + @Override + public void run(IslandLifecycleContext context) { + IslandMinionData minionData = context.island().getMinionData(); + minionData.getMinions().forEach(IslandMinionData.IslandMinion::removeMinion); + context.island().getDatabase().insertOrUpdate("minions", minionData.serialize()); + } +} diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/PortalBuildStep.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/PortalBuildStep.java new file mode 100644 index 000000000..6c7351226 --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/PortalBuildStep.java @@ -0,0 +1,25 @@ +package net.swofty.type.island.lifecycle; + +import net.swofty.type.skyblockgeneric.structure.structures.IslandPortal; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; + +public class PortalBuildStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.LOAD; + } + + @Override + public int order() { + return 20; + } + + @Override + public void run(IslandLifecycleContext context) { + IslandPortal portal = new IslandPortal(0, 6, 100, 43); + portal.setType(IslandPortal.PortalType.HUB); + portal.build(context.island().getIslandInstance()); + } +} diff --git a/type.island/src/main/java/net/swofty/type/island/lifecycle/StarterChestStep.java b/type.island/src/main/java/net/swofty/type/island/lifecycle/StarterChestStep.java new file mode 100644 index 000000000..b297a6c72 --- /dev/null +++ b/type.island/src/main/java/net/swofty/type/island/lifecycle/StarterChestStep.java @@ -0,0 +1,36 @@ +package net.swofty.type.island.lifecycle; + +import net.minestom.server.coordinate.Pos; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.utility.MathUtility; +import net.swofty.type.skyblockgeneric.block.placement.states.state.Facing; +import net.swofty.type.skyblockgeneric.chest.ChestBuilder; +import net.swofty.type.skyblockgeneric.chest.ChestType; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleContext; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecyclePhase; +import net.swofty.type.skyblockgeneric.user.island.IslandLifecycleStep; + +public class StarterChestStep implements IslandLifecycleStep { + @Override + public IslandLifecyclePhase phase() { + return IslandLifecyclePhase.CREATE; + } + + @Override + public int order() { + return 10; + } + + @Override + public void run(IslandLifecycleContext context) { + MathUtility.delay(() -> new ChestBuilder(context.island().getIslandInstance(), new Pos(10, 93, 38), ChestType.SINGLE, Facing.WEST) + .setItem(0, ItemStack.of(Material.DIRT, 5)) + .setItem(1, ItemStack.of(Material.GRASS_BLOCK, 7)) + .setItem(2, ItemStack.of(Material.COBBLESTONE, 8)) + .setItem(3, ItemStack.of(Material.WATER_BUCKET)) + .setItem(4, ItemStack.of(Material.LAVA_BUCKET)) + .setItem(5, ItemStack.of(Material.BONE_MEAL, 3)) + .build(), 60); + } +} diff --git a/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/TypeJerrysWorkshopLoader.java b/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/TypeJerrysWorkshopLoader.java index 2903ef275..297670611 100644 --- a/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/TypeJerrysWorkshopLoader.java +++ b/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/TypeJerrysWorkshopLoader.java @@ -8,7 +8,7 @@ import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; @@ -21,7 +21,7 @@ import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.tabmodules.AccountInformationModule; import net.swofty.type.skyblockgeneric.tabmodules.SkyBlockPlayersOnlineModule; -import net.swofty.type.jerrysworkshop.tab.JerrysWorkshopServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; @@ -66,7 +66,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new JerrysWorkshopServerModule(), + new AreaServerModule("tablist.server_info.area.jerrys_workshop"), new AccountInformationModule() )); } @@ -96,7 +96,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/events/ActionPlayerJoin.java b/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/events/ActionPlayerJoin.java index 59b201f03..465e3fb5e 100644 --- a/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/events/ActionPlayerJoin.java +++ b/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/tab/JerrysWorkshopServerModule.java b/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/tab/JerrysWorkshopServerModule.java deleted file mode 100644 index cc496d6b9..000000000 --- a/type.jerrysworkshop/src/main/java/net/swofty/type/jerrysworkshop/tab/JerrysWorkshopServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.jerrysworkshop.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class JerrysWorkshopServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.jerrys_workshop", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/LobbyOrchestratorConnector.java b/type.lobby/src/main/java/net/swofty/type/lobby/LobbyOrchestratorConnector.java index 9c8ea85ee..34c8d6e87 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/LobbyOrchestratorConnector.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/LobbyOrchestratorConnector.java @@ -4,8 +4,8 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.party.FullParty; -import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocol; +import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocol; import net.swofty.proxyapi.ProxyPlayer; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.party.PartyManager; @@ -36,8 +36,8 @@ public CompletableFuture> findGameServer PLAYERS_SEARCHING.add(player.getUuid()); - GetServerForMapProtocolObject.GetServerForMapMessage message = - new GetServerForMapProtocolObject.GetServerForMapMessage( + GetServerForMapProtocol.GetServerForMapMessage message = + new GetServerForMapProtocol.GetServerForMapMessage( targetServerType, map, gameType, @@ -48,7 +48,7 @@ public CompletableFuture> findGameServer .thenApply(response -> { PLAYERS_SEARCHING.remove(player.getUuid()); - if (response instanceof GetServerForMapProtocolObject.GetServerForMapResponse( + if (response instanceof GetServerForMapProtocol.GetServerForMapResponse( UnderstandableProxyServer server, String gameId, boolean success, String error )) { return new Pair<>(server, gameId); @@ -80,8 +80,8 @@ public void sendToGame(ServerType targetServerType, String gameType, @Nullable S // Solo queue findGameServer(targetServerType, gameType, map, 1).thenAccept(pair -> { if (pair != null && pair.first() != null) { - ChooseGameProtocolObject.ChooseGameMessage message = - new ChooseGameProtocolObject.ChooseGameMessage(player.getUuid(), pair.first(), pair.second()); + ChooseGameProtocol.ChooseGameMessage message = + new ChooseGameProtocol.ChooseGameMessage(player.getUuid(), pair.first(), pair.second()); PROXY_SERVICE.handleRequest(message) .exceptionally(throwable -> { @@ -113,8 +113,8 @@ public void sendPartyToGame(ServerType targetServerType, String gameType, @Nulla List> registrationFutures = new ArrayList<>(); for (UUID memberUuid : partyMemberUuids) { - ChooseGameProtocolObject.ChooseGameMessage message = - new ChooseGameProtocolObject.ChooseGameMessage(memberUuid, server, gameId); + ChooseGameProtocol.ChooseGameMessage message = + new ChooseGameProtocol.ChooseGameMessage(memberUuid, server, gameId); registrationFutures.add( PROXY_SERVICE.handleRequest(message) diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyBlockBreak.java b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyBlockBreak.java index da1b913ed..3138e4cb7 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyBlockBreak.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyBlockBreak.java @@ -2,12 +2,13 @@ import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class LobbyBlockBreak implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockBreak(PlayerBlockBreakEvent event) { event.setCancelled(true); } diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyItemEvents.java b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyItemEvents.java index 0091c19ae..ebab2dba7 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyItemEvents.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyItemEvents.java @@ -7,8 +7,9 @@ import net.minestom.server.event.player.PlayerUseItemOnBlockEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.lobby.LobbyTypeLoader; import net.swofty.type.lobby.item.LobbyItemHandler; @@ -21,7 +22,7 @@ private static LobbyItemHandler getHandler() { return null; } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onItemFinishUse(PlayerFinishItemUseEvent event) { LobbyItemHandler handler = getHandler(); if (handler != null) { @@ -29,7 +30,7 @@ public void onItemFinishUse(PlayerFinishItemUseEvent event) { } } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onItemUseOnBlock(PlayerUseItemOnBlockEvent event) { LobbyItemHandler handler = getHandler(); if (handler != null) { @@ -37,7 +38,7 @@ public void onItemUseOnBlock(PlayerUseItemOnBlockEvent event) { } } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onItemUse(PlayerUseItemEvent event) { LobbyItemHandler handler = getHandler(); if (handler != null) { @@ -45,7 +46,7 @@ public void onItemUse(PlayerUseItemEvent event) { } } - @HypixelEvent(node = EventNodes.ITEM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.ITEM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onItemDrop(ItemDropEvent event) { LobbyItemHandler handler = getHandler(); if (handler != null) { @@ -53,7 +54,7 @@ public void onItemDrop(ItemDropEvent event) { } } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onBlockPlace(PlayerBlockPlaceEvent event) { LobbyItemHandler handler = getHandler(); if (handler != null) { diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyLaunchPadEvents.java b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyLaunchPadEvents.java index f1a59e3a9..58d483a21 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyLaunchPadEvents.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyLaunchPadEvents.java @@ -7,15 +7,16 @@ import net.minestom.server.network.packet.server.play.ParticlePacket; import net.minestom.server.particle.Particle; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.lobby.launchpad.LaunchPad; import net.swofty.type.lobby.launchpad.LaunchPadHandler; public class LobbyLaunchPadEvents implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyParkourEvents.java b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyParkourEvents.java index ac4dd3701..f2445daa3 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyParkourEvents.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyParkourEvents.java @@ -8,8 +8,9 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.utility.MathUtility; import net.swofty.type.lobby.LobbyTypeLoader; @@ -22,7 +23,7 @@ public class LobbyParkourEvents implements HypixelEventClass { private final HashMap lastClickedTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerJoin(PlayerSpawnEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); LobbyTypeLoader loader = (LobbyTypeLoader) HypixelConst.getTypeLoader(); @@ -33,7 +34,7 @@ public void onPlayerJoin(PlayerSpawnEvent event) { parkourManager.updateForPlayer(HypixelConst.getInstanceContainer(), player); } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerDisconnect(PlayerDisconnectEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); lastClickedTimes.remove(player.getUuid()); @@ -45,7 +46,7 @@ public void onPlayerDisconnect(PlayerDisconnectEvent event) { parkourManager.cancelParkour(player); } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { LobbyTypeLoader loader = (LobbyTypeLoader) HypixelConst.getTypeLoader(); final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerJoinEvents.java b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerJoinEvents.java index 354dafdee..68272e57e 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerJoinEvents.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerJoinEvents.java @@ -5,8 +5,9 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.lobby.LobbyTypeLoader; import net.swofty.type.lobby.item.LobbyItem; @@ -22,7 +23,7 @@ public class LobbyPlayerJoinEvents implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(AsyncPlayerConfigurationEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerMove.java b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerMove.java index 2e20ff4e0..715cf48a9 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerMove.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/events/LobbyPlayerMove.java @@ -4,8 +4,9 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerMoveEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class LobbyPlayerMove implements HypixelEventClass { private final Pos spawnPoint; @@ -14,7 +15,7 @@ public LobbyPlayerMove(Pos spawnPoint) { this.spawnPoint = spawnPoint; } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if (player.getPosition().y() < 0) { diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIParty.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIParty.java index 5b2008dba..558e9cc06 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIParty.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIParty.java @@ -9,6 +9,7 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.party.FullParty; import net.swofty.type.generic.data.HypixelDataHandler; +import net.swofty.type.generic.data.datapoints.DatapointAchievementData; import net.swofty.type.generic.data.datapoints.DatapointHypixelExperience; import net.swofty.type.generic.data.datapoints.DatapointString; import net.swofty.type.generic.experience.HypixelExperience; @@ -368,8 +369,9 @@ private ItemStack.Builder createMemberHead(FullParty.Member member) { HypixelDataHandler account = HypixelDataHandler.getOfOfflinePlayer(memberUuid); long xp = account.get(HypixelDataHandler.Data.HYPIXEL_EXPERIENCE, DatapointHypixelExperience.class).getValue(); int level = HypixelExperience.xpToLevel(xp); - // TODO: Get actual achievement points when available - int achievementPoints = 0; + int achievementPoints = account.get(HypixelDataHandler.Data.ACHIEVEMENT_DATA, DatapointAchievementData.class) + .getValue() + .getTotalPoints(); // Get skin String skinTexture = account.get(HypixelDataHandler.Data.SKIN_TEXTURE, DatapointString.class).getValue(); diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUITieredAchievements.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUITieredAchievements.java index b8918abb2..a3ae3f25d 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUITieredAchievements.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUITieredAchievements.java @@ -317,14 +317,7 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { } private String toRoman(int num) { - return switch (num) { - case 1 -> "I"; - case 2 -> "II"; - case 3 -> "III"; - case 4 -> "IV"; - case 5 -> "V"; - default -> String.valueOf(num); - }; + return AchievementTier.toRomanNumeral(num); } private int getMaxPages(int totalAchievements) { diff --git a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/TypeMurderMysteryConfiguratorLoader.java b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/TypeMurderMysteryConfiguratorLoader.java index e480e755a..af940301a 100644 --- a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/TypeMurderMysteryConfiguratorLoader.java +++ b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/TypeMurderMysteryConfiguratorLoader.java @@ -9,7 +9,7 @@ import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; import net.swofty.commons.murdermystery.map.MurderMysteryMapsConfig; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.HypixelTypeLoader; import net.swofty.type.generic.command.HypixelCommand; @@ -147,7 +147,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerBreak.java b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerBreak.java index 82616df2e..cab37927a 100644 --- a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerBreak.java +++ b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerBreak.java @@ -3,13 +3,14 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerBreak implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockBreakEvent event) { // Prevent block breaking in configurator mode event.setCancelled(true); diff --git a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerDataSpawn.java b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerDataSpawn.java index 510497ed6..faa418549 100644 --- a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerDataSpawn.java +++ b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerDataSpawn.java @@ -3,13 +3,14 @@ import net.kyori.adventure.text.Component; import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; diff --git a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerJoin.java b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerJoin.java index 6fd553c30..6dc60dd87 100644 --- a/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerJoin.java +++ b/type.murdermysteryconfigurator/src/main/java/net/swofty/type/murdermysteryconfigurator/events/ActionPlayerJoin.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/TypeMurderMysteryGameLoader.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/TypeMurderMysteryGameLoader.java index f97c2bd84..705fc14b8 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/TypeMurderMysteryGameLoader.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/TypeMurderMysteryGameLoader.java @@ -22,10 +22,9 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.murdermystery.MurderMysteryGameType; import net.swofty.commons.murdermystery.map.MurderMysteryMapsConfig; -import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocol; import net.swofty.proxyapi.ProxyService; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.pvp.MinestomPvP; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; @@ -205,7 +204,7 @@ public void afterInitialize(MinecraftServer server) { commonsGames.add(commonsGame); } - var heartbeat = new GameHeartbeatProtocolObject.HeartbeatMessage( + var heartbeat = new GameHeartbeatProtocol.HeartbeatMessage( uuid, shortName, getType(), @@ -281,19 +280,19 @@ public List getNPCs() { @Override @SuppressWarnings("unchecked") - public List> getTypedServiceHandlers() { + public List> getServiceHandlers() { return (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.murdermysterygame.redis.service", - TypedServiceHandler.class + RedisMessageHandler.class ).toList(); } @Override @SuppressWarnings("unchecked") - public List> getTypedProxyHandlers() { - return (List>) (List) HypixelGenericLoader.loopThroughPackage( + public List> getProxyHandlers() { + return (List>) (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.murdermysterygame.redis", - TypedProxyHandler.class + RedisMessageHandler.class ).toList(); } diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowHit.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowHit.java index 7be28340f..0a6e15b15 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowHit.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowHit.java @@ -5,8 +5,9 @@ import net.swofty.pvp.projectile.AbstractProjectile; import net.swofty.type.generic.achievement.PlayerAchievementHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.game.GameStatus; @@ -15,7 +16,7 @@ public class ActionArrowHit implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(ProjectileCollideWithEntityEvent event) { Entity projectile = event.getEntity(); Entity target = event.getTarget(); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowShoot.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowShoot.java index 5436ebc7a..5a6cf6b1f 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowShoot.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionArrowShoot.java @@ -4,8 +4,9 @@ import net.minestom.server.item.Material; import net.swofty.type.generic.achievement.PlayerAchievementHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.game.GameStatus; @@ -13,7 +14,7 @@ public class ActionArrowShoot implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerCancelItemUseEvent event) { if (event.getItemStack().material() != Material.BOW) return; if (!(event.getPlayer() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionBlockInteraction.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionBlockInteraction.java index 15a9b01e0..0f481b5e8 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionBlockInteraction.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionBlockInteraction.java @@ -3,8 +3,9 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.game.GameStatus; @@ -14,7 +15,7 @@ public class ActionBlockInteraction implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { Point blockPos = event.getBlockPosition(); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGameCustomItems.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGameCustomItems.java index 99ccdfd6a..69cf1978a 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGameCustomItems.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGameCustomItems.java @@ -6,27 +6,28 @@ import net.minestom.server.event.player.PlayerUseItemOnBlockEvent; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionGameCustomItems implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemOnBlockEvent event) { TypeMurderMysteryGameLoader.getItemHandler().onItemUseOnBlock(event); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerFinishItemUseEvent event) { TypeMurderMysteryGameLoader.getItemHandler().onItemFinishUse(event); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemEvent event) { TypeMurderMysteryGameLoader.getItemHandler().onItemUse(event); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockPlaceEvent event) { TypeMurderMysteryGameLoader.getItemHandler().onBlockPlace(event); } diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldDrop.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldDrop.java index 9345a075b..ee6c70628 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldDrop.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldDrop.java @@ -7,12 +7,13 @@ import net.swofty.type.murdermysterygame.game.GameStatus; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionGoldDrop implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(ItemDropEvent event) { if (!(event.getPlayer() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldInventoryMove.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldInventoryMove.java index ec76002a0..745484234 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldInventoryMove.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldInventoryMove.java @@ -8,12 +8,13 @@ import net.swofty.type.murdermysterygame.game.GameStatus; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionGoldInventoryMove implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(InventoryItemChangeEvent event) { if (event.getInventory().getViewers().isEmpty()) return; MurderMysteryPlayer player = (MurderMysteryPlayer) event.getInventory().getViewers().stream().findFirst().orElse(null); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldPickup.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldPickup.java index 5bca81a04..42753b0aa 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldPickup.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionGoldPickup.java @@ -13,12 +13,13 @@ import net.swofty.type.murdermysterygame.role.GameRole; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionGoldPickup implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PickupItemEvent event) { if (!(event.getLivingEntity() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerChat.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerChat.java index a4daaafe5..c8c9993c1 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerChat.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerChat.java @@ -7,8 +7,9 @@ import net.swofty.type.generic.chat.StaffChat; import net.swofty.type.generic.data.datapoints.DatapointChatType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.categories.Rank; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; @@ -17,7 +18,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { MurderMysteryPlayer player = (MurderMysteryPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerCombat.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerCombat.java index 178b397f3..1fed08e47 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerCombat.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerCombat.java @@ -11,12 +11,13 @@ import net.swofty.type.murdermysterygame.role.GameRole; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerCombat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PrepareAttackEvent event) { if (!(event.getEntity() instanceof MurderMysteryPlayer attacker)) return; if (!(event.getTarget() instanceof MurderMysteryPlayer victim)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDataSpawn.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDataSpawn.java index 841fc061a..9ddc274c8 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDataSpawn.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDataSpawn.java @@ -6,12 +6,13 @@ import net.swofty.pvp.projectile.entities.ArrowProjectile; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; final MurderMysteryPlayer player = (MurderMysteryPlayer) event.getPlayer(); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDisconnect.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDisconnect.java index 973f2efcf..09a29bff2 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDisconnect.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerDisconnect.java @@ -6,12 +6,13 @@ import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerDisconnect implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void run(PlayerDisconnectEvent event) { MurderMysteryPlayer player = (MurderMysteryPlayer) event.getPlayer(); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerJoin.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerJoin.java index d8d13d2ac..b19c1ef0f 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerJoin.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerJoin.java @@ -9,16 +9,17 @@ import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.generic.redis.service.TypedGameInformationHandler; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.generic.redis.service.GameInformationHandler; import net.swofty.type.generic.utility.MathUtility; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final MurderMysteryPlayer player = (MurderMysteryPlayer) event.getPlayer(); Logger.info("Player " + player.getUsername() + " joined the server from origin server " + player.getOriginServer()); @@ -31,7 +32,7 @@ public void run(AsyncPlayerConfigurationEvent event) { private void tryJoinGame(MurderMysteryPlayer player, boolean isRetry) { if (!player.isOnline()) return; - String preferredGameId = TypedGameInformationHandler.game.remove(player.getUuid()); + String preferredGameId = GameInformationHandler.game.remove(player.getUuid()); if (preferredGameId == null) { if (!isRetry) { Logger.info("No game assignment found for " + player.getUsername() + ", retrying in 1 second..."); diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerTick.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerTick.java index 57d5c69c0..ec6010dcd 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerTick.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPlayerTick.java @@ -8,12 +8,13 @@ import net.swofty.type.murdermysterygame.game.GameStatus; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerTick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerTickEvent event) { if (!(event.getPlayer() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventBlockModification.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventBlockModification.java index a6a7f926a..bd89eecda 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventBlockModification.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventBlockModification.java @@ -7,12 +7,13 @@ import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPreventBlockModification implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockBreak(PlayerBlockBreakEvent event) { if (!(event.getPlayer() instanceof MurderMysteryPlayer player)) return; @@ -25,7 +26,7 @@ public void onBlockBreak(PlayerBlockBreakEvent event) { } } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockPlace(PlayerBlockPlaceEvent event) { if (!(event.getPlayer() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventFallDamage.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventFallDamage.java index 91095edee..0dc1b1f69 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventFallDamage.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionPreventFallDamage.java @@ -7,12 +7,13 @@ import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.user.MurderMysteryPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPreventFallDamage implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(FinalDamageEvent event) { if (!(event.getEntity() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWaterDeath.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWaterDeath.java index 1e8dc1572..f0a8b679b 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWaterDeath.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWaterDeath.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.instance.block.Block; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.game.GameStatus; @@ -16,7 +17,7 @@ */ public class ActionWaterDeath implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { if (!(event.getPlayer() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWeaknessSplash.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWeaknessSplash.java index 2412ac7cf..f128c37ad 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWeaknessSplash.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/events/ActionWeaknessSplash.java @@ -3,8 +3,9 @@ import net.minestom.server.event.entity.EntityPotionAddEvent; import net.minestom.server.potion.PotionEffect; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; import net.swofty.type.murdermysterygame.game.GameStatus; @@ -18,7 +19,7 @@ */ public class ActionWeaknessSplash implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(EntityPotionAddEvent event) { if (!(event.getEntity() instanceof MurderMysteryPlayer player)) return; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/gold/GoldManager.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/gold/GoldManager.java index 5e41e1908..abad6d03e 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/gold/GoldManager.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/gold/GoldManager.java @@ -27,6 +27,8 @@ public class GoldManager { private static final int SPAWN_INTERVAL_SECONDS = 5; private static final int MAX_GOLD_SPAWNED = 50; private static final double PICKUP_DISTANCE = 1.5; + /** Closer than this and we count a spawn point as 'already occupied' — see #673. */ + private static final double SPAWN_POINT_OCCUPIED_DISTANCE = 1.0; private final Game game; private final List spawnedGold = new ArrayList<>(); @@ -46,10 +48,17 @@ public void startSpawning() { List spawnLocations = config.getGoldSpawns(); spawnTask = MinecraftServer.getSchedulerManager().buildTask(() -> { - if (spawnedGold.size() < MAX_GOLD_SPAWNED && !spawnLocations.isEmpty()) { - MurderMysteryMapsConfig.Position randomSpawn = spawnLocations.get(new Random().nextInt(spawnLocations.size())); - spawnGoldCoin(new Pos(randomSpawn.x(), randomSpawn.y(), randomSpawn.z())); + if (spawnedGold.size() >= MAX_GOLD_SPAWNED || spawnLocations.isEmpty()) { + return; } + MurderMysteryMapsConfig.Position randomSpawn = spawnLocations.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(spawnLocations.size())); + Pos spawnPos = new Pos(randomSpawn.x(), randomSpawn.y(), randomSpawn.z()); + // Issue #673: cap each spawn point at one gold coin. The previous loop + // rolled the same point repeatedly and stacked up to five coins there. + if (isSpawnPointOccupied(spawnPos)) { + return; + } + spawnGoldCoin(spawnPos); }).delay(TaskSchedule.seconds(3)).repeat(TaskSchedule.seconds(SPAWN_INTERVAL_SECONDS)).schedule(); pickupCheckTask = MinecraftServer.getSchedulerManager().buildTask(() -> { @@ -113,6 +122,16 @@ private void spawnGoldCoin(Pos position) { spawnedGold.add(goldEntity); } + private boolean isSpawnPointOccupied(Pos position) { + for (Entity existing : spawnedGold) { + if (existing.isRemoved()) continue; + if (existing.getPosition().distance(position) <= SPAWN_POINT_OCCUPIED_DISTANCE) { + return true; + } + } + return false; + } + public boolean collectGold(MurderMysteryPlayer player, Entity goldEntity) { if (!spawnedGold.contains(goldEntity)) return false; diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/SimpleInteractableItem.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/SimpleInteractableItem.java index d90619502..96451281a 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/SimpleInteractableItem.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/SimpleInteractableItem.java @@ -28,27 +28,15 @@ public ItemStack getItemStack() { new CustomData(CompoundBinaryTag.builder().putString("item", id).build())); } - public void onItemFinishUse(PlayerFinishItemUseEvent event) { - // stub - } + public void onItemFinishUse(PlayerFinishItemUseEvent event) {} - public void onItemUseOnBlock(PlayerUseItemOnBlockEvent event) { - // stub - } + public void onItemUseOnBlock(PlayerUseItemOnBlockEvent event) {} - public void onItemUse(PlayerUseItemEvent event) { - // stub - } + public void onItemUse(PlayerUseItemEvent event) {} - public void onItemDrop(ItemDropEvent event) { - // stub - } + public void onItemDrop(ItemDropEvent event) {} - public void onItemInteract(PlayerInstanceEvent event) { - // stub - } + public void onItemInteract(PlayerInstanceEvent event) {} - public void onBlockPlace(PlayerBlockPlaceEvent event) { - // stub - } + public void onBlockPlace(PlayerBlockPlaceEvent event) {} } diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/impl/PlayAgainItem.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/impl/PlayAgainItem.java index f9d4c92a8..ca08ae3b7 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/impl/PlayAgainItem.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/item/impl/PlayAgainItem.java @@ -5,8 +5,8 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocol; +import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; @@ -36,8 +36,8 @@ public void onItemUse(PlayerUseItemEvent event) { game.leave(player); // Queue for new game using ProxyService directly - GetServerForMapProtocolObject.GetServerForMapMessage message = - new GetServerForMapProtocolObject.GetServerForMapMessage( + GetServerForMapProtocol.GetServerForMapMessage message = + new GetServerForMapProtocol.GetServerForMapMessage( ServerType.MURDER_MYSTERY_GAME, null, gameType, @@ -45,10 +45,10 @@ public void onItemUse(PlayerUseItemEvent event) { ); PROXY_SERVICE.handleRequest(message).thenAccept(response -> { - if (response instanceof GetServerForMapProtocolObject.GetServerForMapResponse resp) { + if (response instanceof GetServerForMapProtocol.GetServerForMapResponse resp) { if (resp.server() != null) { - ChooseGameProtocolObject.ChooseGameMessage chooseMessage = - new ChooseGameProtocolObject.ChooseGameMessage( + ChooseGameProtocol.ChooseGameMessage chooseMessage = + new ChooseGameProtocol.ChooseGameMessage( player.getUuid(), resp.server(), resp.gameId() diff --git a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/redis/service/TypedInstantiateGameHandler.java b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/redis/service/InstantiateGameHandler.java similarity index 85% rename from type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/redis/service/TypedInstantiateGameHandler.java rename to type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/redis/service/InstantiateGameHandler.java index dbe7ceac4..98dc3c8ef 100644 --- a/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/redis/service/TypedInstantiateGameHandler.java +++ b/type.murdermysterygame/src/main/java/net/swofty/type/murdermysterygame/redis/service/InstantiateGameHandler.java @@ -2,25 +2,26 @@ import net.swofty.commons.murdermystery.MurderMysteryGameType; import net.swofty.commons.murdermystery.map.MurderMysteryMapsConfig; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol.Request; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.murdermysterygame.TypeMurderMysteryGameLoader; import net.swofty.type.murdermysterygame.game.Game; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedInstantiateGameHandler implements TypedServiceHandler { +public class InstantiateGameHandler implements RedisMessageHandler { private static final InstantiateGamePushProtocol PROTOCOL = new InstantiateGamePushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request request) { + public Response handle(Request request, RedisMessageContext context) { try { MurderMysteryGameType gameType = MurderMysteryGameType.valueOf(request.gameType().toUpperCase()); diff --git a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/TypeMurderMysteryLobbyLoader.java b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/TypeMurderMysteryLobbyLoader.java index c30928981..46a40acc0 100644 --- a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/TypeMurderMysteryLobbyLoader.java +++ b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/TypeMurderMysteryLobbyLoader.java @@ -7,8 +7,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.command.HypixelCommand; @@ -173,15 +172,15 @@ public List getNPCs() { @Override @SuppressWarnings("unchecked") - public List> getTypedServiceHandlers() { + public List> getServiceHandlers() { return (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.murdermysterylobby.redis.service", - TypedServiceHandler.class + RedisMessageHandler.class ).toList(); } @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerChat.java b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerChat.java index 9cfe6c720..97c84d2da 100644 --- a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerChat.java +++ b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerChat.java @@ -7,8 +7,9 @@ import net.swofty.type.generic.data.HypixelDataHandler; import net.swofty.type.generic.data.datapoints.DatapointChatType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; @@ -17,7 +18,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDataSpawn.java b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDataSpawn.java index d00e453d2..41f28ea5a 100644 --- a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDataSpawn.java +++ b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDataSpawn.java @@ -6,14 +6,15 @@ import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; if (!(HypixelConst.getTypeLoader().getType() == ServerType.MURDER_MYSTERY_LOBBY)) return; diff --git a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDisconnect.java b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDisconnect.java index 18fb6d325..31f6ae9d9 100644 --- a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDisconnect.java +++ b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerDisconnect.java @@ -2,14 +2,15 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.murdermysterylobby.MurderMysteryLobbyScoreboard; public class ActionPlayerDisconnect implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void run(PlayerDisconnectEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); MurderMysteryLobbyScoreboard.removeCache(player); diff --git a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerSpawn.java b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerSpawn.java index 9584a31d2..ad89716b7 100644 --- a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerSpawn.java +++ b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/events/ActionPlayerSpawn.java @@ -3,8 +3,9 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.minestom.server.entity.GameMode; import net.swofty.type.murdermysterylobby.TypeMurderMysteryLobbyLoader; @@ -13,7 +14,7 @@ public class ActionPlayerSpawn implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.SPAWN) public void run(PlayerSpawnEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); player.setGameMode(GameMode.SURVIVAL); diff --git a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/gui/GUIMapSelection.java b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/gui/GUIMapSelection.java index 50139f052..2375f2434 100644 --- a/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/gui/GUIMapSelection.java +++ b/type.murdermysterylobby/src/main/java/net/swofty/type/murdermysterylobby/gui/GUIMapSelection.java @@ -7,7 +7,7 @@ import net.swofty.commons.murdermystery.MurderMysteryGameType; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.lobby.LobbyOrchestratorConnector; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; @@ -64,12 +64,12 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { private void loadMaps(HypixelPlayer player) { ProxyService orchestratorService = new ProxyService(ServiceType.ORCHESTRATOR); - GetMapsProtocolObject.GetMapsMessage message = - new GetMapsProtocolObject.GetMapsMessage(ServerType.MURDER_MYSTERY_GAME, gameType.toString()); + GetMapsProtocol.GetMapsMessage message = + new GetMapsProtocol.GetMapsMessage(ServerType.MURDER_MYSTERY_GAME, gameType.toString()); orchestratorService.handleRequest(message) .thenAccept(response -> { - if (response instanceof GetMapsProtocolObject.GetMapsResponse mapsResponse) { + if (response instanceof GetMapsProtocol.GetMapsResponse mapsResponse) { maps = mapsResponse.maps(); mapsLoaded = true; diff --git a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/TypePrototypeLobbyLoader.java b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/TypePrototypeLobbyLoader.java index 056cd6285..0a136858c 100644 --- a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/TypePrototypeLobbyLoader.java +++ b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/TypePrototypeLobbyLoader.java @@ -5,8 +5,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.data.GameDataHandler; @@ -160,15 +159,15 @@ public List getNPCs() { @Override @SuppressWarnings("unchecked") - public List> getTypedServiceHandlers() { + public List> getServiceHandlers() { return (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.prototypelobby.redis.service", - TypedServiceHandler.class + RedisMessageHandler.class ).toList(); } @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerChat.java b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerChat.java index ad4b4db48..8a174f572 100644 --- a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerChat.java +++ b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerChat.java @@ -7,8 +7,9 @@ import net.swofty.type.generic.data.HypixelDataHandler; import net.swofty.type.generic.data.datapoints.DatapointChatType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; @@ -17,7 +18,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDataSpawn.java b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDataSpawn.java index e2f64118f..829c99196 100644 --- a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDataSpawn.java +++ b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDataSpawn.java @@ -6,14 +6,15 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; @@ -34,4 +35,4 @@ public void run(PlayerSpawnEvent event) { .clickEvent(ClickEvent.openUrl("https://hypixel.net/PTL"))); player.sendMessage(Component.empty()); } -} \ No newline at end of file +} diff --git a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDisconnect.java b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDisconnect.java index 0b6566b8d..8d45859dd 100644 --- a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDisconnect.java +++ b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerDisconnect.java @@ -2,14 +2,15 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.prototypelobby.PrototypeLobbyScoreboard; public class ActionPlayerDisconnect implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void run(PlayerDisconnectEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); PrototypeLobbyScoreboard.removeCache(player); diff --git a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerSpawn.java b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerSpawn.java index 0c5b6c4e2..dee879796 100644 --- a/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerSpawn.java +++ b/type.prototypelobby/src/main/java/net/swofty/type/prototypelobby/events/ActionPlayerSpawn.java @@ -3,15 +3,16 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.prototypelobby.util.PrototypeLobbyMap; public class ActionPlayerSpawn implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.SPAWN) public void run(PlayerSpawnEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerFirstSpawnTexturePack.java b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerFirstSpawnTexturePack.java index a8947cbfa..feac0233f 100644 --- a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerFirstSpawnTexturePack.java +++ b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerFirstSpawnTexturePack.java @@ -3,15 +3,16 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.ravengardgeneric.texturepack.TexturePackManager; import org.tinylog.Logger; public class ActionPlayerFirstSpawnTexturePack implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) { return; diff --git a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerJoin.java b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerJoin.java index f3b4cc883..aa026253a 100644 --- a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerJoin.java +++ b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.instance.Instance; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.ravengardgeneric.user.RavengardPlayer; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { RavengardPlayer player = (RavengardPlayer) event.getPlayer(); diff --git a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerClearRavengardCache.java b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerClearRavengardCache.java index e7adc33e7..b8bae2f8f 100644 --- a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerClearRavengardCache.java +++ b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerClearRavengardCache.java @@ -2,12 +2,13 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerClearRavengardCache implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerDisconnectEvent event) { // Reserved for non-persistent Ravengard runtime caches. } diff --git a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataLoad.java b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataLoad.java index 581c5de73..4c0b04a03 100644 --- a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataLoad.java +++ b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataLoad.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.ravengardgeneric.data.RavengardDataHandler; import net.swofty.type.ravengardgeneric.user.RavengardPlayer; import org.bson.Document; @@ -16,7 +17,7 @@ public class ActionPlayerRavengardDataLoad implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(AsyncPlayerConfigurationEvent event) { RavengardPlayer player = (RavengardPlayer) event.getPlayer(); UUID playerUuid = player.getUuid(); diff --git a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSave.java b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSave.java index 2bda33d6d..c637b8b05 100644 --- a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSave.java +++ b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSave.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.ravengardgeneric.data.RavengardDataHandler; import net.swofty.type.ravengardgeneric.user.RavengardPlayer; import org.tinylog.Logger; @@ -15,7 +16,7 @@ public class ActionPlayerRavengardDataSave implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerDisconnectEvent event) { RavengardPlayer player = (RavengardPlayer) event.getPlayer(); UUID playerUuid = player.getUuid(); diff --git a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSpawn.java b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSpawn.java index 51a069186..d1e707662 100644 --- a/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSpawn.java +++ b/type.ravengardgeneric/src/main/java/net/swofty/type/ravengardgeneric/event/actions/player/data/ActionPlayerRavengardDataSpawn.java @@ -2,14 +2,15 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.ravengardgeneric.data.RavengardDataHandler; import net.swofty.type.ravengardgeneric.user.RavengardPlayer; public class ActionPlayerRavengardDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) { return; diff --git a/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/TypeRavengardLobbyLoader.java b/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/TypeRavengardLobbyLoader.java index a17d2c5de..a878abaf5 100644 --- a/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/TypeRavengardLobbyLoader.java +++ b/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/TypeRavengardLobbyLoader.java @@ -10,7 +10,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.RavengardTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; @@ -114,7 +114,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/events/ActionPlayerVoid.java b/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/events/ActionPlayerVoid.java index 2cd21b2b5..f1eb9cd8e 100644 --- a/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/events/ActionPlayerVoid.java +++ b/type.ravengardlobby/src/main/java/net/swofty/type/ravengardlobby/events/ActionPlayerVoid.java @@ -3,12 +3,13 @@ import net.minestom.server.event.player.PlayerMoveEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerVoid implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { if (event.getPlayer().getPosition().y() < 0) { event.getPlayer().teleport(HypixelConst.getTypeLoader() diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java index c78beccd4..1a1480c6a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java @@ -61,6 +61,7 @@ import net.swofty.type.skyblockgeneric.entity.mob.MobRegistry; import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; import net.swofty.type.skyblockgeneric.event.value.SkyBlockValueEvent; +import net.swofty.type.skyblockgeneric.fishing.registry.FishingRegistry; import net.swofty.type.skyblockgeneric.item.ItemConfigParser; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.CraftableComponent; @@ -72,6 +73,7 @@ import net.swofty.type.skyblockgeneric.item.set.impl.SetRepeatable; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; import net.swofty.type.skyblockgeneric.levels.CustomLevelAward; +import net.swofty.type.skyblockgeneric.slayer.SlayerRegistry; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelRequirement; import net.swofty.type.skyblockgeneric.levels.unlocks.CustomLevelUnlock; @@ -85,7 +87,7 @@ import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; import net.swofty.type.skyblockgeneric.server.attribute.SkyBlockServerAttributes; import net.swofty.type.skyblockgeneric.server.eventcaller.CustomEventCaller; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; +import net.swofty.type.skyblockgeneric.user.island.SkyBlockIsland; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.user.SkyBlockScoreboard; import net.swofty.type.skyblockgeneric.user.StashReminder; @@ -176,6 +178,8 @@ public void initialize(MinecraftServer server) { } catch (IOException e) { Logger.error("Failed to scan for YAML files", e); } + FishingRegistry.loadAll(); + SlayerRegistry.loadAll(); /** * Register commands diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarAwarder.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarAwarder.java index e42c5a2b0..72539da1e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarAwarder.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarAwarder.java @@ -9,6 +9,7 @@ import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import org.json.JSONObject; +import org.tinylog.Logger; import java.text.DecimalFormat; import java.util.UUID; @@ -93,12 +94,12 @@ public static boolean processPendingTransaction(SkyBlockPlayer player, String tr return processExpiredOrder(player, transaction); } default -> { - System.err.println("Unknown pending transaction type: " + transactionType); + Logger.warn("Unknown pending transaction type: {}", transactionType); return false; } } } catch (Exception e) { - System.err.println("Failed to process pending transaction: " + e.getMessage()); + Logger.error(e, "Failed to process pending transaction"); return false; } } @@ -138,7 +139,7 @@ private static boolean processBuyer(SkyBlockPlayer player, SuccessfulBazaarTrans return true; } catch (Exception e) { - System.err.println("Failed to process buyer transaction: " + e.getMessage()); + Logger.error(e, "Failed to process buyer transaction"); return false; } } @@ -174,7 +175,7 @@ private static boolean processRefund(SkyBlockPlayer player, BuyOrderRefundTransa return true; } catch (Exception e) { - System.err.println("Failed to process refund transaction: " + e.getMessage()); + Logger.error(e, "Failed to process refund transaction"); return false; } } @@ -214,7 +215,7 @@ private static boolean processSeller(SkyBlockPlayer player, SuccessfulBazaarTran return true; } catch (Exception e) { - System.err.println("Failed to process seller transaction: " + e.getMessage()); + Logger.error(e, "Failed to process seller transaction"); return false; } } @@ -263,7 +264,7 @@ private static boolean processExpiredOrderOwner(SkyBlockPlayer player, OrderExpi return true; } catch (Exception e) { - System.err.println("Failed to process expired order: " + e.getMessage()); + Logger.error(e, "Failed to process expired order"); return false; } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java index a784a15f3..d5b654954 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java @@ -28,13 +28,13 @@ private UUID getPlayerProfileUUID() { } public CompletableFuture> getPendingOrders() { - var message = new BazaarGetPendingOrdersProtocolObject.BazaarGetPendingOrdersMessage( + var message = new BazaarGetPendingOrdersProtocol.BazaarGetPendingOrdersMessage( player.getUuid(), getPlayerProfileUUID() ); - return bazaarService.handleRequest(message) + return bazaarService.handleRequest(message) .thenApply(response -> response.orders().stream() .map(order -> new BazaarOrder( order.orderId(), @@ -48,22 +48,22 @@ public CompletableFuture> getPendingOrders() { } public CompletableFuture cancelOrder(UUID orderId) { - var message = new BazaarCancelProtocolObject.CancelMessage( + var message = new BazaarCancelProtocol.CancelMessage( orderId, player.getUuid(), getPlayerProfileUUID() ); - return bazaarService.handleRequest(message) + return bazaarService.handleRequest(message) .thenApply(response -> response.success()); } public CompletableFuture getItemData(ItemType itemType) { - var message = new BazaarGetItemProtocolObject.BazaarGetItemMessage(itemType.name()); + var message = new BazaarGetItemProtocol.BazaarGetItemMessage(itemType.name()); - return bazaarService.handleRequest(message) + return bazaarService.handleRequest(message) .thenApply(response -> { var buyOrders = response.buyOrders().stream() .map(order -> new MarketOrder( @@ -104,7 +104,7 @@ public CompletableFuture getItemStatistics(ItemType itemType) } public CompletableFuture createBuyOrder(ItemType itemType, double pricePerUnit, int quantity) { - var message = new BazaarBuyProtocolObject.BazaarBuyMessage( + var message = new BazaarBuyProtocol.BazaarBuyMessage( itemType.name(), quantity, pricePerUnit, @@ -112,8 +112,8 @@ public CompletableFuture createBuyOrder(ItemType itemType, double getPlayerProfileUUID() ); - return bazaarService.handleRequest(message) + return bazaarService.handleRequest(message) .thenApply(response -> new BazaarResult( response.success(), response.success() ? "Buy order created!" : "Failed to create buy order" @@ -121,7 +121,7 @@ public CompletableFuture createBuyOrder(ItemType itemType, double } public CompletableFuture createSellOrder(ItemType itemType, double pricePerUnit, int quantity) { - var message = new BazaarSellProtocolObject.BazaarSellMessage( + var message = new BazaarSellProtocol.BazaarSellMessage( itemType.name(), player.getUuid(), getPlayerProfileUUID(), @@ -129,8 +129,8 @@ public CompletableFuture createSellOrder(ItemType itemType, double quantity ); - return bazaarService.handleRequest(message) + return bazaarService.handleRequest(message) .thenApply(response -> new BazaarResult( response.success(), response.success() ? "Sell order created!" : "Failed to create sell order" @@ -206,13 +206,13 @@ public CompletableFuture isOnline() { } public CompletableFuture> getPendingTransactions() { - var message = new BazaarGetPendingTransactionsProtocolObject.BazaarGetPendingTransactionsMessage( + var message = new BazaarGetPendingTransactionsProtocol.BazaarGetPendingTransactionsMessage( player.getUuid(), getPlayerProfileUUID() ); - return bazaarService.handleRequest(message) + return bazaarService.handleRequest(message) .thenApply(response -> response.transactions().stream() .map(txInfo -> new PendingTransaction( txInfo.id(), @@ -224,14 +224,14 @@ public CompletableFuture> getPendingTransactions() { } public CompletableFuture processPendingTransactions(List transactionIds) { - var message = new BazaarProcessPendingTransactionsProtocolObject.BazaarProcessPendingTransactionsMessage( + var message = new BazaarProcessPendingTransactionsProtocol.BazaarProcessPendingTransactionsMessage( player.getUuid(), getPlayerProfileUUID(), transactionIds ); - return bazaarService.handleRequest(message) + return bazaarService.handleRequest(message) .thenApply(response -> new TransactionProcessResult( response.processedCount(), response.failedCount(), @@ -279,7 +279,7 @@ private CompletableFuture processTransactions(List trackedItemFuture = service.handleRequest( - new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage( + CompletableFuture trackedItemFuture = service.handleRequest( + new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage( UUID.fromString(item.getAttributeHandler().getUniqueTrackedID()) )); @@ -51,9 +51,9 @@ public void registerUsage(MinestomCommand command) { player.sendMessage("§7- §eItem UUID: §7" + trackedItem.getItemUUID()); player.sendMessage("§7- §eNumber Made: §7" + trackedItem.getNumberMade()); player.sendMessage("§7- §eMade: §7" + StringUtility.formatTimeAsAgo(trackedItem.getCreated())); - player.sendMessage("§8Attached Players: §7" + trackedItem.attachedPlayers.size()); + player.sendMessage("§8Attached Players: §7" + trackedItem.getAttachedPlayers().size()); - trackedItem.attachedPlayers.forEach(log -> { + trackedItem.getAttachedPlayers().forEach(log -> { player.sendMessage("§7- §ePlayer UUID: §7" + log.playerUUID()); player.sendMessage("§7- §eProfile UUID: §7" + log.playerProfileUUID()); player.sendMessage("§7- §eFirst Seen: §7" + StringUtility.formatTimeAsAgo(log.firstSeen())); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/SlayerCommand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/SlayerCommand.java new file mode 100644 index 000000000..077340a10 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/SlayerCommand.java @@ -0,0 +1,65 @@ +package net.swofty.type.skyblockgeneric.commands; + +import net.minestom.server.command.builder.arguments.ArgumentEnum; +import net.minestom.server.command.builder.arguments.ArgumentType; +import net.swofty.type.generic.command.CommandParameters; +import net.swofty.type.generic.command.HypixelCommand; +import net.swofty.type.generic.user.categories.Rank; +import net.swofty.type.skyblockgeneric.slayer.SlayerService; +import net.swofty.type.skyblockgeneric.slayer.SlayerTier; +import net.swofty.type.skyblockgeneric.slayer.SlayerTierDefinition; +import net.swofty.type.skyblockgeneric.slayer.SlayerType; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +@CommandParameters(description = "Starts and manages Slayer quests", + usage = "/slayer ", + permission = Rank.DEFAULT, + allowsConsole = false) +public class SlayerCommand extends HypixelCommand { + @Override + public void registerUsage(MinestomCommand command) { + ArgumentEnum typeArgument = ArgumentType.Enum("type", SlayerType.class); + ArgumentEnum tierArgument = ArgumentType.Enum("tier", SlayerTier.class); + + command.addSyntax((sender, context) -> { + if (!permissionCheck(sender)) return; + + SkyBlockPlayer player = (SkyBlockPlayer) sender; + SlayerService.StartResult result = SlayerService.startQuest( + player, + context.get(typeArgument), + context.get(tierArgument) + ); + if (!result.success()) { + player.sendMessage("§c" + result.message()); + } + }, ArgumentType.Literal("start"), typeArgument, tierArgument); + + command.addSyntax((sender, context) -> { + if (!permissionCheck(sender)) return; + + SkyBlockPlayer player = (SkyBlockPlayer) sender; + SlayerService.QuestStatus status = SlayerService.status(player); + if (!status.active()) { + player.sendMessage("§cYou do not have an active Slayer quest."); + return; + } + + SlayerTierDefinition tier = status.tier(); + if (tier == null) { + player.sendMessage("§cYour active Slayer quest is no longer configured."); + return; + } + + player.sendMessage("§5§lSLAYER QUEST"); + player.sendMessage("§7Boss: §c" + tier.displayName(status.quest().type())); + player.sendMessage("§7Progress: §e" + status.quest().combatXp() + "§8/§e" + tier.requiredCombatXp() + " Combat XP"); + player.sendMessage(status.quest().bossSpawned() ? "§cBoss spawned!" : "§7Kill matching mobs to summon your boss."); + }, ArgumentType.Literal("status")); + + command.addSyntax((sender, context) -> { + if (!permissionCheck(sender)) return; + SlayerService.cancelQuest((SkyBlockPlayer) sender); + }, ArgumentType.Literal("cancel")); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/VerifyApiCommand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/VerifyApiCommand.java index 0e0d99175..3d68d71e6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/VerifyApiCommand.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/VerifyApiCommand.java @@ -2,7 +2,7 @@ import net.minestom.server.command.builder.arguments.ArgumentString; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.api.APIAuthenticateCodeProtocolObject; +import net.swofty.commons.protocol.objects.api.APIAuthenticateCodeProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.command.CommandParameters; import net.swofty.type.generic.command.HypixelCommand; @@ -35,12 +35,12 @@ public void registerUsage(MinestomCommand command) { SkyBlockPlayer player = (SkyBlockPlayer) sender; ProxyService apiService = new ProxyService(ServiceType.API); - apiService.handleRequest(new APIAuthenticateCodeProtocolObject.AuthenticateCodeMessage( + apiService.handleRequest(new APIAuthenticateCodeProtocol.AuthenticateCodeMessage( codeString, player.getUsername(), player.getUuid() )).thenAccept(nonCastedResponse -> { - APIAuthenticateCodeProtocolObject.AuthenticateCodeResponse response = (APIAuthenticateCodeProtocolObject.AuthenticateCodeResponse) nonCastedResponse; + APIAuthenticateCodeProtocol.AuthenticateCodeResponse response = (APIAuthenticateCodeProtocol.AuthenticateCodeResponse) nonCastedResponse; if (response.success()) { sender.sendMessage("§aCode '" + codeString + "' has successfully been verified! Check your web browser."); } else { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/DataMutexService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/DataMutexService.java index eb309067b..bd8b17454 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/DataMutexService.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/DataMutexService.java @@ -3,9 +3,9 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.UnderstandableProxyServer; import net.swofty.commons.protocol.Serializer; -import net.swofty.commons.protocol.objects.datamutex.SynchronizeDataProtocolObject; -import net.swofty.commons.protocol.objects.datamutex.UnlockDataProtocolObject; -import net.swofty.commons.protocol.objects.datamutex.UpdateSynchronizedDataProtocolObject; +import net.swofty.commons.protocol.objects.datamutex.SynchronizeDataProtocol; +import net.swofty.commons.protocol.objects.datamutex.UnlockDataProtocol; +import net.swofty.commons.protocol.objects.datamutex.UpdateSynchronizedDataProtocol; import net.swofty.proxyapi.ProxyInformation; import net.swofty.proxyapi.ProxyPlayer; import net.swofty.proxyapi.ProxyService; @@ -63,12 +63,12 @@ public void withSynchronizedData(String lockKey, List coopMembers, UUID playerUUID = coopMembers.getFirst(); Logger.info("Using playerUUID: " + playerUUID + " for synchronization"); - SynchronizeDataProtocolObject.SynchronizeDataRequest request = - new SynchronizeDataProtocolObject.SynchronizeDataRequest(onlineServers, playerUUID, dataType.getKey()); + SynchronizeDataProtocol.SynchronizeDataRequest request = + new SynchronizeDataProtocol.SynchronizeDataRequest(onlineServers, playerUUID, dataType.getKey()); Logger.info("Sending synchronization request to service..."); - CompletableFuture syncFuture = + CompletableFuture syncFuture = service.handleRequest(request); syncFuture.thenAccept(response -> { @@ -88,11 +88,11 @@ public void withSynchronizedData(String lockKey, List coopMembers, // Serialize as T String serializedData = ser.serialize(modifiedData); - UpdateSynchronizedDataProtocolObject.UpdateDataRequest updateRequest = - new UpdateSynchronizedDataProtocolObject.UpdateDataRequest( + UpdateSynchronizedDataProtocol.UpdateDataRequest updateRequest = + new UpdateSynchronizedDataProtocol.UpdateDataRequest( onlineServers, playerUUID, dataType.getKey(), serializedData); - CompletableFuture updateFuture = + CompletableFuture updateFuture = service.handleRequest(updateRequest); updateFuture.thenAccept(updateResponse -> { @@ -176,10 +176,10 @@ private void unlockData(List serverUUIDs, UUID playerUUID, String dataKey) Logger.info("Unlocking data for player " + playerUUID + " on servers: " + serverUUIDs); // Send unlock request to the mutex service, which will then unlock on all servers - service.handleRequest(new UnlockDataProtocolObject.UnlockDataRequest( + service.handleRequest(new UnlockDataProtocol.UnlockDataRequest( serverUUIDs, playerUUID, dataKey )).thenAccept(response -> { - UnlockDataProtocolObject.UnlockDataResponse responseObject = (UnlockDataProtocolObject.UnlockDataResponse) response; + UnlockDataProtocol.UnlockDataResponse responseObject = (UnlockDataProtocol.UnlockDataResponse) response; Logger.info("Unlock response: success=" + responseObject.success() + ", error=" + responseObject.error()); if (!responseObject.success()) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java index a3afeed4e..5bd336526 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java @@ -373,6 +373,15 @@ DatapointPetData.class, new DatapointPetData("pet_data")), QUIVER("quiver", false, false, false, DatapointQuiver.class, new DatapointQuiver("quiver")), + SHIP_STATE("ship_state", false, false, false, + DatapointShipState.class, new DatapointShipState("ship_state")), + + TROPHY_FISH("trophy_fish", false, false, false, + DatapointTrophyFish.class, new DatapointTrophyFish("trophy_fish")), + + SLAYER("slayer", false, false, false, + DatapointSlayer.class, new DatapointSlayer("slayer")), + RACE_BEST_TIME("race_best_time", false, false, false, DatapointMapStringLong.class, new DatapointMapStringLong("race_best_time")), diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointCompletedBazaarTransactions.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointCompletedBazaarTransactions.java index aa777a721..69719677f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointCompletedBazaarTransactions.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointCompletedBazaarTransactions.java @@ -81,7 +81,7 @@ public PlayerCompletedBazaarTransactions deserialize(String json) { transactions.add(transaction); } } catch (Exception e) { - System.err.println("Failed to deserialize completed bazaar transactions: " + e.getMessage()); + org.tinylog.Logger.error(e, "Failed to deserialize completed bazaar transactions"); return new PlayerCompletedBazaarTransactions(new ArrayList<>()); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointShipState.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointShipState.java new file mode 100644 index 000000000..5f761ba50 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointShipState.java @@ -0,0 +1,97 @@ +package net.swofty.type.skyblockgeneric.data.datapoints; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class DatapointShipState extends SkyBlockDatapoint { + private static final Serializer serializer = new Serializer<>() { + @Override + public String serialize(ShipState value) { + JSONObject object = new JSONObject(); + object.put("shipName", value.getShipName()); + object.put("helm", value.getHelm()); + object.put("engine", value.getEngine()); + object.put("hull", value.getHull()); + object.put("destinations", value.getUnlockedDestinations()); + return object.toString(); + } + + @Override + public ShipState deserialize(String json) { + if (json == null || json.isEmpty()) { + return new ShipState(); + } + + JSONObject object = new JSONObject(json); + List destinations = new ArrayList<>(); + JSONArray array = object.optJSONArray("destinations"); + if (array != null) { + for (Object entry : array) { + destinations.add(String.valueOf(entry)); + } + } + + return new ShipState( + object.optString("shipName", "Zephyr"), + object.optString("helm", "CRACKED_SHIP_HELM"), + emptyToNull(object.optString("engine", "")), + object.optString("hull", "RUSTY_SHIP_HULL"), + destinations + ); + } + + @Override + public ShipState clone(ShipState value) { + return new ShipState( + value.getShipName(), + value.getHelm(), + value.getEngine(), + value.getHull(), + new ArrayList<>(value.getUnlockedDestinations()) + ); + } + }; + + public DatapointShipState(String key, ShipState value) { + super(key, value, serializer); + } + + public DatapointShipState(String key) { + this(key, new ShipState()); + } + + private static String emptyToNull(String value) { + return value == null || value.isEmpty() ? null : value; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ShipState { + private String shipName = "Zephyr"; + private String helm = "CRACKED_SHIP_HELM"; + private String engine = null; + private String hull = "RUSTY_SHIP_HULL"; + private List unlockedDestinations = new ArrayList<>(); + + public boolean hasDestination(String destinationId) { + return unlockedDestinations.contains(destinationId); + } + + public void unlockDestination(String destinationId) { + if (!unlockedDestinations.contains(destinationId)) { + unlockedDestinations.add(destinationId); + } + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointSlayer.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointSlayer.java new file mode 100644 index 000000000..77428f429 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointSlayer.java @@ -0,0 +1,139 @@ +package net.swofty.type.skyblockgeneric.data.datapoints; + +import java.util.EnumMap; +import java.util.Map; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; +import net.swofty.type.skyblockgeneric.slayer.SlayerQuest; +import net.swofty.type.skyblockgeneric.slayer.SlayerTier; +import net.swofty.type.skyblockgeneric.slayer.SlayerType; +import org.jetbrains.annotations.Nullable; +import org.json.JSONObject; + +public class DatapointSlayer extends SkyBlockDatapoint { + private static final Serializer serializer = new Serializer<>() { + @Override + public String serialize(SlayerData value) { + JSONObject object = new JSONObject(); + JSONObject progressObject = new JSONObject(); + value.getProgress().forEach((type, progress) -> { + JSONObject entry = new JSONObject(); + entry.put("xp", progress.getXp()); + JSONObject completions = new JSONObject(); + progress.getCompletions().forEach((tier, amount) -> completions.put(tier.name(), amount)); + entry.put("completions", completions); + progressObject.put(type.name(), entry); + }); + object.put("progress", progressObject); + + if (value.getActiveQuest() != null) { + SlayerQuest quest = value.getActiveQuest(); + JSONObject questObject = new JSONObject(); + questObject.put("type", quest.type().name()); + questObject.put("tier", quest.tier().name()); + questObject.put("startedAt", quest.startedAt()); + questObject.put("combatXp", quest.combatXp()); + questObject.put("bossSpawned", quest.bossSpawned()); + if (quest.bossUuid() != null) { + questObject.put("bossUuid", quest.bossUuid().toString()); + } + object.put("activeQuest", questObject); + } + + return object.toString(); + } + + @Override + public SlayerData deserialize(String json) { + SlayerData data = new SlayerData(); + if (json == null || json.isEmpty()) { + return data; + } + + JSONObject object = new JSONObject(json); + JSONObject progressObject = object.optJSONObject("progress"); + if (progressObject != null) { + for (String typeId : progressObject.keySet()) { + SlayerType type = SlayerType.valueOf(typeId); + JSONObject entry = progressObject.getJSONObject(typeId); + SlayerProgress progress = new SlayerProgress(); + progress.setXp(entry.optInt("xp", 0)); + JSONObject completions = entry.optJSONObject("completions"); + if (completions != null) { + for (String tierId : completions.keySet()) { + progress.getCompletions().put(SlayerTier.valueOf(tierId), completions.optInt(tierId, 0)); + } + } + data.getProgress().put(type, progress); + } + } + + JSONObject questObject = object.optJSONObject("activeQuest"); + if (questObject != null) { + data.setActiveQuest(new SlayerQuest( + SlayerType.valueOf(questObject.getString("type")), + SlayerTier.valueOf(questObject.getString("tier")), + questObject.optLong("startedAt", System.currentTimeMillis()), + questObject.optInt("combatXp", 0), + questObject.optBoolean("bossSpawned", false), + questObject.has("bossUuid") ? UUID.fromString(questObject.getString("bossUuid")) : null + )); + } + return data; + } + + @Override + public SlayerData clone(SlayerData value) { + SlayerData clone = new SlayerData(); + value.getProgress().forEach((type, progress) -> { + SlayerProgress copied = new SlayerProgress(progress.getXp(), new EnumMap<>(progress.getCompletions())); + clone.getProgress().put(type, copied); + }); + clone.setActiveQuest(value.getActiveQuest()); + return clone; + } + }; + + public DatapointSlayer(String key, SlayerData value) { + super(key, value, serializer); + } + + public DatapointSlayer(String key) { + this(key, new SlayerData()); + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SlayerData { + private Map progress = new EnumMap<>(SlayerType.class); + private @Nullable SlayerQuest activeQuest; + + public SlayerProgress progress(SlayerType type) { + return progress.computeIfAbsent(type, ignored -> new SlayerProgress()); + } + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SlayerProgress { + private int xp; + private Map completions = new EnumMap<>(SlayerTier.class); + + public int completions(SlayerTier tier) { + return completions.getOrDefault(tier, 0); + } + + public void addCompletion(SlayerTier tier) { + completions.put(tier, completions(tier) + 1); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java new file mode 100644 index 000000000..395512ca5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java @@ -0,0 +1,144 @@ +package net.swofty.type.skyblockgeneric.data.datapoints; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Map; + +public class DatapointTrophyFish extends SkyBlockDatapoint { + private static final Serializer serializer = new Serializer<>() { + @Override + public String serialize(TrophyFishData value) { + JSONObject object = new JSONObject(); + JSONObject fishObject = new JSONObject(); + value.getFish().forEach((fishId, progress) -> { + JSONObject progressObject = new JSONObject(); + progressObject.put("bronze", progress.getBronze()); + progressObject.put("silver", progress.getSilver()); + progressObject.put("gold", progress.getGold()); + progressObject.put("diamond", progress.getDiamond()); + progressObject.put("totalCatches", progress.getTotalCatches()); + progressObject.put("catchesSinceGoldPity", progress.getCatchesSinceGoldPity()); + progressObject.put("catchesSinceDiamondPity", progress.getCatchesSinceDiamondPity()); + fishObject.put(fishId, progressObject); + }); + object.put("fish", fishObject); + return object.toString(); + } + + @Override + public TrophyFishData deserialize(String json) { + TrophyFishData data = new TrophyFishData(); + if (json == null || json.isEmpty()) { + return data; + } + + JSONObject object = new JSONObject(json); + JSONObject fishObject = object.optJSONObject("fish"); + if (fishObject == null) { + return data; + } + + for (String fishId : fishObject.keySet()) { + JSONObject progressObject = fishObject.getJSONObject(fishId); + data.getFish().put(fishId, new FishProgress( + progressObject.optInt("bronze", 0), + progressObject.optInt("silver", 0), + progressObject.optInt("gold", 0), + progressObject.optInt("diamond", 0), + progressObject.optInt("totalCatches", 0), + progressObject.optInt("catchesSinceGoldPity", progressObject.optInt("totalCatches", 0)), + progressObject.optInt("catchesSinceDiamondPity", progressObject.optInt("totalCatches", 0)) + )); + } + return data; + } + + @Override + public TrophyFishData clone(TrophyFishData value) { + Map fish = new HashMap<>(); + value.getFish().forEach((fishId, progress) -> + fish.put(fishId, new FishProgress( + progress.getBronze(), + progress.getSilver(), + progress.getGold(), + progress.getDiamond(), + progress.getTotalCatches(), + progress.getCatchesSinceGoldPity(), + progress.getCatchesSinceDiamondPity() + ))); + return new TrophyFishData(fish); + } + }; + + public DatapointTrophyFish(String key, TrophyFishData value) { + super(key, value, serializer); + } + + public DatapointTrophyFish(String key) { + this(key, new TrophyFishData()); + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class TrophyFishData { + private Map fish = new HashMap<>(); + + public FishProgress getProgress(String fishId) { + return fish.computeIfAbsent(fishId, ignored -> new FishProgress()); + } + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class FishProgress { + private int bronze; + private int silver; + private int gold; + private int diamond; + private int totalCatches; + private int catchesSinceGoldPity; + private int catchesSinceDiamondPity; + + public void increment(String tier) { + switch (tier.toUpperCase()) { + case "DIAMOND" -> { + diamond++; + catchesSinceDiamondPity = 0; + catchesSinceGoldPity = 0; + } + case "GOLD" -> { + gold++; + catchesSinceGoldPity = 0; + catchesSinceDiamondPity++; + } + case "SILVER" -> silver++; + default -> bronze++; + } + if (!"GOLD".equalsIgnoreCase(tier) && !"DIAMOND".equalsIgnoreCase(tier)) { + catchesSinceGoldPity++; + catchesSinceDiamondPity++; + } + totalCatches++; + } + + public boolean hasTier(String tier) { + return switch (tier.toUpperCase()) { + case "DIAMOND" -> diamond > 0; + case "GOLD" -> gold > 0; + case "SILVER" -> silver > 0; + default -> bronze > 0; + }; + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionCandidate.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionCandidate.java index 84f3f5e4e..31b537884 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionCandidate.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionCandidate.java @@ -1,6 +1,6 @@ package net.swofty.type.skyblockgeneric.elections; -import net.swofty.commons.protocol.objects.election.GetCandidatesProtocolObject; +import net.swofty.commons.protocol.objects.election.GetCandidatesProtocol; import java.util.List; @@ -11,7 +11,7 @@ public record ElectionCandidate( double votePercentage ) { - public static ElectionCandidate fromProtocol(GetCandidatesProtocolObject.CandidateInfo info) { + public static ElectionCandidate fromProtocol(GetCandidatesProtocol.CandidateInfo info) { SkyBlockMayor mayor; try { mayor = SkyBlockMayor.valueOf(info.mayorName()); @@ -33,7 +33,7 @@ public static ElectionCandidate fromProtocol(GetCandidatesProtocolObject.Candida return new ElectionCandidate(mayor, perks, info.votes(), info.votePercentage()); } - public static List fromProtocolList(List infos) { + public static List fromProtocolList(List infos) { return infos.stream() .map(ElectionCandidate::fromProtocol) .filter(c -> c != null) diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionManager.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionManager.java index b8f988daf..be96fc3d1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionManager.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/elections/ElectionManager.java @@ -5,12 +5,12 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.timer.TaskSchedule; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.election.CastVoteProtocolObject; -import net.swofty.commons.protocol.objects.election.GetCandidatesProtocolObject; -import net.swofty.commons.protocol.objects.election.GetElectionDataProtocolObject; -import net.swofty.commons.protocol.objects.election.GetPlayerVoteProtocolObject; -import net.swofty.commons.protocol.objects.election.ResolveElectionProtocolObject; -import net.swofty.commons.protocol.objects.election.StartElectionProtocolObject; +import net.swofty.commons.protocol.objects.election.CastVoteProtocol; +import net.swofty.commons.protocol.objects.election.GetCandidatesProtocol; +import net.swofty.commons.protocol.objects.election.GetElectionDataProtocol; +import net.swofty.commons.protocol.objects.election.GetPlayerVoteProtocol; +import net.swofty.commons.protocol.objects.election.ResolveElectionProtocol; +import net.swofty.commons.protocol.objects.election.StartElectionProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; import org.tinylog.Logger; @@ -35,10 +35,10 @@ public class ElectionManager { public static void loadFromService() { SERVICE = new ProxyService(ServiceType.ELECTION); try { - GetElectionDataProtocolObject.GetElectionDataResponse response = - SERVICE.handleRequest( - new GetElectionDataProtocolObject.GetElectionDataMessage() + GetElectionDataProtocol.GetElectionDataResponse response = + SERVICE.handleRequest( + new GetElectionDataProtocol.GetElectionDataMessage() ).join(); if (response.found() && response.serializedData() != null) { @@ -81,10 +81,10 @@ public static void onElectionStart() { String serialized = GSON.toJson(electionData); try { - StartElectionProtocolObject.StartElectionResponse response = - SERVICE.handleRequest( - new StartElectionProtocolObject.StartElectionMessage(currentYear, serialized) + StartElectionProtocol.StartElectionResponse response = + SERVICE.handleRequest( + new StartElectionProtocol.StartElectionMessage(currentYear, serialized) ).join(); if (response.serializedData() != null) { @@ -107,10 +107,10 @@ public static void onElectionEnd() { int currentYear = SkyBlockCalendar.getYear(); try { - ResolveElectionProtocolObject.ResolveElectionResponse response = - SERVICE.handleRequest( - new ResolveElectionProtocolObject.ResolveElectionMessage(currentYear) + ResolveElectionProtocol.ResolveElectionResponse response = + SERVICE.handleRequest( + new ResolveElectionProtocol.ResolveElectionMessage(currentYear) ).join(); if (response.serializedData() != null) { @@ -136,9 +136,9 @@ public static CompletableFuture castVote(UUID accountId, String candidateN .anyMatch(c -> c.getMayorName().equals(candidateName)); if (!validCandidate) return CompletableFuture.completedFuture(null); - return SERVICE.handleRequest( - new CastVoteProtocolObject.CastVoteMessage(accountId, candidateName) + return SERVICE.handleRequest( + new CastVoteProtocol.CastVoteMessage(accountId, candidateName) ).thenAccept(response -> { if (response.success()) { playerVoteCache.put(accountId, candidateName); @@ -160,9 +160,9 @@ public static CompletableFuture fetchPlayerVote(UUID accountId) { String cached = playerVoteCache.get(accountId); if (cached != null) return CompletableFuture.completedFuture(cached); - return SERVICE.handleRequest( - new GetPlayerVoteProtocolObject.GetPlayerVoteMessage(accountId) + return SERVICE.handleRequest( + new GetPlayerVoteProtocol.GetPlayerVoteMessage(accountId) ).thenApply(response -> { if (response.candidateName() != null) { playerVoteCache.put(accountId, response.candidateName()); @@ -196,11 +196,11 @@ public static boolean isPerkActive(SkyBlockMayor.Perk perk) { return isMayorPerkActive(perk) || isMinisterPerkActive(perk); } - public static CompletableFuture> fetchCandidates() { - return SERVICE.handleRequest( - new GetCandidatesProtocolObject.GetCandidatesMessage() - ).thenApply(GetCandidatesProtocolObject.GetCandidatesResponse::candidates); + public static CompletableFuture> fetchCandidates() { + return SERVICE.handleRequest( + new GetCandidatesProtocol.GetCandidatesMessage() + ).thenApply(GetCandidatesProtocol.GetCandidatesResponse::candidates); } public static void checkElectionCycle() { @@ -228,13 +228,13 @@ private static void startTallyRefreshTask() { } private static void refreshTalliesAsync() { - SERVICE.handleRequest( - new GetCandidatesProtocolObject.GetCandidatesMessage() + SERVICE.handleRequest( + new GetCandidatesProtocol.GetCandidatesMessage() ).thenAccept(response -> { if (response.electionOpen()) { Map tallies = new HashMap<>(); - for (GetCandidatesProtocolObject.CandidateInfo info : response.candidates()) { + for (GetCandidatesProtocol.CandidateInfo info : response.candidates()) { tallies.put(info.mayorName(), info.votes()); } electionData.updateTallies(tallies); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java index f8e00c296..04ef2c121 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java @@ -27,6 +27,21 @@ public enum EnchantmentType { GIANT_KILLER(EnchantmentGiantKiller.class), EXECUTE(EnchantmentExecute.class), IMPALING(EnchantmentImpaling.class), + CASTER(EnchantmentCaster.class), + CHARM(EnchantmentCharm.class), + ANGLER(EnchantmentAngler.class), + BLESSING(EnchantmentBlessing.class), + CORRUPTION(EnchantmentCorruption.class), + EXPERTISE(EnchantmentExpertise.class), + FLASH(EnchantmentFlash.class), + FRAIL(EnchantmentFrail.class), + LUCK_OF_THE_SEA(EnchantmentLuckOfTheSea.class), + LURE(EnchantmentLure.class), + MAGNET(EnchantmentMagnet.class), + PISCARY(EnchantmentPiscary.class), + QUICK_BITE(EnchantmentQuickBite.class), + SPIKED_HOOK(EnchantmentSpikedHook.class), + TABASCO(EnchantmentTabasco.class), BANE_OF_ARTHROPODS(EnchantmentBaneOfArthropods.class), CUBISM(EnchantmentCubism.class), FORTUNE(EnchantmentFortune.class), diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentAngler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentAngler.java new file mode 100644 index 000000000..7b9fa0371 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentAngler.java @@ -0,0 +1,58 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentAngler implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §3+" + level + "% Sea Creature Chance§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.SEA_CREATURE_CHANCE, (double) level).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentBlessing.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentBlessing.java new file mode 100644 index 000000000..15f7600b1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentBlessing.java @@ -0,0 +1,51 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentBlessing implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §a+" + (level * 5) + "%§7 chance for a better §6Treasure§7 quality outcome."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCaster.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCaster.java new file mode 100644 index 000000000..57016d46b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCaster.java @@ -0,0 +1,51 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentCaster implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "§a" + (level * 5) + "%§7 chance to not consume bait."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 15, + 3, 20, + 4, 25, + 5, 30, + 6, 60 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD, EnchantItemGroups.FISHING_WEAPON); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 15, + 3, 20, + 4, 25, + 5, 30 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCharm.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCharm.java new file mode 100644 index 000000000..0e771ba22 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCharm.java @@ -0,0 +1,34 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentCharm implements Ench { + @Override + public String getDescription(int level) { + return "§7Increases the chance to receive higher-tiered Trophy Fish by §a" + (level * 2) + "%§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.ofEntries( + Map.entry(1, 10), + Map.entry(2, 20), + Map.entry(3, 30), + Map.entry(4, 40), + Map.entry(5, 50), + Map.entry(6, 100) + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCorruption.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCorruption.java new file mode 100644 index 000000000..ba7a17de2 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCorruption.java @@ -0,0 +1,50 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentCorruption implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "§a" + (level * 10) + "%§7 chance to summon a §5Corrupted §7variant of a caught §3Sea Creature§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 5, + 2, 10, + 3, 15, + 4, 20, + 5, 50 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 5, + 2, 10, + 3, 15, + 4, 20, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 10; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentExpertise.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentExpertise.java new file mode 100644 index 000000000..4a3bbd78a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentExpertise.java @@ -0,0 +1,52 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentExpertise implements Ench { + private static final double[] SEA_CREATURE_CHANCE_BONUS = { + 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0 + }; + + @Override + public String getDescription(int level) { + return "Tracks §3Sea Creature §7kills on this rod. Every kill grants §b+0.1☂ Fishing Wisdom§7. " + + "Current tier grants §3+" + SEA_CREATURE_CHANCE_BONUS[level - 1] + "% Sea Creature Chance§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder() + .withBase(ItemStatistic.SEA_CREATURE_CHANCE, SEA_CREATURE_CHANCE_BONUS[level - 1]) + .build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 50, + 2, 100, + 3, 200, + 4, 400, + 5, 800, + 6, 1600, + 7, 3200, + 8, 6400, + 9, 12800, + 10, 25600 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFlash.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFlash.java new file mode 100644 index 000000000..12e0d1ec6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFlash.java @@ -0,0 +1,57 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentFlash implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §b+" + (level * 5) + "☂ Fishing Speed§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.FISHING_SPEED, level * 5.0).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 60, + 5, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 60, + 5, 100 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFrail.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFrail.java new file mode 100644 index 000000000..aa9c437a8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFrail.java @@ -0,0 +1,52 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentFrail implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Reduces the defense of §3Sea Creatures §7you hit by §a" + (level * 10) + "%§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD, EnchantItemGroups.FISHING_WEAPON); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLuckOfTheSea.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLuckOfTheSea.java new file mode 100644 index 000000000..4ed33f8b0 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLuckOfTheSea.java @@ -0,0 +1,59 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentLuckOfTheSea implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §b+" + level + "✯ Magic Find§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.MAGIC_FIND, (double) level).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLure.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLure.java new file mode 100644 index 000000000..daaf8248e --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLure.java @@ -0,0 +1,58 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentLure implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §b+" + (level * 4) + "☂ Fishing Speed§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.FISHING_SPEED, level * 4.0).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentMagnet.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentMagnet.java new file mode 100644 index 000000000..ec27affd3 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentMagnet.java @@ -0,0 +1,51 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentMagnet implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Instantly pulls nearby items to you within §a" + (level * 2) + " §7blocks."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentPiscary.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentPiscary.java new file mode 100644 index 000000000..dd76b4ee5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentPiscary.java @@ -0,0 +1,59 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentPiscary implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §6+" + level + "% Trophy Fish Chance§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.TROPHY_FISH_CHANCE, (double) level).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentQuickBite.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentQuickBite.java new file mode 100644 index 000000000..d2331abb3 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentQuickBite.java @@ -0,0 +1,50 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentQuickBite implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Decreases the time for your hook to get a bite by §a" + (level * 5) + "%§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 60, + 4, 80, + 5, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 60, + 4, 80, + 5, 100 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 5; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentSpikedHook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentSpikedHook.java new file mode 100644 index 000000000..719ee96e8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentSpikedHook.java @@ -0,0 +1,52 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentSpikedHook implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Deals §a" + (level * 5) + "%§7 more damage to §3Sea Creatures§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD, EnchantItemGroups.FISHING_WEAPON); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentTabasco.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentTabasco.java new file mode 100644 index 000000000..2becbc3e5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentTabasco.java @@ -0,0 +1,53 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentTabasco implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §6+" + (level * 5) + "% Trophy Fish Chance §7while fishing in §clava§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.TROPHY_FISH_CHANCE, level * 5.0).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 80 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 80 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 15; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java new file mode 100644 index 000000000..0e0d48236 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java @@ -0,0 +1,340 @@ +package net.swofty.type.skyblockgeneric.entity; + +import lombok.Getter; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.metadata.other.FishingHookMeta; +import net.minestom.server.event.entity.EntityTickEvent; +import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; +import net.minestom.server.item.Material; +import net.minestom.server.network.packet.server.play.ParticlePacket; +import net.minestom.server.particle.Particle; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.timer.Scheduler; +import net.minestom.server.timer.Task; +import net.minestom.server.timer.TaskSchedule; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.FishingService; +import net.swofty.type.skyblockgeneric.fishing.FishingSession; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class FishingHook { + + public static final List activeHooks = new ArrayList<>(); + private static final double INITIAL_SPEED_MULTIPLIER = 10.0; + private static final double BOB_SPEED = 0.1; + private static final double BOB_AMOUNT = 0.09; + private static final double SURFACE_OFFSET = -0.02; + private static final double MAX_PULL_DOWN = 0.3; + private static final double PULL_DOWN_RECOVERY_SPEED = 0.016666666666666666; + private static final double CONTROLLER_DRAG = 0.2; + private static final double WATER_CHECK_OFFSET = -0.2; + private static final long BITE_WINDOW_TICKS = 20L; + private final SkyBlockPlayer owner; + private final SkyBlockItem rod; + private final FishingMedium requiredMedium; + private final Entity hook; + private final Entity controller; + @Getter + private boolean isRemoved = false; + private double bobTick = 0; + private double pullDownOffset = 0; + private Double stableWaterY = null; + private Task nextBiteTask; + private Task biteExpiryTask; + private boolean sessionStarted = false; + + public FishingHook(SkyBlockPlayer owner, SkyBlockItem rod) { + this.owner = owner; + this.rod = rod; + String itemId = rod.getAttributeHandler().getPotentialType() == null ? null : rod.getAttributeHandler().getPotentialType().name(); + var rodMetadata = FishingItemSupport.getRodMetadata(itemId); + this.requiredMedium = rodMetadata == null ? FishingMedium.WATER : rodMetadata.getMedium(); + + this.hook = new Entity(EntityType.FISHING_BOBBER); + this.hook.editEntityMeta(FishingHookMeta.class, meta -> { + meta.setOwnerEntity(owner); + }); + + this.controller = new Entity(EntityType.TEXT_DISPLAY); + this.controller.setNoGravity(true); + + this.controller.eventNode().addListener(EntityTickEvent.class, + event -> tick(event.getEntity())); + } + + public static FishingHook getFishingHookForOwner(@NotNull SkyBlockPlayer owner) { + for (FishingHook fishingHook : activeHooks) { + if (fishingHook.owner.getUuid().equals(owner.getUuid())) { + return fishingHook; + } + } + return null; + } + + private static boolean blockMatchesMedium(@NotNull Block block, @NotNull FishingMedium medium) { + if (!block.isLiquid()) { + return false; + } + String blockName = block.name(); + return switch (medium) { + case WATER -> blockName.contains("water"); + case LAVA -> blockName.contains("lava"); + }; + } + + public void spawn(Instance instance) { + Pos spawnPos = owner.getPosition().add(0, owner.getEyeHeight(), 0); + spawn(instance, spawnPos); + } + + public void spawn(Instance instance, Pos pos) { + activeHooks.add(this); + this.controller.setInstance(instance, pos); + this.hook.setInstance(instance, pos); + this.controller.addPassenger(hook); + this.controller.setVelocity(owner.getPosition().direction().mul(INITIAL_SPEED_MULTIPLIER)); + float pitch = (float) 1/3 + (float) (Math.random() * (0.5 - 1.0 / 3.0)); + owner.playSound( + Sound.sound() + .type(Key.key("entity.fishing_bobber.throw")) + .source(Sound.Source.NEUTRAL) + .volume(0.5f) + .pitch(pitch) + .build() + ); + } + + private boolean shouldKeepExisting() { + // Checks if the user is still in the same instance as the hook + Instance instance = controller.getInstance(); + if (instance == null) return false; + if (owner.getInstance() != instance) return false; + // Checks if the owner is still holding a fishing rod + return owner.getItemInMainHand().material() == Material.FISHING_ROD; + } + + private void tick(@NotNull Entity controller) { + Instance instance = controller.getInstance(); + if (instance == null) return; + if (!shouldKeepExisting()) { + remove(); + return; + } + + Pos pos = controller.getPosition(); + if (notInWater()) { + stableWaterY = null; + controller.setNoGravity(false); // Re-enable gravity to fall/stop + return; + } + + FishingMedium mediumAtHook = getCurrentMedium(); + if (mediumAtHook == null) { + if (sessionStarted) { + FishingService.clearSession(owner.getUuid()); + sessionStarted = false; + } + stableWaterY = null; + cancelBiteTasks(); + controller.setNoGravity(false); + return; + } + + if (mediumAtHook != requiredMedium) { + remove(); + return; + } + + // Hook is in valid fishing liquid + controller.setNoGravity(true); + Block blockBelow = instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0)); + + if (stableWaterY == null) { + // First time hitting water, establish stable surface Y + stableWaterY = getWaterSurface(blockBelow, (int) Math.floor(pos.y() + WATER_CHECK_OFFSET)) + SURFACE_OFFSET; + bobTick = 0; + pullDownOffset = 0; + // show particles + instance.playSound(Sound.sound() + .type(SoundEvent.ENTITY_FISHING_BOBBER_SPLASH) + .source(Sound.Source.PLAYER) + .volume(0.25f) + .pitch(0.8f) // 0.6-1.4 in vanilla + .build() + ); + instance.sendGroupedPacket(new ParticlePacket( + Particle.SPLASH, + controller.getPosition(), + new Pos(0.1, 0.001, 0.1), + 0, 5 + )); + startFishingSession(); + } + + bobTick += BOB_SPEED; + double yBob = Math.sin(bobTick) * BOB_AMOUNT; + + pullDownOffset = Math.max(pullDownOffset - PULL_DOWN_RECOVERY_SPEED, 0); + Pos targetPos = new Pos(pos.x(), stableWaterY + yBob - pullDownOffset, pos.z()); + + controller.teleport(targetPos); + controller.setVelocity(controller.getVelocity().mul(CONTROLLER_DRAG)); + } + + + public boolean notInWater() { + Instance instance = controller.getInstance(); + Pos pos = controller.getPosition(); + return getMedium(instance.getBlock(pos)) == null + && getMedium(instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0))) == null; + } + + public void showBiteAnimation() { + Instance instance = controller.getInstance(); + if (instance == null) return; + + instance.playSound(Sound.sound() + .type(SoundEvent.ENTITY_FISHING_BOBBER_SPLASH) + .source(Sound.Source.PLAYER) + .build() + ); + instance.sendGroupedPacket(new ParticlePacket( + Particle.SPLASH, + controller.getPosition(), + new Pos(0.1, 0.001, 0.1), + 0, 20 + )); + + pullDownOffset = Math.min(pullDownOffset + 0.15, MAX_PULL_DOWN); + bobTick += Math.PI / 6; + } + + public void remove() { + activeHooks.remove(this); + if (this.isRemoved) return; + this.isRemoved = true; + cancelBiteTasks(); + FishingService.clearSession(owner.getUuid()); + hook.remove(); + controller.remove(); + } + + public void tryRetrieve(SkyBlockItem rodInHand) { + FishingSession session = FishingService.getSession(owner.getUuid()); + if (session == null || !session.biteReady() || System.currentTimeMillis() > session.biteWindowEndsAt()) { + return; + } + + FishingService.resolveCatch(owner, rodInHand, this); + } + + private double getWaterSurface(Block block, int blockY) { + if (!block.isLiquid()) return blockY + 1.0; + + String levelStr = block.getProperty("level"); + int level = (levelStr == null) ? 0 : Integer.parseInt(levelStr); + + return blockY + ((level == 0) ? 1.0 : (8 - level) / 8.0); + } + + public Scheduler getScheduler() { + return hook.scheduler(); + } + + public Instance getInstance() { + return controller.getInstance(); + } + + public Pos getSpawnPosition() { + return controller.getPosition(); + } + + private void startFishingSession() { + if (sessionStarted) { + return; + } + + FishingSession session = FishingService.beginCast(owner, rod, requiredMedium); + sessionStarted = true; + FishingBaitComponent bait = FishingItemSupport.getBait(session.baitItemId()); + long waitTicks = FishingService.computeWaitTicks(owner, rod, bait); + scheduleNextBite(waitTicks); + } + + private void scheduleNextBite(long delayTicks) { + cancelBiteTasks(); + nextBiteTask = hook.scheduler().buildTask(() -> { + if (isRemoved || notInWater()) { + return; + } + + FishingSession session = FishingService.getSession(owner.getUuid()); + if (session == null || session.resolved()) { + return; + } + + long now = System.currentTimeMillis(); + FishingService.updateSession(session.withBiteTiming(now, now + (BITE_WINDOW_TICKS * 50)).withBiteReady(true)); + showBiteAnimation(); + + biteExpiryTask = hook.scheduler().buildTask(() -> { + FishingSession activeSession = FishingService.getSession(owner.getUuid()); + if (activeSession == null || activeSession.resolved() || isRemoved) { + return; + } + + FishingService.updateSession(activeSession.withBiteReady(false)); + FishingBaitComponent bait = FishingItemSupport.getBait(activeSession.baitItemId()); + long nextDelay = FishingService.computeWaitTicks(owner, rod, bait); + scheduleNextBite(nextDelay); + }).delay(TaskSchedule.tick((int) BITE_WINDOW_TICKS)).schedule(); + }).delay(TaskSchedule.tick((int) delayTicks)).schedule(); + } + + private void cancelBiteTasks() { + if (nextBiteTask != null) { + nextBiteTask.cancel(); + nextBiteTask = null; + } + if (biteExpiryTask != null) { + biteExpiryTask.cancel(); + biteExpiryTask = null; + } + } + + private FishingMedium getCurrentMedium() { + Instance instance = controller.getInstance(); + if (instance == null) { + return null; + } + + Pos pos = controller.getPosition(); + FishingMedium current = getMedium(instance.getBlock(pos)); + if (current != null) { + return current; + } + return getMedium(instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0))); + } + + private FishingMedium getMedium(Block block) { + if (blockMatchesMedium(block, FishingMedium.WATER)) { + return FishingMedium.WATER; + } + if (blockMatchesMedium(block, FishingMedium.LAVA)) { + return FishingMedium.LAVA; + } + return null; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/MinionEntityImpl.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/MinionEntityImpl.java index c526851b7..0b1f21e79 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/MinionEntityImpl.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/MinionEntityImpl.java @@ -76,8 +76,9 @@ public void updateMinionDisplay(IslandMinionData.IslandMinion updatedMinion) { try { setItemInMainHand(ItemStack.builder(minionTier.heldItem()).build()); - } catch (Exception e) {} - // TODO: Fix this, I have no clue why it stopped working + } catch (Exception e) { + org.tinylog.Logger.warn(e, "Failed to set held item for minion tier {}", minionTier); + } } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureBehaviour.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureBehaviour.java new file mode 100644 index 000000000..e06c304b7 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureBehaviour.java @@ -0,0 +1,82 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.seacreature; + +import java.util.List; +import net.minestom.server.entity.ai.GoalSelector; +import net.minestom.server.entity.ai.TargetSelector; +import net.minestom.server.entity.ai.goal.MeleeAttackGoal; +import net.minestom.server.entity.ai.goal.RandomStrollGoal; +import net.minestom.server.entity.ai.target.ClosestEntityTarget; +import net.minestom.server.entity.ai.target.LastEntityDamagerTarget; +import net.minestom.server.utils.time.TimeUnit; +import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +/** + * Strategy describing how a sea creature moves and selects targets. The + * sealed hierarchy is exhaustive — pattern-match on it elsewhere if you + * need to introspect (e.g. catalog GUIs that render "aggressive" vs + * "passive" differently). + */ +public sealed interface SeaCreatureBehaviour + permits SeaCreatureBehaviour.Passive, + SeaCreatureBehaviour.Aggressive, + SeaCreatureBehaviour.Custom { + + List goals(SkyBlockMob self); + + List targets(SkyBlockMob self); + + static Passive passive(int strollRange) { + return new Passive(strollRange); + } + + static Aggressive aggressive(double speed, int attackCooldownTicks, int aggroRange) { + return new Aggressive(speed, attackCooldownTicks, aggroRange); + } + + static Custom of(List goals, List targets) { + return new Custom(goals, targets); + } + + record Passive(int strollRange) implements SeaCreatureBehaviour { + @Override + public List goals(SkyBlockMob self) { + return List.of(new RandomStrollGoal(self, strollRange)); + } + + @Override + public List targets(SkyBlockMob self) { + return List.of(); + } + } + + record Aggressive(double speed, int attackCooldownTicks, int aggroRange) implements SeaCreatureBehaviour { + @Override + public List goals(SkyBlockMob self) { + return List.of( + new MeleeAttackGoal(self, speed, attackCooldownTicks, TimeUnit.SERVER_TICK), + new RandomStrollGoal(self, Math.max(8, aggroRange / 2)) + ); + } + + @Override + public List targets(SkyBlockMob self) { + return List.of( + new LastEntityDamagerTarget(self, aggroRange), + new ClosestEntityTarget(self, aggroRange, entity -> entity instanceof SkyBlockPlayer) + ); + } + } + + record Custom(List customGoals, List customTargets) implements SeaCreatureBehaviour { + @Override + public List goals(SkyBlockMob self) { + return customGoals; + } + + @Override + public List targets(SkyBlockMob self) { + return customTargets; + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureMob.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureMob.java new file mode 100644 index 000000000..1bbc864ed --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureMob.java @@ -0,0 +1,73 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.seacreature; + +import java.util.List; +import net.minestom.server.entity.ai.GoalSelector; +import net.minestom.server.entity.ai.TargetSelector; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; +import net.swofty.type.skyblockgeneric.loottable.OtherLoot; +import net.swofty.type.skyblockgeneric.loottable.SkyBlockLootTable; +import net.swofty.type.skyblockgeneric.skill.SkillCategories; +import org.jetbrains.annotations.Nullable; + +/** + * A sea creature is fully described by a {@link SeaCreatureProfile} — one + * concrete class drives every variant. The thread-local handoff + * ({@link #IN_CONSTRUCTION}) is the standard workaround for SkyBlockMob's + * super-constructor calling abstract accessors before subclass field + * assignment happens; without it those accessors would NPE on the profile + * field. Once super() returns the field is set and future calls hit the + * fast path. + */ +public final class SeaCreatureMob extends SkyBlockMob { + + private static final ThreadLocal IN_CONSTRUCTION = new ThreadLocal<>(); + + private final SeaCreatureProfile profile; + + private SeaCreatureMob(SeaCreatureProfile profile) { + super(profile.entityType()); + this.profile = profile; + } + + public static SeaCreatureMob create(SeaCreatureProfile profile) { + IN_CONSTRUCTION.set(profile); + try { + return new SeaCreatureMob(profile); + } finally { + IN_CONSTRUCTION.remove(); + } + } + + public String getSeaCreatureId() { + return live().id(); + } + + public SeaCreatureProfile getProfile() { + return live(); + } + + @Override public String getDisplayName() { return live().displayName(); } + @Override public Integer getLevel() { return live().level(); } + @Override public List getMobTypes() { return live().mobTypes(); } + @Override public ItemStatistics getBaseStatistics() { return live().asBaseStatistics(); } + @Override public OtherLoot getOtherLoot() { return live().asOtherLoot(); } + @Override public long damageCooldown() { return live().damageCooldownMs(); } + @Override public @Nullable SkyBlockLootTable getLootTable() { return live().lootTable(); } + @Override public SkillCategories getSkillCategory() { return SkillCategories.FISHING; } + + @Override + public List getGoalSelectors() { + return live().behaviour().goals(this); + } + + @Override + public List getTargetSelectors() { + return live().behaviour().targets(this); + } + + private SeaCreatureProfile live() { + return profile != null ? profile : IN_CONSTRUCTION.get(); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureProfile.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureProfile.java new file mode 100644 index 000000000..57df50113 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureProfile.java @@ -0,0 +1,90 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.seacreature; + +import java.util.List; +import net.minestom.server.entity.EntityType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.loottable.OtherLoot; +import net.swofty.type.skyblockgeneric.loottable.SkyBlockLootTable; + +/** + * Immutable, declarative description of a sea creature. The concrete mob + * class just hands one of these to {@link SeaCreatureMob} and the base + * class does the rest — no abstract-method ceremony, no per-creature + * duplicated builder boilerplate. + */ +public record SeaCreatureProfile( + String id, + String displayName, + int level, + EntityType entityType, + double health, + double damage, + double speed, + long damageCooldownMs, + long fishingXpReward, + int xpOrbs, + List mobTypes, + SeaCreatureBehaviour behaviour, + SkyBlockLootTable lootTable +) { + + public ItemStatistics asBaseStatistics() { + return ItemStatistics.builder() + .withBase(ItemStatistic.HEALTH, health) + .withBase(ItemStatistic.DAMAGE, damage) + .withBase(ItemStatistic.SPEED, speed) + .build(); + } + + public OtherLoot asOtherLoot() { + return new OtherLoot(fishingXpReward, 0, xpOrbs); + } + + public static Builder builder(String id) { + return new Builder(id); + } + + public static final class Builder { + private final String id; + private String displayName; + private int level = 1; + private EntityType entityType = EntityType.SQUID; + private double health = 100D; + private double damage = 0D; + private double speed = 30D; + private long damageCooldownMs = 500L; + private long fishingXpReward = 0L; + private int xpOrbs = 0; + private List mobTypes = List.of(MobType.AQUATIC); + private SeaCreatureBehaviour behaviour = SeaCreatureBehaviour.passive(8); + private SkyBlockLootTable lootTable = null; + + private Builder(String id) { + this.id = id; + this.displayName = id; + } + + public Builder displayName(String displayName) { this.displayName = displayName; return this; } + public Builder level(int level) { this.level = level; return this; } + public Builder entityType(EntityType entityType) { this.entityType = entityType; return this; } + public Builder health(double health) { this.health = health; return this; } + public Builder damage(double damage) { this.damage = damage; return this; } + public Builder speed(double speed) { this.speed = speed; return this; } + public Builder damageCooldownMs(long damageCooldownMs) { this.damageCooldownMs = damageCooldownMs; return this; } + public Builder fishingXpReward(long fishingXpReward) { this.fishingXpReward = fishingXpReward; return this; } + public Builder xpOrbs(int xpOrbs) { this.xpOrbs = xpOrbs; return this; } + public Builder mobTypes(MobType... mobTypes) { this.mobTypes = List.of(mobTypes); return this; } + public Builder behaviour(SeaCreatureBehaviour behaviour) { this.behaviour = behaviour; return this; } + public Builder lootTable(SkyBlockLootTable lootTable) { this.lootTable = lootTable; return this; } + + public SeaCreatureProfile build() { + return new SeaCreatureProfile( + id, displayName, level, entityType, + health, damage, speed, damageCooldownMs, + fishingXpReward, xpOrbs, mobTypes, behaviour, lootTable + ); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureProfiles.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureProfiles.java new file mode 100644 index 000000000..250a09241 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureProfiles.java @@ -0,0 +1,260 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.seacreature; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; +import net.minestom.server.entity.EntityType; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; + +/** + * Canonical Hypixel sea creature profiles. Each constant is the entire + * declarative spec for one creature: stats, AI flavour, fishing rewards. + * Adding a new creature is one builder chain, not a new class. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SeaCreatureProfiles { + + /* ---------- water ---------- */ + + public static final SeaCreatureProfile SQUID = SeaCreatureProfile.builder("SQUID") + .displayName("Squid") + .level(1) + .entityType(EntityType.SQUID) + .health(145D).damage(5D).speed(30D) + .behaviour(SeaCreatureBehaviour.passive(8)) + .mobTypes(MobType.AQUATIC) + .fishingXpReward(20).xpOrbs(4) + .build(); + + public static final SeaCreatureProfile SEA_WALKER = SeaCreatureProfile.builder("SEA_WALKER") + .displayName("Sea Walker") + .level(4) + .entityType(EntityType.ZOMBIE) + .health(240D).damage(25D).speed(70D) + .behaviour(SeaCreatureBehaviour.aggressive(1.6, 20, 16)) + .mobTypes(MobType.AQUATIC, MobType.UNDEAD) + .damageCooldownMs(400) + .fishingXpReward(40).xpOrbs(6) + .build(); + + public static final SeaCreatureProfile NIGHT_SQUID = SeaCreatureProfile.builder("NIGHT_SQUID") + .displayName("Night Squid") + .level(6) + .entityType(EntityType.GLOW_SQUID) + .health(400D).damage(15D).speed(30D) + .behaviour(SeaCreatureBehaviour.passive(6)) + .mobTypes(MobType.AQUATIC) + .fishingXpReward(80).xpOrbs(8) + .build(); + + public static final SeaCreatureProfile SEA_GUARDIAN = SeaCreatureProfile.builder("SEA_GUARDIAN") + .displayName("Sea Guardian") + .level(8) + .entityType(EntityType.GUARDIAN) + .health(600D).damage(40D).speed(60D) + .behaviour(SeaCreatureBehaviour.aggressive(2.0, 25, 18)) + .mobTypes(MobType.AQUATIC) + .damageCooldownMs(400) + .fishingXpReward(120).xpOrbs(10) + .build(); + + public static final SeaCreatureProfile SEA_WITCH = SeaCreatureProfile.builder("SEA_WITCH") + .displayName("Sea Witch") + .level(10) + .entityType(EntityType.WITCH) + .health(800D).damage(60D).speed(60D) + .behaviour(SeaCreatureBehaviour.aggressive(1.5, 30, 16)) + .mobTypes(MobType.AQUATIC, MobType.ARCANE) + .damageCooldownMs(450) + .fishingXpReward(150).xpOrbs(12) + .build(); + + public static final SeaCreatureProfile SEA_ARCHER = SeaCreatureProfile.builder("SEA_ARCHER") + .displayName("Sea Archer") + .level(15) + .entityType(EntityType.SKELETON) + .health(1000D).damage(80D).speed(75D) + .behaviour(SeaCreatureBehaviour.aggressive(1.7, 25, 20)) + .mobTypes(MobType.AQUATIC, MobType.SKELETAL) + .damageCooldownMs(400) + .fishingXpReward(200).xpOrbs(14) + .build(); + + public static final SeaCreatureProfile MONSTER_OF_THE_DEEP = SeaCreatureProfile.builder("MONSTER_OF_THE_DEEP") + .displayName("Monster of the Deep") + .level(20) + .entityType(EntityType.DROWNED) + .health(1500D).damage(120D).speed(80D) + .behaviour(SeaCreatureBehaviour.aggressive(2.0, 22, 20)) + .mobTypes(MobType.AQUATIC, MobType.UNDEAD) + .damageCooldownMs(400) + .fishingXpReward(300).xpOrbs(16) + .build(); + + public static final SeaCreatureProfile CATFISH = SeaCreatureProfile.builder("CATFISH") + .displayName("Catfish") + .level(24) + .entityType(EntityType.OCELOT) + .health(2000D).damage(150D).speed(90D) + .behaviour(SeaCreatureBehaviour.aggressive(2.2, 18, 18)) + .mobTypes(MobType.AQUATIC, MobType.ANIMAL) + .damageCooldownMs(350) + .fishingXpReward(400).xpOrbs(18) + .build(); + + public static final SeaCreatureProfile CARROT_KING = SeaCreatureProfile.builder("CARROT_KING") + .displayName("Carrot King") + .level(26) + .entityType(EntityType.RABBIT) + .health(2500D).damage(170D).speed(95D) + .behaviour(SeaCreatureBehaviour.aggressive(2.0, 25, 16)) + .mobTypes(MobType.AQUATIC, MobType.ANIMAL) + .damageCooldownMs(400) + .fishingXpReward(500).xpOrbs(20) + .build(); + + public static final SeaCreatureProfile SEA_LEECH = SeaCreatureProfile.builder("SEA_LEECH") + .displayName("Sea Leech") + .level(30) + .entityType(EntityType.SILVERFISH) + .health(3000D).damage(200D).speed(110D) + .behaviour(SeaCreatureBehaviour.aggressive(2.4, 18, 14)) + .mobTypes(MobType.AQUATIC, MobType.ARTHROPOD) + .damageCooldownMs(350) + .fishingXpReward(650).xpOrbs(22) + .build(); + + public static final SeaCreatureProfile GUARDIAN_DEFENDER = SeaCreatureProfile.builder("GUARDIAN_DEFENDER") + .displayName("Guardian Defender") + .level(35) + .entityType(EntityType.GUARDIAN) + .health(5000D).damage(250D).speed(70D) + .behaviour(SeaCreatureBehaviour.aggressive(1.8, 30, 20)) + .mobTypes(MobType.AQUATIC, MobType.SHIELDED) + .damageCooldownMs(450) + .fishingXpReward(900).xpOrbs(26) + .build(); + + public static final SeaCreatureProfile WATER_HYDRA = SeaCreatureProfile.builder("WATER_HYDRA") + .displayName("Water Hydra") + .level(60) + .entityType(EntityType.WITHER) + .health(50000D).damage(800D).speed(80D) + .behaviour(SeaCreatureBehaviour.aggressive(2.5, 20, 28)) + .mobTypes(MobType.AQUATIC, MobType.ELUSIVE) + .damageCooldownMs(300) + .fishingXpReward(7500).xpOrbs(60) + .build(); + + public static final SeaCreatureProfile THE_SEA_EMPEROR = SeaCreatureProfile.builder("THE_SEA_EMPEROR") + .displayName("The Sea Emperor") + .level(80) + .entityType(EntityType.ELDER_GUARDIAN) + .health(150000D).damage(1500D).speed(60D) + .behaviour(SeaCreatureBehaviour.aggressive(2.0, 30, 32)) + .mobTypes(MobType.AQUATIC, MobType.MYTHOLOGICAL, MobType.ELUSIVE) + .damageCooldownMs(400) + .fishingXpReward(20000).xpOrbs(120) + .build(); + + /* ---------- lava (Crimson Isle) ---------- */ + + public static final SeaCreatureProfile MAGMA_SLUG = SeaCreatureProfile.builder("MAGMA_SLUG") + .displayName("Magma Slug") + .level(21) + .entityType(EntityType.MAGMA_CUBE) + .health(850D).damage(170D).speed(50D) + .behaviour(SeaCreatureBehaviour.aggressive(1.6, 20, 14)) + .mobTypes(MobType.MAGMATIC, MobType.CUBIC) + .damageCooldownMs(400) + .fishingXpReward(450).xpOrbs(12) + .build(); + + public static final SeaCreatureProfile MOOGMA = SeaCreatureProfile.builder("MOOGMA") + .displayName("Moogma") + .level(22) + .entityType(EntityType.STRIDER) + .health(900D).damage(180D).speed(75D) + .behaviour(SeaCreatureBehaviour.aggressive(1.8, 22, 16)) + .mobTypes(MobType.MAGMATIC, MobType.ANIMAL) + .damageCooldownMs(400) + .fishingXpReward(500).xpOrbs(14) + .build(); + + public static final SeaCreatureProfile LAVA_LEECH = SeaCreatureProfile.builder("LAVA_LEECH") + .displayName("Lava Leech") + .level(24) + .entityType(EntityType.SILVERFISH) + .health(1100D).damage(200D).speed(100D) + .behaviour(SeaCreatureBehaviour.aggressive(2.4, 18, 14)) + .mobTypes(MobType.MAGMATIC, MobType.ARTHROPOD) + .damageCooldownMs(350) + .fishingXpReward(550).xpOrbs(14) + .build(); + + public static final SeaCreatureProfile PYROCLASTIC_WORM = SeaCreatureProfile.builder("PYROCLASTIC_WORM") + .displayName("Pyroclastic Worm") + .level(28) + .entityType(EntityType.ENDERMITE) + .health(1400D).damage(240D).speed(95D) + .behaviour(SeaCreatureBehaviour.aggressive(2.2, 18, 16)) + .mobTypes(MobType.MAGMATIC, MobType.ARTHROPOD) + .damageCooldownMs(350) + .fishingXpReward(800).xpOrbs(16) + .build(); + + public static final SeaCreatureProfile FIRE_EEL = SeaCreatureProfile.builder("FIRE_EEL") + .displayName("Fire Eel") + .level(28) + .entityType(EntityType.PHANTOM) + .health(1300D).damage(220D).speed(100D) + .behaviour(SeaCreatureBehaviour.aggressive(2.5, 18, 18)) + .mobTypes(MobType.MAGMATIC, MobType.AIRBORNE) + .damageCooldownMs(350) + .fishingXpReward(800).xpOrbs(16) + .build(); + + public static final SeaCreatureProfile LAVA_BLAZE = SeaCreatureProfile.builder("LAVA_BLAZE") + .displayName("Lava Blaze") + .level(30) + .entityType(EntityType.BLAZE) + .health(1500D).damage(250D).speed(90D) + .behaviour(SeaCreatureBehaviour.aggressive(2.5, 20, 20)) + .mobTypes(MobType.MAGMATIC) + .damageCooldownMs(350) + .fishingXpReward(1000).xpOrbs(18) + .build(); + + public static final SeaCreatureProfile TAURUS = SeaCreatureProfile.builder("TAURUS") + .displayName("Taurus") + .level(36) + .entityType(EntityType.HOGLIN) + .health(6000D).damage(400D).speed(85D) + .behaviour(SeaCreatureBehaviour.aggressive(2.4, 22, 22)) + .mobTypes(MobType.MAGMATIC, MobType.ANIMAL) + .damageCooldownMs(400) + .fishingXpReward(2500).xpOrbs(32) + .build(); + + public static final SeaCreatureProfile LORD_JAWBUS = SeaCreatureProfile.builder("LORD_JAWBUS") + .displayName("Lord Jawbus") + .level(45) + .entityType(EntityType.GHAST) + .health(40000D).damage(900D).speed(70D) + .behaviour(SeaCreatureBehaviour.aggressive(2.0, 25, 30)) + .mobTypes(MobType.MAGMATIC, MobType.INFERNAL, MobType.ELUSIVE) + .damageCooldownMs(350) + .fishingXpReward(15000).xpOrbs(80) + .build(); + + public static final List CANONICAL = List.of( + // Water + SQUID, SEA_WALKER, NIGHT_SQUID, SEA_GUARDIAN, + SEA_WITCH, SEA_ARCHER, MONSTER_OF_THE_DEEP, CATFISH, CARROT_KING, + SEA_LEECH, GUARDIAN_DEFENDER, WATER_HYDRA, THE_SEA_EMPEROR, + // Lava + MAGMA_SLUG, MOOGMA, LAVA_LEECH, PYROCLASTIC_WORM, FIRE_EEL, + LAVA_BLAZE, TAURUS, LORD_JAWBUS + ); +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureSpawner.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureSpawner.java new file mode 100644 index 000000000..1d51b0a50 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/seacreature/SeaCreatureSpawner.java @@ -0,0 +1,66 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.seacreature; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.LinkedHashMap; +import java.util.Map; +import net.kyori.adventure.text.Component; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.instance.Instance; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SeaCreatureSpawner { + + private static final Map PROFILES = new LinkedHashMap<>(); + + static { + SeaCreatureProfiles.CANONICAL.forEach(SeaCreatureSpawner::register); + } + + public static void register(SeaCreatureProfile profile) { + PROFILES.put(profile.id(), profile); + } + + public static boolean canSpawn(String seaCreatureId) { + return PROFILES.containsKey(seaCreatureId); + } + + public static @Nullable SeaCreatureProfile getProfile(String seaCreatureId) { + return PROFILES.get(seaCreatureId); + } + + public static @Nullable SeaCreatureMob spawn(SkyBlockPlayer angler, String seaCreatureId, Pos position) { + SeaCreatureProfile profile = PROFILES.get(seaCreatureId); + if (profile == null) { + Logger.warn("No sea creature profile registered for id={}, no spawn will occur", seaCreatureId); + return null; + } + + Instance instance = angler.getInstance(); + if (instance == null) { + return null; + } + + SeaCreatureMob mob = SeaCreatureMob.create(profile); + mob.setInstance(instance, position); + + broadcastCatch(angler, profile, instance, position); + return mob; + } + + private static void broadcastCatch(SkyBlockPlayer angler, SeaCreatureProfile profile, Instance instance, Pos position) { + Component selfMessage = Component.text("§3§lSEA CREATURE! §bA " + profile.displayName().toUpperCase() + " has spawned!"); + angler.sendMessage(selfMessage); + + Component nearbyMessage = Component.text("§3§lSEA CREATURE! §b" + angler.getUsername() + + " caught §a" + profile.displayName() + "§b!"); + instance.getPlayers().stream() + .filter(player -> player.getPosition().distance(position) <= 32) + .filter(player -> !player.getUuid().equals(angler.getUuid())) + .forEach(player -> player.sendMessage(nearbyMessage)); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossBehaviour.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossBehaviour.java new file mode 100644 index 000000000..15bb33cce --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossBehaviour.java @@ -0,0 +1,31 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer; + +import java.util.List; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.minestom.server.entity.ai.GoalSelector; +import net.minestom.server.entity.ai.TargetSelector; +import net.minestom.server.entity.ai.goal.MeleeAttackGoal; +import net.minestom.server.entity.ai.goal.RandomStrollGoal; +import net.minestom.server.entity.ai.target.ClosestEntityTarget; +import net.minestom.server.entity.ai.target.LastEntityDamagerTarget; +import net.minestom.server.utils.time.TimeUnit; +import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SlayerBossBehaviour { + public static List goals(SkyBlockMob self) { + return List.of( + new MeleeAttackGoal(self, 1.8, 16, TimeUnit.SERVER_TICK), + new RandomStrollGoal(self, 12) + ); + } + + public static List targets(SkyBlockMob self) { + return List.of( + new LastEntityDamagerTarget(self, 24), + new ClosestEntityTarget(self, 24, entity -> entity instanceof SkyBlockPlayer) + ); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossMob.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossMob.java new file mode 100644 index 000000000..d39c7b2f2 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossMob.java @@ -0,0 +1,110 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer; + +import java.util.List; +import java.util.UUID; +import net.minestom.server.entity.ai.GoalSelector; +import net.minestom.server.entity.ai.TargetSelector; +import net.minestom.server.entity.damage.Damage; +import net.minestom.server.timer.Task; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability.SlayerBossAbility; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability.SlayerBossAbilityFactory; +import net.swofty.type.skyblockgeneric.loottable.OtherLoot; +import net.swofty.type.skyblockgeneric.loottable.SkyBlockLootTable; +import net.swofty.type.skyblockgeneric.skill.SkillCategories; +import org.jetbrains.annotations.Nullable; + +public final class SlayerBossMob extends SkyBlockMob { + private static final ThreadLocal IN_CONSTRUCTION = new ThreadLocal<>(); + + private final SlayerBossProfile profile; + private final UUID ownerUuid; + private final SlayerBossAbility ability; + private final List abilityTasks = new java.util.concurrent.CopyOnWriteArrayList<>(); + + private SlayerBossMob(UUID ownerUuid, SlayerBossProfile profile) { + super(profile.entityType()); + this.ownerUuid = ownerUuid; + this.profile = profile; + this.ability = SlayerBossAbilityFactory.create(profile.type()); + } + + public static SlayerBossMob create(UUID ownerUuid, SlayerBossProfile profile) { + IN_CONSTRUCTION.set(profile); + try { + return new SlayerBossMob(ownerUuid, profile); + } finally { + IN_CONSTRUCTION.remove(); + } + } + + public UUID getOwnerUuid() { + return ownerUuid; + } + + public SlayerBossProfile getProfile() { + return live(); + } + + public SlayerBossAbility getAbility() { + return ability; + } + + public void trackAbilityTask(Task task) { + abilityTasks.add(task); + } + + @Override public String getDisplayName() { return live().displayName(); } + @Override public Integer getLevel() { return live().tier().bossLevel(); } + @Override public List getMobTypes() { return live().mobTypes(); } + @Override public ItemStatistics getBaseStatistics() { return live().asBaseStatistics(); } + @Override public OtherLoot getOtherLoot() { return live().asOtherLoot(); } + @Override public long damageCooldown() { return 500L; } + @Override public @Nullable SkyBlockLootTable getLootTable() { return live().asLootTable(); } + @Override public SkillCategories getSkillCategory() { return SkillCategories.COMBAT; } + + @Override + public List getGoalSelectors() { + return SlayerBossBehaviour.goals(this); + } + + @Override + public List getTargetSelectors() { + return SlayerBossBehaviour.targets(this); + } + + @Override + public void onSpawn() { + ability.onSpawn(this); + } + + @Override + public boolean damage(@org.jetbrains.annotations.NotNull Damage damage) { + float amount = damage.getAmount(); + float modified = ability.modifyIncomingDamage(this, damage, amount); + if (modified <= 0F) { + return false; + } + + Damage applied = modified == amount + ? damage + : new Damage(damage.getType(), damage.getSource(), damage.getAttacker(), damage.getSourcePosition(), modified); + boolean result = super.damage(applied); + ability.onDamaged(this, applied, modified); + return result; + } + + @Override + public void kill() { + ability.onDeath(this); + abilityTasks.forEach(Task::cancel); + abilityTasks.clear(); + super.kill(); + } + + private SlayerBossProfile live() { + return profile != null ? profile : IN_CONSTRUCTION.get(); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossProfile.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossProfile.java new file mode 100644 index 000000000..59a828f7d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerBossProfile.java @@ -0,0 +1,59 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer; + +import java.util.List; +import java.util.Optional; +import net.minestom.server.entity.EntityType; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.loottable.OtherLoot; +import net.swofty.type.skyblockgeneric.loottable.SkyBlockLootTable; +import net.swofty.type.skyblockgeneric.slayer.SlayerTierDefinition; +import net.swofty.type.skyblockgeneric.slayer.SlayerType; + +public record SlayerBossProfile( + SlayerType type, + SlayerTierDefinition tier, + List mobTypes, + EntityType entityType +) { + public String id() { + return type.name() + "_" + tier.tier().name(); + } + + public String displayName() { + return type.displayName() + " " + tier.tier().numeral(); + } + + public ItemStatistics asBaseStatistics() { + return ItemStatistics.builder() + .withBase(ItemStatistic.HEALTH, tier.bossHealth()) + .withBase(ItemStatistic.DAMAGE, tier.bossDamage()) + .withBase(ItemStatistic.SPEED, tier.bossSpeed()) + .build(); + } + + public OtherLoot asOtherLoot() { + return new OtherLoot(tier.requiredCombatXp(), 0, Math.max(1, tier.slayerXp() / 5)); + } + + public SkyBlockLootTable asLootTable() { + Optional item = tier.tokenItem(); + if (item.isEmpty() || tier.tokenDrops() <= 0) { + return null; + } + + return new SkyBlockLootTable() { + @Override + public List getLootTable() { + return List.of(new LootRecord(item.get(), tier.tokenDrops(), 100)); + } + + @Override + public CalculationMode getCalculationMode() { + return CalculationMode.CALCULATE_INDIVIDUAL; + } + }; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerMinionMob.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerMinionMob.java new file mode 100644 index 000000000..c086b03d8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/SlayerMinionMob.java @@ -0,0 +1,83 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer; + +import java.util.List; +import java.util.UUID; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.ai.GoalSelector; +import net.minestom.server.entity.ai.TargetSelector; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; +import net.swofty.type.skyblockgeneric.loottable.OtherLoot; +import net.swofty.type.skyblockgeneric.loottable.SkyBlockLootTable; +import net.swofty.type.skyblockgeneric.skill.SkillCategories; +import org.jetbrains.annotations.Nullable; + +public final class SlayerMinionMob extends SkyBlockMob { + private static final ThreadLocal IN_CONSTRUCTION = new ThreadLocal<>(); + + private final SlayerMinionProfile profile; + private final UUID ownerUuid; + + private SlayerMinionMob(UUID ownerUuid, SlayerMinionProfile profile) { + super(profile.entityType()); + this.ownerUuid = ownerUuid; + this.profile = profile; + } + + public static SlayerMinionMob create(UUID ownerUuid, SlayerMinionProfile profile) { + IN_CONSTRUCTION.set(profile); + try { + return new SlayerMinionMob(ownerUuid, profile); + } finally { + IN_CONSTRUCTION.remove(); + } + } + + public UUID getOwnerUuid() { + return ownerUuid; + } + + @Override public String getDisplayName() { return live().displayName(); } + @Override public Integer getLevel() { return live().level(); } + @Override public List getMobTypes() { return live().mobTypes(); } + @Override public @Nullable SkyBlockLootTable getLootTable() { return null; } + @Override public SkillCategories getSkillCategory() { return SkillCategories.COMBAT; } + @Override public long damageCooldown() { return 700L; } + @Override public OtherLoot getOtherLoot() { return new OtherLoot(0, 0, 0); } + + @Override + public List getGoalSelectors() { + return SlayerBossBehaviour.goals(this); + } + + @Override + public List getTargetSelectors() { + return SlayerBossBehaviour.targets(this); + } + + @Override + public ItemStatistics getBaseStatistics() { + return ItemStatistics.builder() + .withBase(ItemStatistic.HEALTH, live().health()) + .withBase(ItemStatistic.DAMAGE, live().damage()) + .withBase(ItemStatistic.SPEED, live().speed()) + .build(); + } + + private SlayerMinionProfile live() { + return profile != null ? profile : IN_CONSTRUCTION.get(); + } + + public record SlayerMinionProfile( + String displayName, + int level, + EntityType entityType, + double health, + double damage, + double speed, + List mobTypes + ) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/InfernoDemonlordAbility.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/InfernoDemonlordAbility.java new file mode 100644 index 000000000..5cac4c15e --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/InfernoDemonlordAbility.java @@ -0,0 +1,132 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import java.util.List; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.damage.Damage; +import net.minestom.server.particle.Particle; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerMinionMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +final class InfernoDemonlordAbility extends SlayerAbilitySupport { + private final String[] attunements = {"ASHEN", "SPIRIT", "AURIC", "CRYSTAL"}; + private int attunementIndex; + private int shieldHits; + private boolean split66; + private boolean split50; + private boolean split33; + private boolean pillars; + private boolean apocalypse; + + @Override + public void onSpawn(SlayerBossMob boss) { + repeating(boss, 20, 20, () -> { + nearbyPlayers(boss, 6).forEach(player -> trueDamage(boss, player, immolateDamage(boss, player), "Immolate")); + particles(boss, Particle.FLAME, 1.3f, 35); + + if (boss.getProfile().tier().tier().number() >= 3 && !split66 && healthRatio(boss) <= 0.66D) { + split66 = true; + demonSplit(boss); + } + if (!split50 && healthRatio(boss) <= 0.50D) { + split50 = true; + demonSplit(boss); + } + if (boss.getProfile().tier().tier().number() >= 3 && !split33 && healthRatio(boss) <= 0.33D) { + split33 = true; + demonSplit(boss); + } + if (!pillars && healthRatio(boss) <= (boss.getProfile().tier().tier().number() >= 4 ? 0.66D : 0.50D)) { + pillars = true; + firePillars(boss); + } + if (boss.getProfile().tier().tier().number() >= 3 && !apocalypse && healthRatio(boss) <= 0.33D) { + apocalypse = true; + ddrApocalypse(boss); + } + }); + } + + @Override + public float modifyIncomingDamage(SlayerBossMob boss, Damage damage, float amount) { + shieldHits++; + if (shieldHits >= 8) { + shieldHits = 0; + attunementIndex = (attunementIndex + 1) % attunements.length; + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§6Hellion Shield attuned to §e" + attunements[attunementIndex] + "§6!")); + } + + if (boss.getProfile().tier().tier().number() >= 2) { + return amount * 0.35F; + } + return amount; + } + + private double immolateDamage(SlayerBossMob boss, SkyBlockPlayer player) { + double percent = switch (boss.getProfile().tier().tier()) { + case I -> healthRatio(boss) <= 0.33D ? 0.12D : healthRatio(boss) <= 0.66D ? 0.08D : 0.05D; + case II -> healthRatio(boss) <= 0.33D ? 0.15D : healthRatio(boss) <= 0.66D ? 0.10D : 0.05D; + case III -> healthRatio(boss) <= 0.33D ? 0.20D : healthRatio(boss) <= 0.66D ? 0.10D : 0.05D; + case IV, V -> healthRatio(boss) <= 0.33D ? 0.50D : healthRatio(boss) <= 0.66D ? 0.30D : 0.20D; + }; + return 100D + player.getMaxHealth() * percent; + } + + private void demonSplit(SlayerBossMob boss) { + nearbyPlayers(boss, 18).forEach(player -> player.sendMessage("§6Demonsplit! §eQuazii and Typhoeus join the fight.")); + spawnMinion(boss, new SlayerMinionMob.SlayerMinionProfile( + "Quazii", + boss.getLevel(), + EntityType.BLAZE, + boss.getProfile().tier().bossHealth() * 0.08D, + boss.getProfile().tier().bossDamage() * 0.5D, + 120D, + List.of(MobType.INFERNAL, MobType.MAGMATIC) + ), boss.getPosition().add(2, 0, 0), 260); + spawnMinion(boss, new SlayerMinionMob.SlayerMinionProfile( + "Typhoeus", + boss.getLevel(), + EntityType.BLAZE, + boss.getProfile().tier().bossHealth() * 0.08D, + boss.getProfile().tier().bossDamage() * 0.5D, + 120D, + List.of(MobType.INFERNAL, MobType.MAGMATIC) + ), boss.getPosition().add(-2, 0, 0), 260); + repeating(boss, 20, 20, () -> nearbyPlayers(boss, 7).forEach(player -> + trueDamage(boss, player, scorchedAngerDamage(boss), "Scorched Anger"))); + } + + private void firePillars(SlayerBossMob boss) { + repeating(boss, 140, 160, () -> { + SkyBlockPlayer owner = owner(boss); + if (owner == null) { + return; + } + + Pos pillar = owner.getPosition().add((Math.random() - 0.5D) * 6D, 0, (Math.random() - 0.5D) * 6D); + nearbyPlayers(boss, 18).forEach(player -> player.sendMessage("§6Fire Pillar! §eClear it before it explodes.")); + delayed(boss, 140, () -> { + if (owner.getPosition().distance(pillar) <= 4D) { + trueDamage(boss, owner, owner.getMaxHealth() * 10D, "Fire Pillar"); + } + }); + }); + } + + private void ddrApocalypse(SlayerBossMob boss) { + nearbyPlayers(boss, 18).forEach(player -> player.sendMessage("§cDDR Apocalypse!")); + repeating(boss, 20, 20, () -> nearbyPlayers(boss, 8).forEach(player -> + trueDamage(boss, player, player.getMaxHealth() * 2D, "DDR Apocalypse"))); + } + + private double scorchedAngerDamage(SlayerBossMob boss) { + return switch (boss.getProfile().tier().tier()) { + case I -> 1250D; + case II -> 4000D; + case III -> 7500D; + case IV, V -> 15000D; + }; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/NoopSlayerBossAbility.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/NoopSlayerBossAbility.java new file mode 100644 index 000000000..f28b6c5a0 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/NoopSlayerBossAbility.java @@ -0,0 +1,18 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.minestom.server.entity.damage.Damage; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +final class NoopSlayerBossAbility implements SlayerBossAbility { + static final NoopSlayerBossAbility INSTANCE = new NoopSlayerBossAbility(); + + @Override public void onSpawn(SlayerBossMob boss) {} + @Override public float modifyIncomingDamage(SlayerBossMob boss, Damage damage, float amount) { return amount; } + @Override public void onDamaged(SlayerBossMob boss, Damage damage, float appliedDamage) {} + @Override public void onMeleeHit(SlayerBossMob boss, SkyBlockPlayer target) {} + @Override public void onDeath(SlayerBossMob boss) {} +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/RevenantHorrorAbility.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/RevenantHorrorAbility.java new file mode 100644 index 000000000..d012791d7 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/RevenantHorrorAbility.java @@ -0,0 +1,88 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import net.minestom.server.particle.Particle; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +final class RevenantHorrorAbility extends SlayerAbilitySupport { + private boolean enrage; + private boolean thermonuclear; + private long spawnedAt; + + @Override + public void onSpawn(SlayerBossMob boss) { + spawnedAt = System.currentTimeMillis(); + + repeating(boss, 50, 50, () -> { + double damage = lifeDrainDamage(boss); + nearbyPlayers(boss, 5.5).forEach(player -> trueDamage(boss, player, damage, "Life Drain")); + particles(boss, Particle.SOUL, 0.7f, 12); + }); + + if (boss.getProfile().tier().tier().number() >= 3) { + repeating(boss, 20, 20, () -> { + double damage = pestilenceDamage(boss) * (enrage ? 6D : 1D); + nearbyPlayers(boss, 8.5).forEach(player -> trueDamage(boss, player, damage, "Pestilence")); + particles(boss, Particle.ASH, 1.2f, 20); + }); + } + + if (boss.getProfile().tier().tier().number() >= 4) { + repeating(boss, 800, 800, () -> { + enrage = true; + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§c" + boss.getDisplayName() + " is enraged!")); + delayed(boss, 240, () -> enrage = false); + }); + } + + if (boss.getProfile().tier().tier().number() >= 5) { + repeating(boss, 40, 40, () -> heal(boss, boss.getProfile().tier().bossHealth() * 0.015D)); + repeating(boss, 160, 160, () -> nearbyPlayers(boss, 6).forEach(player -> { + player.sendMessage("§cExplosive Assault!"); + trueDamage(boss, player, 4800, "Explosive Assault"); + })); + } + } + + @Override + public void onDamaged(SlayerBossMob boss, net.minestom.server.entity.damage.Damage damage, float appliedDamage) { + if (boss.getProfile().tier().tier().number() < 5 || thermonuclear || healthRatio(boss) > 0.33D) { + return; + } + + thermonuclear = true; + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§4§lTHERMONUCLEAR! §cMove away!")); + delayed(boss, 45, () -> { + nearbyPlayers(boss, 7).forEach(player -> { + lightning(player.getPosition(), player.getInstance()); + trueDamage(boss, player, 24000, "Thermonuclear"); + }); + }); + } + + @Override + public void onMeleeHit(SlayerBossMob boss, SkyBlockPlayer target) { + if (enrage) { + trueDamage(boss, target, boss.getProfile().tier().bossDamage() * 0.5D, "Enrage"); + } + } + + private double lifeDrainDamage(SlayerBossMob boss) { + return switch (boss.getProfile().tier().tier()) { + case I -> 15D; + case II -> 40D; + case III -> 100D; + case IV -> 260D; + case V -> 900D; + }; + } + + private double pestilenceDamage(SlayerBossMob boss) { + return switch (boss.getProfile().tier().tier()) { + case I, II -> 0D; + case III -> 35D; + case IV -> 120D; + case V -> 400D; + }; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerAbilitySupport.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerAbilitySupport.java new file mode 100644 index 000000000..f9d842579 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerAbilitySupport.java @@ -0,0 +1,156 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import java.util.List; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; +import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.LivingEntity; +import net.minestom.server.entity.damage.EntityDamage; +import net.minestom.server.instance.Instance; +import net.minestom.server.network.packet.server.play.ParticlePacket; +import net.minestom.server.particle.Particle; +import net.minestom.server.timer.Task; +import net.minestom.server.timer.TaskSchedule; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerMinionMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.DamageIndicator; + +abstract class SlayerAbilitySupport implements SlayerBossAbility { + protected Task repeating(SlayerBossMob boss, int delayTicks, int repeatTicks, Runnable runnable) { + Task task = boss.scheduler().buildTask(() -> { + if (boss.isRemoved() || boss.getInstance() == null) { + return; + } + runnable.run(); + }).delay(TaskSchedule.tick(delayTicks)).repeat(TaskSchedule.tick(repeatTicks)).schedule(); + boss.trackAbilityTask(task); + return task; + } + + protected Task delayed(SlayerBossMob boss, int delayTicks, Runnable runnable) { + Task task = boss.scheduler().buildTask(() -> { + if (boss.isRemoved() || boss.getInstance() == null) { + return; + } + runnable.run(); + }).delay(TaskSchedule.tick(delayTicks)).schedule(); + boss.trackAbilityTask(task); + return task; + } + + protected List nearbyPlayers(SlayerBossMob boss, double range) { + Instance instance = boss.getInstance(); + if (instance == null) { + return List.of(); + } + + return instance.getPlayers().stream() + .filter(player -> player instanceof SkyBlockPlayer) + .map(player -> (SkyBlockPlayer) player) + .filter(player -> player.getPosition().distance(boss.getPosition()) <= range) + .toList(); + } + + protected SkyBlockPlayer owner(SlayerBossMob boss) { + Instance instance = boss.getInstance(); + if (instance == null) { + return null; + } + + return instance.getPlayers().stream() + .filter(player -> player.getUuid().equals(boss.getOwnerUuid())) + .filter(player -> player instanceof SkyBlockPlayer) + .map(player -> (SkyBlockPlayer) player) + .findFirst() + .orElse(null); + } + + protected void trueDamage(SlayerBossMob boss, SkyBlockPlayer player, double damage, String source) { + if (damage <= 0 || player.isRemoved()) { + return; + } + + player.setHealth((float) Math.max(0, player.getHealth() - damage)); + new DamageIndicator().damage((float) damage).pos(player.getPosition()).critical(false).display(player.getInstance()); + player.sendMessage("§c" + source + " dealt " + Math.round(damage) + " true damage!"); + player.playSound(Sound.sound(Key.key("entity.player.hurt"), Sound.Source.PLAYER, 0.8f, 0.8f), Sound.Emitter.self()); + } + + protected void damage(SlayerBossMob boss, SkyBlockPlayer player, double damage) { + if (damage <= 0 || player.isRemoved()) { + return; + } + player.damage(new EntityDamage(boss, (float) damage)); + new DamageIndicator().damage((float) damage).pos(player.getPosition()).critical(false).display(player.getInstance()); + } + + protected void heal(SlayerBossMob boss, double amount) { + float max = (float) boss.getBaseStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.HEALTH).doubleValue(); + boss.setHealth(Math.min(max, boss.getHealth() + (float) amount)); + } + + protected double healthRatio(SlayerBossMob boss) { + double max = boss.getBaseStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.HEALTH); + if (max <= 0) { + return 0D; + } + return boss.getHealth() / max; + } + + protected void particles(SlayerBossMob boss, Particle particle, float spread, int count) { + Instance instance = boss.getInstance(); + if (instance == null) { + return; + } + + Pos position = boss.getPosition().add(0, 1, 0); + instance.getPlayers().forEach(player -> player.sendPacket(new ParticlePacket( + particle, + true, + true, + position.x(), + position.y(), + position.z(), + spread, + spread, + spread, + 0.1f, + count + ))); + } + + protected void lightning(Pos position, Instance instance) { + if (instance == null) { + return; + } + + LivingEntity lightning = new LivingEntity(net.minestom.server.entity.EntityType.LIGHTNING_BOLT); + lightning.setInstance(instance, position); + MinecraftServer.getSchedulerManager().scheduleTask(lightning::remove, TaskSchedule.seconds(1), TaskSchedule.stop()); + } + + protected SlayerMinionMob spawnMinion(SlayerBossMob boss, SlayerMinionMob.SlayerMinionProfile profile, Pos position, int lifespanTicks) { + Instance instance = boss.getInstance(); + if (instance == null) { + return null; + } + + SlayerMinionMob minion = SlayerMinionMob.create(boss.getOwnerUuid(), profile); + minion.setInstance(instance, position); + if (lifespanTicks > 0) { + delayed(boss, lifespanTicks, () -> { + if (!minion.isRemoved()) { + minion.remove(); + } + }); + } + return minion; + } + + @Override public float modifyIncomingDamage(SlayerBossMob boss, net.minestom.server.entity.damage.Damage damage, float amount) { return amount; } + @Override public void onDamaged(SlayerBossMob boss, net.minestom.server.entity.damage.Damage damage, float appliedDamage) {} + @Override public void onMeleeHit(SlayerBossMob boss, SkyBlockPlayer target) {} + @Override public void onDeath(SlayerBossMob boss) {} +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerBossAbility.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerBossAbility.java new file mode 100644 index 000000000..7810f4d95 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerBossAbility.java @@ -0,0 +1,21 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import net.minestom.server.entity.damage.Damage; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public interface SlayerBossAbility { + void onSpawn(SlayerBossMob boss); + + float modifyIncomingDamage(SlayerBossMob boss, Damage damage, float amount); + + void onDamaged(SlayerBossMob boss, Damage damage, float appliedDamage); + + void onMeleeHit(SlayerBossMob boss, SkyBlockPlayer target); + + void onDeath(SlayerBossMob boss); + + static SlayerBossAbility none() { + return NoopSlayerBossAbility.INSTANCE; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerBossAbilityFactory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerBossAbilityFactory.java new file mode 100644 index 000000000..aa86ac4b0 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SlayerBossAbilityFactory.java @@ -0,0 +1,19 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.swofty.type.skyblockgeneric.slayer.SlayerType; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SlayerBossAbilityFactory { + public static SlayerBossAbility create(SlayerType type) { + return switch (type) { + case REVENANT_HORROR -> new RevenantHorrorAbility(); + case TARANTULA_BROODFATHER -> new TarantulaBroodfatherAbility(); + case SVEN_PACKMASTER -> new SvenPackmasterAbility(); + case VOIDGLOOM_SERAPH -> new VoidgloomSeraphAbility(); + case INFERNO_DEMONLORD -> new InfernoDemonlordAbility(); + case RIFTSTALKER_BLOODFIEND -> SlayerBossAbility.none(); + }; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SvenPackmasterAbility.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SvenPackmasterAbility.java new file mode 100644 index 000000000..06ddf6a1e --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/SvenPackmasterAbility.java @@ -0,0 +1,55 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import java.util.List; +import net.minestom.server.entity.EntityType; +import net.minestom.server.particle.Particle; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerMinionMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +final class SvenPackmasterAbility extends SlayerAbilitySupport { + private boolean pupsCalled; + + @Override + public void onSpawn(SlayerBossMob boss) { + repeating(boss, 20, 20, () -> { + if (boss.getProfile().tier().tier().number() >= 3 && !pupsCalled && healthRatio(boss) <= 0.50D) { + pupsCalled = true; + callPups(boss); + } + particles(boss, Particle.CRIT, 0.5f, 4); + }); + } + + @Override + public void onMeleeHit(SlayerBossMob boss, SkyBlockPlayer target) { + double trueDamage = switch (boss.getProfile().tier().tier()) { + case I -> 0D; + case II -> 10D; + case III -> 50D; + case IV, V -> 200D; + }; + if (trueDamage > 0) { + trueDamage(boss, target, trueDamage, "True Damage"); + } + } + + private void callPups(SlayerBossMob boss) { + int pups = boss.getProfile().tier().tier().number() >= 4 ? 6 : 5; + double damage = boss.getProfile().tier().tier().number() >= 4 ? 220D : 90D; + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§fCall the pups!")); + for (int i = 0; i < pups; i++) { + int index = i; + delayed(boss, i * 10, () -> spawnMinion(boss, new SlayerMinionMob.SlayerMinionProfile( + "Pack Pup", + boss.getLevel(), + EntityType.WOLF, + boss.getProfile().tier().bossHealth() * 0.02D, + damage, + 160D, + List.of(MobType.WOODLAND) + ), boss.getPosition().add(index - pups / 2D, 0, 1.5), 360)); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/TarantulaBroodfatherAbility.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/TarantulaBroodfatherAbility.java new file mode 100644 index 000000000..39bd45c61 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/TarantulaBroodfatherAbility.java @@ -0,0 +1,105 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import java.util.List; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.damage.Damage; +import net.minestom.server.particle.Particle; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerMinionMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +final class TarantulaBroodfatherAbility extends SlayerAbilitySupport { + private boolean web66; + private boolean web33; + private boolean barrage; + private boolean conjoined; + + @Override + public void onSpawn(SlayerBossMob boss) { + repeating(boss, 80, 120, () -> { + SkyBlockPlayer owner = owner(boss); + if (owner == null) { + return; + } + Pos behind = owner.getPosition().sub(owner.getPosition().direction().mul(2)).withY(owner.getPosition().y()); + boss.teleport(behind); + owner.sendMessage("§5Backstab!"); + }); + + repeating(boss, 20, 20, () -> { + int tier = boss.getProfile().tier().tier().number(); + if (tier >= 3 && !web66 && healthRatio(boss) <= 0.66D) { + web66 = true; + webOfLies(boss); + } + if (tier >= 3 && !web33 && healthRatio(boss) <= 0.33D) { + web33 = true; + webOfLies(boss); + } + if (tier >= 4 && !barrage && healthRatio(boss) <= (tier == 4 ? 0.50D : 0.66D)) { + barrage = true; + batBarrage(boss); + } + }); + } + + @Override + public float modifyIncomingDamage(SlayerBossMob boss, Damage damage, float amount) { + if (boss.getProfile().tier().tier().number() >= 5 && !conjoined && amount >= boss.getHealth()) { + conjoined = true; + boss.setHealth((float) boss.getProfile().tier().bossHealth()); + boss.getAttribute(net.minestom.server.entity.attribute.Attribute.MAX_HEALTH).setBaseValue(boss.getProfile().tier().bossHealth() * 2D); + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§5Til Death Do Us Part! §dThe Conjoined Brood awakens!")); + return 0F; + } + return amount; + } + + @Override + public void onMeleeHit(SlayerBossMob boss, SkyBlockPlayer target) { + int tier = boss.getProfile().tier().tier().number(); + if (tier >= 2) { + trueDamage(boss, target, tier * 25D, "Noxious Paralysis"); + } + } + + private void webOfLies(SlayerBossMob boss) { + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§5Web of Lies! §dDestroy the egg sacs!")); + heal(boss, boss.getProfile().tier().bossHealth() * 0.05D); + int sacs = boss.getProfile().tier().tier().number() >= 5 ? 3 : 2; + for (int i = 0; i < sacs; i++) { + Pos pos = boss.getPosition().add(i - 1, 2, i % 2 == 0 ? 1 : -1); + spawnMinion(boss, new SlayerMinionMob.SlayerMinionProfile( + "Tarantula Egg Sac", + boss.getLevel(), + EntityType.SPIDER, + boss.getProfile().tier().bossHealth() * 0.04D, + boss.getProfile().tier().bossDamage() * 0.25D, + 60D, + List.of(MobType.ARTHROPOD) + ), pos, 220); + } + particles(boss, Particle.ITEM_COBWEB, 1.5f, 40); + } + + private void batBarrage(SlayerBossMob boss) { + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§5Bat Barrage!")); + int bats = boss.getProfile().tier().tier().number() >= 5 ? 6 : 4; + for (int i = 0; i < bats; i++) { + spawnMinion(boss, new SlayerMinionMob.SlayerMinionProfile( + "Brood Bat", + boss.getLevel(), + EntityType.BAT, + boss.getProfile().tier().bossHealth() * 0.015D, + boss.getProfile().tier().bossDamage() * 0.2D, + 160D, + List.of(MobType.ARTHROPOD) + ), boss.getPosition().add(i - 2, 1, i % 2 == 0 ? 2 : -2), 300); + } + + repeating(boss, 20, 20, () -> nearbyPlayers(boss, 7).forEach(player -> + trueDamage(boss, player, player.getMaxHealth() * (boss.getProfile().tier().tier().number() >= 5 ? 0.04D : 0.02D), "Bat Barrage"))); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/VoidgloomSeraphAbility.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/VoidgloomSeraphAbility.java new file mode 100644 index 000000000..0328ddf8f --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/mob/mobs/slayer/ability/VoidgloomSeraphAbility.java @@ -0,0 +1,115 @@ +package net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.ability; + +import java.util.HashSet; +import java.util.Set; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.damage.Damage; +import net.minestom.server.particle.Particle; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +final class VoidgloomSeraphAbility extends SlayerAbilitySupport { + private final Set triggeredShields = new HashSet<>(); + private int shieldHits; + private boolean glyphStarted; + private int fixationHeads; + + @Override + public void onSpawn(SlayerBossMob boss) { + triggerShield(boss, 100); + + repeating(boss, 20, 20, () -> { + SkyBlockPlayer owner = owner(boss); + if (owner != null) { + Pos side = owner.getPosition().add((Math.random() - 0.5D) * 3D, 0, (Math.random() - 0.5D) * 3D); + boss.teleport(side); + } + nearbyPlayers(boss, 6.5).forEach(player -> trueDamage(boss, player, dissonanceDamage(boss), "Dissonance")); + particles(boss, Particle.PORTAL, 1.2f, 25); + + if (healthRatio(boss) <= 0.66D) { + triggerShield(boss, 66); + } + if (healthRatio(boss) <= 0.33D) { + triggerShield(boss, 33); + } + if (boss.getProfile().tier().tier().number() >= 2 && !glyphStarted && healthRatio(boss) <= 0.50D) { + glyphStarted = true; + startGlyphs(boss); + } + }); + + if (boss.getProfile().tier().tier().number() >= 3) { + repeating(boss, 120, 120, () -> { + if (healthRatio(boss) <= 0.33D && fixationHeads < 6) { + fixationHeads++; + nearbyPlayers(boss, 12).forEach(player -> player.sendMessage("§5Nukekubi Fixation spawned!")); + } + }); + repeating(boss, 20, 20, () -> { + if (fixationHeads > 0) { + double damage = Math.min(dissonanceDamage(boss), 800D * (fixationHeads * Math.pow(2, fixationHeads - 1))); + nearbyPlayers(boss, 8).forEach(player -> trueDamage(boss, player, damage, "Nukekubi Fixation")); + } + }); + } + } + + @Override + public float modifyIncomingDamage(SlayerBossMob boss, Damage damage, float amount) { + if (shieldHits <= 0) { + return amount; + } + + shieldHits--; + if (shieldHits == 0) { + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§dMalevolent Hitshield broken!")); + } else { + nearbyPlayers(boss, 12).forEach(player -> player.sendMessage("§5Hitshield: §d" + shieldHits + " hits left")); + } + boss.teleport(boss.getPosition().add((Math.random() - 0.5D) * 1.5D, 0, (Math.random() - 0.5D) * 1.5D)); + return 0F; + } + + private void triggerShield(SlayerBossMob boss, int threshold) { + if (!triggeredShields.add(threshold)) { + return; + } + + shieldHits = switch (boss.getProfile().tier().tier()) { + case I -> 15; + case II -> 30; + case III -> 60; + case IV, V -> 100; + }; + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§5Malevolent Hitshield! §d" + shieldHits + " hits required.")); + } + + private void startGlyphs(SlayerBossMob boss) { + repeating(boss, 160, 160, () -> { + SkyBlockPlayer owner = owner(boss); + if (owner == null) { + return; + } + + Pos glyph = owner.getPosition().add((Math.random() - 0.5D) * 7D, 0, (Math.random() - 0.5D) * 7D); + nearbyPlayers(boss, 16).forEach(player -> player.sendMessage("§eYang Glyph! §7Stand on it before it detonates.")); + delayed(boss, 100, () -> { + if (owner.getPosition().distance(glyph) > 1.5D) { + trueDamage(boss, owner, owner.getMaxHealth() * 1000D, "Yang Glyph"); + } else { + owner.sendMessage("§aYang Glyph shattered!"); + } + }); + }); + } + + private double dissonanceDamage(SlayerBossMob boss) { + return switch (boss.getProfile().tier().tier()) { + case I -> 720D; + case II -> 3000D; + case III -> 7200D; + case IV, V -> 12600D; + }; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeMiningRegion.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeMiningRegion.java index 2098c466e..42bcace7d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeMiningRegion.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeMiningRegion.java @@ -3,13 +3,14 @@ import net.minestom.server.entity.attribute.Attribute; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionChangeMiningRegion implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeTimeCalender.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeTimeCalender.java index 169918357..05e4930c5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeTimeCalender.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionChangeTimeCalender.java @@ -1,13 +1,14 @@ package net.swofty.type.skyblockgeneric.event.actions.custom; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.event.custom.CalenderHourlyUpdateEvent; public class ActionChangeTimeCalender implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(CalenderHourlyUpdateEvent event) { int hour = event.hour(); long minecraftTime = (hour * 1000L + 6000) % 24000; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionDisplayMenu.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionDisplayMenu.java index 6ce7d9516..61692a258 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionDisplayMenu.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionDisplayMenu.java @@ -1,14 +1,15 @@ package net.swofty.type.skyblockgeneric.event.actions.custom; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.skyblockgeneric.event.actions.player.ActionPlayerChangeHypixelMenuDisplay; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionDisplayMenu implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(HypixelInventoryGUI.InventoryGUIOpenEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.player(); ActionPlayerChangeHypixelMenuDisplay.setMainMenu(player); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionNewZoneDisplay.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionNewZoneDisplay.java index 24219ed5f..139e5ebe3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionNewZoneDisplay.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionNewZoneDisplay.java @@ -6,8 +6,9 @@ import net.kyori.adventure.title.Title; import net.swofty.type.generic.data.datapoints.DatapointStringList; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.region.RegionType; @@ -18,7 +19,7 @@ public class ActionNewZoneDisplay implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionPlayerDamageBlock.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionPlayerDamageBlock.java index a565f83ca..966051f76 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionPlayerDamageBlock.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionPlayerDamageBlock.java @@ -7,8 +7,9 @@ import net.minestom.server.network.packet.server.play.BlockBreakAnimationPacket; import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerDamageSkyBlockBlockEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; @@ -24,7 +25,7 @@ public class ActionPlayerDamageBlock implements HypixelEventClass { public static final Map CLICKING = new HashMap<>(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerDamageSkyBlockBlockEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); SkyBlockRegion region = SkyBlockRegion.getRegionOfPosition(event.getBlockPosition()); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionChangeDisplay.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionChangeDisplay.java index ec49f2bf4..b3b6313b5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionChangeDisplay.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionChangeDisplay.java @@ -1,8 +1,9 @@ package net.swofty.type.skyblockgeneric.event.actions.custom; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.region.RegionType; import net.swofty.type.skyblockgeneric.user.SkyBlockActionBar; @@ -10,7 +11,7 @@ public class ActionRegionChangeDisplay implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionPlaySong.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionPlaySong.java index c6060cc89..963aa309b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionPlaySong.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionRegionPlaySong.java @@ -5,8 +5,9 @@ import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.noteblock.SkyBlockSong; import net.swofty.type.skyblockgeneric.noteblock.SkyBlockSongsHandler; @@ -18,7 +19,7 @@ public class ActionRegionPlaySong implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { SkyBlockPlayer player = event.getPlayer(); SkyBlockSongsHandler songHandler = player.getSongHandler(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionSlayerMobKill.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionSlayerMobKill.java new file mode 100644 index 000000000..415e4b95f --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/ActionSlayerMobKill.java @@ -0,0 +1,15 @@ +package net.swofty.type.skyblockgeneric.event.actions.custom; + +import net.swofty.type.generic.event.EventNodes; +import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.skyblockgeneric.event.custom.PlayerKilledSkyBlockMobEvent; +import net.swofty.type.skyblockgeneric.slayer.SlayerService; + +public class ActionSlayerMobKill implements HypixelEventClass { + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) + public void run(PlayerKilledSkyBlockMobEvent event) { + SlayerService.handleMobKill(event.getPlayer(), event.getKilledMob()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/bestiary/ActionBestiaryLevelUp.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/bestiary/ActionBestiaryLevelUp.java index 68e190759..a8f0e195c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/bestiary/ActionBestiaryLevelUp.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/bestiary/ActionBestiaryLevelUp.java @@ -4,8 +4,9 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.bestiary.BestiaryData; import net.swofty.type.skyblockgeneric.entity.mob.BestiaryMob; import net.swofty.type.skyblockgeneric.event.custom.BestiaryUpdateEvent; @@ -20,7 +21,7 @@ public class ActionBestiaryLevelUp implements HypixelEventClass { private final BestiaryData bestiaryData = new BestiaryData(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(BestiaryUpdateEvent event) { SkyBlockPlayer player = event.getPlayer(); BestiaryMob mob = event.getBestiaryMob(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionAdd.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionAdd.java index 1b1e1b75d..98798a859 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionAdd.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionAdd.java @@ -4,8 +4,9 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.proxyapi.ProxyPlayerSet; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.event.HypixelEventHandler; import net.swofty.type.generic.utility.MathUtility; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; @@ -21,7 +22,7 @@ public class ActionCollectionAdd implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(CustomBlockBreakEvent event) { if (event.getPlayerPlaced()) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionDisplay.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionDisplay.java index b7b0c3234..4de3637c6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionDisplay.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionDisplay.java @@ -5,8 +5,9 @@ import net.minestom.server.item.ItemStack; import net.swofty.commons.StringUtility; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.collection.CollectionCategories; import net.swofty.type.skyblockgeneric.collection.CollectionCategory; import net.swofty.type.skyblockgeneric.event.custom.CollectionUpdateEvent; @@ -19,7 +20,7 @@ public class ActionCollectionDisplay implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(CollectionUpdateEvent event) { if (event.getOldValue() == 0 && CollectionCategories.getCategory(event.getItemType()) != null) { @@ -92,4 +93,4 @@ public void run(CollectionUpdateEvent event) { player.sendMessage("§e§l▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"); } } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionHypixelLevel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionHypixelLevel.java index 4a4c8f61f..0d59cec11 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionHypixelLevel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/collection/ActionCollectionHypixelLevel.java @@ -1,8 +1,9 @@ package net.swofty.type.skyblockgeneric.event.actions.custom.collection; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.collection.CollectionCategories; import net.swofty.type.skyblockgeneric.collection.CollectionCategory; import net.swofty.type.skyblockgeneric.event.custom.CollectionUpdateEvent; @@ -11,7 +12,7 @@ public class ActionCollectionHypixelLevel implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(CollectionUpdateEvent event) { if (CollectionCategories.getCategory(event.getItemType()) == null) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/levels/ActionChangeHypixelXP.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/levels/ActionChangeHypixelXP.java index 846d51e12..2f9016ac0 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/levels/ActionChangeHypixelXP.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/levels/ActionChangeHypixelXP.java @@ -1,8 +1,9 @@ package net.swofty.type.skyblockgeneric.event.actions.custom.levels; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.actions.player.ActionAddSkyBlockXPToNametag; import net.swofty.type.skyblockgeneric.event.custom.SkyBlockXPModificationEvent; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; @@ -15,7 +16,7 @@ public class ActionChangeHypixelXP implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(SkyBlockXPModificationEvent event) { if (event.getNewXP() <= event.getOldXP()) return; SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/CoinDropHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/CoinDropHandler.java index f5fe26d09..7e0cf0700 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/CoinDropHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/CoinDropHandler.java @@ -5,15 +5,16 @@ import net.swofty.type.skyblockgeneric.entity.mob.BestiaryMob; import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerKilledSkyBlockMobEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class CoinDropHandler implements HypixelEventClass { BestiaryData bestiaryData = new BestiaryData(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerKilledSkyBlockMobEvent event) { SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/VanillaExperienceHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/VanillaExperienceHandler.java index ff91bcdaa..6f18c07e7 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/VanillaExperienceHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/loot/VanillaExperienceHandler.java @@ -4,8 +4,9 @@ import net.swofty.type.skyblockgeneric.entity.mob.BestiaryMob; import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; import net.swofty.type.skyblockgeneric.enchantment.impl.EnchantmentExperience; @@ -17,7 +18,7 @@ public class VanillaExperienceHandler implements HypixelEventClass { BestiaryData bestiaryData = new BestiaryData(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerKilledSkyBlockMobEvent event) { SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillCarpentryGain.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillCarpentryGain.java index ee4cdfc1a..08cff1df3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillCarpentryGain.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillCarpentryGain.java @@ -2,8 +2,9 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.ItemCraftEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.CraftableComponent; @@ -16,7 +17,7 @@ import java.util.Map; public class ActionSkillCarpentryGain implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(ItemCraftEvent event) { SkyBlockPlayer player = event.getPlayer(); if (!player.getMissionData().hasCompleted("give_wool_to_carpenter")) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillDisplay.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillDisplay.java index f91c62d4f..da8e9caa6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillDisplay.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillDisplay.java @@ -1,15 +1,16 @@ package net.swofty.type.skyblockgeneric.event.actions.custom.skill; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.SkillUpdateEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockActionBar; public class ActionSkillDisplay implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(SkillUpdateEvent event) { double oldValue = event.getOldValueRaw(); double newValue = event.getNewValueRaw(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillHypixelLevel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillHypixelLevel.java index c0036c6c4..4652a9ccb 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillHypixelLevel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillHypixelLevel.java @@ -1,8 +1,9 @@ package net.swofty.type.skyblockgeneric.event.actions.custom.skill; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.SkillUpdateEvent; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.skill.SkillCategories; @@ -10,7 +11,7 @@ public class ActionSkillHypixelLevel implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(SkillUpdateEvent event) { if (event.getNewValueRaw() <= event.getOldValueRaw()) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillLevelUp.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillLevelUp.java index 502d89904..bbceed0c6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillLevelUp.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillLevelUp.java @@ -5,8 +5,9 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.SkillUpdateEvent; import net.swofty.type.skyblockgeneric.skill.SkillCategories; import net.swofty.type.skyblockgeneric.skill.SkillCategory; @@ -17,7 +18,7 @@ public class ActionSkillLevelUp implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(SkillUpdateEvent event) { if (event.getNewValueRaw() <= event.getOldValueRaw()) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillMiningHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillMiningHandler.java index a018d3a66..92948a21c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillMiningHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillMiningHandler.java @@ -1,8 +1,9 @@ package net.swofty.type.skyblockgeneric.event.actions.custom.skill; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSkills; import net.swofty.type.skyblockgeneric.event.custom.CustomBlockBreakEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; @@ -11,7 +12,7 @@ public class ActionSkillMiningHandler implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(CustomBlockBreakEvent event) { if (event.getPlayerPlaced()) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillPetLevel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillPetLevel.java index 55f4769eb..57fad6f26 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillPetLevel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillPetLevel.java @@ -2,8 +2,9 @@ import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributePetData; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.SkillUpdateEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.PetComponent; @@ -11,7 +12,7 @@ public class ActionSkillPetLevel implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(SkillUpdateEvent event) { if (event.getNewValueRaw() <= event.getOldValueRaw()) return; double xp = event.getNewValueRaw() - event.getOldValueRaw(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillUpdateLast.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillUpdateLast.java index 48f832b7a..6536a9e4c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillUpdateLast.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/custom/skill/ActionSkillUpdateLast.java @@ -1,14 +1,15 @@ package net.swofty.type.skyblockgeneric.event.actions.custom.skill; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSkillCategory; import net.swofty.type.skyblockgeneric.event.custom.SkillUpdateEvent; public class ActionSkillUpdateLast implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(SkillUpdateEvent event) { double oldValue = event.getOldValueRaw(); double newValue = event.getNewValueRaw(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionAnimateEntityDamage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionAnimateEntityDamage.java index 31730b2a4..c04a1262f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionAnimateEntityDamage.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionAnimateEntityDamage.java @@ -3,12 +3,13 @@ import net.minestom.server.event.entity.EntityDamageEvent; import net.minestom.server.network.packet.server.play.DamageEventPacket; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionAnimateEntityDamage implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ENTITY, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ENTITY, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(EntityDamageEvent event) { event.setAnimation(true); event.setCancelled(false); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionChunkUnload.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionChunkUnload.java index fb549b543..84a4d6e30 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionChunkUnload.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/entity/ActionChunkUnload.java @@ -4,12 +4,13 @@ import net.minestom.server.instance.Instance; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionChunkUnload implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ENTITY, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.ENTITY, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(InstanceChunkUnloadEvent event) { Instance instance = event.getInstance(); int chunkX = event.getChunkX(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionDrinkPotion.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionDrinkPotion.java index 831c14a0c..76a9c3e7e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionDrinkPotion.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionDrinkPotion.java @@ -5,8 +5,9 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributePotionData; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.potion.PotionEffectService; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -17,7 +18,7 @@ */ public class ActionDrinkPotion implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerFinishItemUseEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); ItemStack itemStack = event.getItemStack(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockLeftUse.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockLeftUse.java index f2fa68b11..19a6ef16f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockLeftUse.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockLeftUse.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.AbilityComponent; import net.swofty.type.skyblockgeneric.item.handlers.ability.RegisteredAbility; @@ -14,7 +15,7 @@ public class ActionItemAbilityBlockLeftUse implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockBreakEvent event) { ItemStack itemStack = event.getPlayer().getItemInMainHand(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockRightUse.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockRightUse.java index fa9910c26..06e46ddfa 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockRightUse.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityBlockRightUse.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.AbilityComponent; import net.swofty.type.skyblockgeneric.item.handlers.ability.RegisteredAbility; @@ -14,7 +15,7 @@ public class ActionItemAbilityBlockRightUse implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { ItemStack itemStack = event.getPlayer().getItemInMainHand(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityLeftUse.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityLeftUse.java index f73ae3f18..d7b4dfffc 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityLeftUse.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityLeftUse.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerHandAnimationEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.AbilityComponent; import net.swofty.type.skyblockgeneric.item.handlers.ability.RegisteredAbility; @@ -15,7 +16,7 @@ public class ActionItemAbilityLeftUse implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerHandAnimationEvent event) { ItemStack itemStack = event.getPlayer().getItemInMainHand(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityRightUse.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityRightUse.java index a003cedc6..f5927655e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityRightUse.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemAbilityRightUse.java @@ -5,8 +5,9 @@ import net.minestom.server.item.ItemStack; import net.swofty.commons.skyblock.item.UnderstandableSkyBlockItem; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.AbilityComponent; import net.swofty.type.skyblockgeneric.item.handlers.ability.RegisteredAbility; @@ -16,7 +17,7 @@ public class ActionItemAbilityRightUse implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemEvent event) { ItemStack itemStack = event.getItemStack(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDisableEatingAnimation.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDisableEatingAnimation.java index 0c5650dd3..fde5cb3c4 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDisableEatingAnimation.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDisableEatingAnimation.java @@ -2,15 +2,16 @@ import net.minestom.server.event.item.PlayerBeginItemUseEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.DisableAnimationComponent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionItemDisableEatingAnimation implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBeginItemUseEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); SkyBlockItem item = new SkyBlockItem(player.getItemInMainHand()); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDrop.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDrop.java index 7f064cce1..0d7b17325 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDrop.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemDrop.java @@ -5,15 +5,16 @@ import net.minestom.server.event.item.ItemDropEvent; import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.entity.DroppedItemEntityImpl; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionItemDrop implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(ItemDropEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); @@ -27,6 +28,11 @@ public void run(ItemDropEvent event) { return; } + if (player.isInLaunchpad()) { + event.setCancelled(true); + return; + } + boolean hideMessage = player.getToggles().get(DatapointToggles.Toggles.ToggleType.DISABLE_DROP_MESSAGES); if (!hideMessage) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemLeftUse.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemLeftUse.java index 65c8e9e3c..2138e1424 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemLeftUse.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemLeftUse.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerHandAnimationEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.InteractableComponent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -13,7 +14,7 @@ public class ActionItemLeftUse implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerHandAnimationEvent event) { ItemStack itemStack = event.getPlayer().getItemInMainHand(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemPlace.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemPlace.java index f63bed015..041b1c9b8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemPlace.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemPlace.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.block.SkyBlockBlock; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.PlaceEventComponent; @@ -15,7 +16,7 @@ public class ActionItemPlace implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockPlaceEvent event) { ItemStack itemStack = event.getPlayer().getItemInMainHand(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemRightUse.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemRightUse.java index 964cf87f1..b6a8915b9 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemRightUse.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionItemRightUse.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.PlayerUseItemEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.InteractableComponent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionItemRightUse implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemEvent event) { ItemStack itemStack = event.getPlayer().getItemInMainHand(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionPlayerItemPickup.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionPlayerItemPickup.java index 7d65fe0ef..7018957e1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionPlayerItemPickup.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionPlayerItemPickup.java @@ -4,14 +4,15 @@ import net.minestom.server.network.packet.server.play.CollectItemPacket; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.entity.DroppedItemEntityImpl; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerItemPickup implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionThrowSplashPotion.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionThrowSplashPotion.java index 44523a8ec..8ee20d44e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionThrowSplashPotion.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionThrowSplashPotion.java @@ -6,8 +6,9 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributePotionData; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.entity.SplashPotionEntity; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -17,7 +18,7 @@ */ public class ActionThrowSplashPotion implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); ItemStack itemStack = event.getItemStack(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseBow.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseBow.java index 3a9ef3031..98ed94c63 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseBow.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseBow.java @@ -4,8 +4,9 @@ import net.minestom.server.event.item.PlayerCancelItemUseEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.BowComponent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -13,7 +14,7 @@ public class ActionUseBow implements HypixelEventClass { private static final double MIN_POWER = 0.1; - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerCancelItemUseEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); SkyBlockItem item = new SkyBlockItem(event.getItemStack()); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseShortBow.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseShortBow.java index cc2d64dfc..565b3ee74 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseShortBow.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/item/ActionUseShortBow.java @@ -3,8 +3,9 @@ import net.minestom.server.event.item.PlayerBeginItemUseEvent; import net.minestom.server.item.ItemAnimation; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.ArrowComponent; import net.swofty.type.skyblockgeneric.item.components.BowComponent; @@ -12,7 +13,7 @@ public class ActionUseShortBow implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBeginItemUseEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); ItemAnimation type = event.getAnimation(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/npc/ActionPlayerInteractNPC.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/npc/ActionPlayerInteractNPC.java index fd9e6bf8a..578940961 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/npc/ActionPlayerInteractNPC.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/npc/ActionPlayerInteractNPC.java @@ -3,8 +3,9 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.trait.NPCAbiphoneTrait; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.skyblockgeneric.abiphone.AbiphoneNPC; import net.swofty.type.skyblockgeneric.abiphone.AbiphoneRegistry; @@ -15,7 +16,7 @@ public class ActionPlayerInteractNPC implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(NPCInteractEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); HypixelNPC npc = event.getNpc(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAddSkyBlockXPToNametag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAddSkyBlockXPToNametag.java index b07e0f090..d234a18e2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAddSkyBlockXPToNametag.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAddSkyBlockXPToNametag.java @@ -7,8 +7,9 @@ import net.minestom.server.scoreboard.TeamBuilder; import net.swofty.commons.StringUtility; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.categories.Rank; import net.swofty.type.generic.utility.MathUtility; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSkyBlockExperience; @@ -16,7 +17,7 @@ public class ActionAddSkyBlockXPToNametag implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!event.isFirstSpawn()) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAnvilClick.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAnvilClick.java index 8773d41bb..3f6769d36 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAnvilClick.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionAnvilClick.java @@ -2,14 +2,15 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.gui.inventories.GUIAnvil; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionAnvilClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionClearPendingBazaar.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionClearPendingBazaar.java index 34018cfd5..45efbc6d5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionClearPendingBazaar.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionClearPendingBazaar.java @@ -2,13 +2,14 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionClearPendingBazaar implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); player.getBazaarConnector().processAllPendingTransactions(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java index a57d36039..b2f7bd980 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java @@ -3,14 +3,15 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUICrafting; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionCraftingTableClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionEnchantmentTableClick.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionEnchantmentTableClick.java index 3cc4c50d6..eaec45fad 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionEnchantmentTableClick.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionEnchantmentTableClick.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.gui.inventories.GUIEnchantmentTable; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionEnchantmentTableClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerBankAddInterest.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerBankAddInterest.java index c2024801a..97b0874bf 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerBankAddInterest.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerBankAddInterest.java @@ -4,8 +4,9 @@ import net.swofty.commons.StringUtility; import net.swofty.proxyapi.ProxyPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointBankData; import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; @@ -14,7 +15,7 @@ public class ActionPlayerBankAddInterest implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { if (event.isFirstSpawn()) return; SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChangeHypixelMenuDisplay.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChangeHypixelMenuDisplay.java index 0990ac5a4..7e3316a39 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChangeHypixelMenuDisplay.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChangeHypixelMenuDisplay.java @@ -8,8 +8,9 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.skyblockgeneric.collection.CustomCollectionAward; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointQuiver; @@ -24,7 +25,7 @@ public class ActionPlayerChangeHypixelMenuDisplay implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChangeHeldSlotEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); runCheck(player); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChat.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChat.java index 933283a78..357cd4464 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChat.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerChat.java @@ -8,8 +8,9 @@ import net.swofty.type.generic.data.datapoints.DatapointChatType; import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.categories.Rank; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; @@ -20,7 +21,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerInteractFairySoul.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerInteractFairySoul.java index 4a6ce7df4..35c82fe89 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerInteractFairySoul.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerInteractFairySoul.java @@ -2,15 +2,16 @@ import net.minestom.server.event.player.PlayerEntityInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.entity.EntityFairySoul; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.user.fairysouls.FairySoul; public class ActionPlayerInteractFairySoul implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerEntityInteractEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerJoin.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerJoin.java index b4ee11e12..5c09abf4d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerJoin.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerJoin.java @@ -2,13 +2,14 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; public class ActionPlayerJoin implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.SPAWN) public void onPlayerJoin(PlayerSpawnEvent event) { int hour = SkyBlockCalendar.getHour(); long minecraftTime = (hour * 1000L + 6000) % 24000; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerLaunchPads.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerLaunchPads.java index 0c73772c6..6d46d764b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerLaunchPads.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerLaunchPads.java @@ -14,8 +14,9 @@ import net.swofty.commons.UnderstandableProxyServer; import net.swofty.proxyapi.ProxyInformation; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.utility.MathUtility; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.utility.LaunchPads; @@ -35,7 +36,7 @@ public class ActionPlayerLaunchPads implements HypixelEventClass { private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private static final Set notifiedPlayers = ConcurrentHashMap.newKeySet(); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRemoveTab.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRemoveTab.java index 0425b244a..3f779ea8a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRemoveTab.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRemoveTab.java @@ -5,8 +5,9 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.minestom.server.network.packet.server.play.TeamsPacket; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.categories.Rank; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -16,7 +17,7 @@ public class ActionPlayerRemoveTab implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { Player player = event.getPlayer(); @@ -48,4 +49,4 @@ public void run(PlayerSpawnEvent event) { ))); }); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRightClickOnPlayer.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRightClickOnPlayer.java index 487e9138f..ad5af9ad1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRightClickOnPlayer.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerRightClickOnPlayer.java @@ -3,14 +3,15 @@ import net.minestom.server.event.player.PlayerEntityInteractEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.gui.inventories.GUIViewPlayerProfile; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerRightClickOnPlayer implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerEntityInteractEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerStrayTooFar.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerStrayTooFar.java index 896b845e0..2900f35ad 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerStrayTooFar.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerStrayTooFar.java @@ -3,8 +3,9 @@ import net.minestom.server.event.player.PlayerMoveEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.categories.Rank; import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -17,7 +18,7 @@ public class ActionPlayerStrayTooFar implements HypixelEventClass { public static Map startedStray = new HashMap<>(); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); SkyBlockRegion region = player.getRegion(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTransferServerParty.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTransferServerParty.java index 1f1950312..d490d6d15 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTransferServerParty.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTransferServerParty.java @@ -6,8 +6,9 @@ import net.swofty.proxyapi.ProxyPlayer; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.generic.utility.MathUtility; @@ -15,7 +16,7 @@ public class ActionPlayerTransferServerParty implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerDisconnectEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTravel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTravel.java index 13a4e4a24..9721c1999 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTravel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionPlayerTravel.java @@ -9,8 +9,9 @@ import net.swofty.commons.ServerType; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.MissionSet; import net.swofty.type.skyblockgeneric.mission.missions.MissionUseTeleporter; @@ -25,7 +26,7 @@ public class ActionPlayerTravel implements HypixelEventClass { public static List delay = new ArrayList<>(); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockDestroy.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockDestroy.java index 8ab63c1b5..c30fd6f96 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockDestroy.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockDestroy.java @@ -2,14 +2,15 @@ import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.block.SkyBlockBlock; import net.swofty.type.skyblockgeneric.block.impl.BlockBreakable; public class ActionBlockDestroy implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onDestroy(PlayerBlockBreakEvent event) { if (SkyBlockBlock.isSkyBlockBlock(event.getBlock())) { SkyBlockBlock block = new SkyBlockBlock(event.getBlock()); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockInteract.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockInteract.java index 20a69b1c6..df152fe3d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockInteract.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockInteract.java @@ -3,8 +3,9 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.block.SkyBlockBlock; import net.swofty.type.skyblockgeneric.block.impl.BlockInteractable; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; @@ -14,7 +15,7 @@ public class ActionBlockInteract implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onInteract(PlayerBlockInteractEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); ItemStack stack = event.getPlayer().getItemInMainHand(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockPlaceable.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockPlaceable.java index bd5cc9c2b..1ba12b6ea 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockPlaceable.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionBlockPlaceable.java @@ -3,8 +3,9 @@ import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.block.SkyBlockBlock; import net.swofty.type.skyblockgeneric.block.impl.BlockPlaceable; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; @@ -13,7 +14,7 @@ public class ActionBlockPlaceable implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onPlace(PlayerBlockPlaceEvent event) { ItemStack itemStack = event.getPlayer().getItemInMainHand(); SkyBlockItem item = new SkyBlockItem(itemStack); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionPlayerSetupMining.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionPlayerSetupMining.java index f523935a2..7e51978f5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionPlayerSetupMining.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/blocks/ActionPlayerSetupMining.java @@ -4,12 +4,13 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionPlayerSetupMining implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onSpawn(PlayerSpawnEvent event) { var player = event.getPlayer(); @@ -18,4 +19,4 @@ public void onSpawn(PlayerSpawnEvent event) { player.getAttribute(Attribute.BLOCK_BREAK_SPEED).clearModifiers(); player.getAttribute(Attribute.BLOCK_BREAK_SPEED).setBaseValue(0D); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerClearSkyBlockCache.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerClearSkyBlockCache.java index b576de21f..261a8da29 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerClearSkyBlockCache.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerClearSkyBlockCache.java @@ -3,8 +3,9 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.packet.packets.client.anticheat.PacketListenerAirJump; import net.swofty.type.skyblockgeneric.event.actions.player.ActionPlayerStrayTooFar; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemOrigin; @@ -15,7 +16,7 @@ public class ActionPlayerClearSkyBlockCache implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT, order = 10) public void run(PlayerDisconnectEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); @@ -27,4 +28,4 @@ public void run(PlayerDisconnectEvent event) { ActionPlayerStrayTooFar.startedStray.remove(player.getUuid()); CustomEventCaller.clearCache(player); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerDataLoaded.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerDataLoaded.java index df21b9903..c47ec59bf 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerDataLoaded.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerDataLoaded.java @@ -1,140 +1,23 @@ package net.swofty.type.skyblockgeneric.event.actions.player.data; import lombok.SneakyThrows; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.title.Title; -import net.minestom.server.MinecraftServer; import net.minestom.server.event.player.PlayerSpawnEvent; -import net.minestom.server.network.packet.server.play.UpdateHealthPacket; -import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; -import net.swofty.packer.packs.TestingTexture; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.data.datapoints.DatapointBoolean; -import net.swofty.type.generic.data.datapoints.DatapointString; -import net.swofty.type.generic.data.datapoints.DatapointStringList; -import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.generic.event.HypixelEventHandler; -import net.swofty.type.generic.user.categories.CustomGroups; -import net.swofty.type.generic.user.categories.Rank; -import net.swofty.type.generic.utility.MathUtility; -import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; -import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; -import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; -import net.swofty.type.skyblockgeneric.data.datapoints.DatapointUUID; -import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; -import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; -import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.generic.user.flow.PlayerFlow; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import net.swofty.type.skyblockgeneric.warps.TravelScrollIslands; -import org.tinylog.Logger; - -import java.time.Duration; -import java.util.List; -import java.util.UUID; +import net.swofty.type.skyblockgeneric.user.flow.SkyBlockPlayerDataFlow; public class ActionPlayerDataLoaded implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, phase = EventPhase.POST_SPAWN, order = 10) public void run(PlayerSpawnEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!event.isFirstSpawn()) return; - Logger.info("Loading SkyBlock data for spawned player: " + event.getPlayer().getUsername() + "..."); - - UUID playerUuid = player.getUuid(); - SkyBlockPlayerProfiles profiles = player.getProfiles(); - SkyBlockDataHandler handler = player.getSkyblockDataHandler(); - handler.runOnLoad(player); - - // Handle coop synchronization - if (handler.get(SkyBlockDataHandler.Data.IS_COOP, DatapointBoolean.class).getValue()) { - CoopDatabase.Coop coop = CoopDatabase.getFromMember(playerUuid); - if (coop.members().size() != 1) { - SkyBlockDataHandler data; - - if (SkyBlockGenericLoader.getLoadedPlayers().stream().anyMatch(player1 -> coop.members().contains(player1.getUuid()))) { - // A coop member is online, use their data - SkyBlockPlayer otherCoopMember = SkyBlockGenericLoader.getLoadedPlayers().stream() - .filter(player1 -> coop.members().contains(player1.getUuid())).findFirst().get(); - data = otherCoopMember.getSkyblockDataHandler(); - } else { - // No coop members are online, use the first member's data - UUID finalProfileId = profiles.getCurrentlySelected(); - data = SkyBlockDataHandler.createFromProfileOnly( - new ProfilesDatabase(coop.memberProfiles().stream() - .filter(uuid -> !uuid.equals(finalProfileId)) - .findFirst().get().toString()).getDocument() - ); - } - - data.getCoopValues().forEach((key, value) -> { - SkyBlockDatapoint targetDatapoint = (SkyBlockDatapoint) handler.getSkyBlockDatapoint(key); - targetDatapoint.setValueBypassCoop(value); - }); - } - } - - player.sendMessage(""); - - // Manually call region event with a delay - MathUtility.delay(() -> { - SkyBlockRegion playerRegion = player.getRegion(); - if (playerRegion != null && player.isOnline()) - HypixelEventHandler.callCustomEvent(new PlayerRegionChangeEvent( - player, - null, - playerRegion.getType() - )); - }, 50); - - Logger.info("Successfully loaded SkyBlock data for: " + player.getUsername()); - - Thread.startVirtualThread(() -> { - player.showTitle(Title.title( - Component.text(TestingTexture.FULL_SCREEN_BLACK.toString()), - Component.empty(), - Title.Times.times(Duration.ZERO, Duration.ofMillis(300), Duration.ofSeconds(1)) - )); - - Rank rank = player.getRank(); - if (rank.isStaff()) { - CustomGroups.staffMembers.add(player); - } - - player.sendMessage("§7 "); - player.sendMessage("§aYou are playing on profile: §e" + player.getSkyblockDataHandler().get( - SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue()); - player.sendMessage("§8Profile ID: " + player.getProfiles().getCurrentlySelected()); - - UUID islandUuid = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class).getValue(); - if (islandUuid != player.getProfiles().getCurrentlySelected()) - player.sendMessage("§8Island ID: " + islandUuid); - player.sendMessage(" "); - - player.health = player.getMaxHealth(); - player.sendPacket(new UpdateHealthPacket( - (player.health / player.getMaxHealth()) * 20, - 20, - 20)); - - MinecraftServer.getBossBarManager().removeAllBossBars(player); - MathUtility.delay(() -> { - if (!player.isOnline()) return; - player.getPetData().updatePetEntityImpl(player); - }, 20); - - TravelScrollIslands island = TravelScrollIslands.getFromType(HypixelConst.getTypeLoader().getType()); - if (island != null) { - List visitedIslands = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.VISITED_ISLANDS, DatapointStringList.class).getValue(); - if (!visitedIslands.contains(island.getInternalName())) { - visitedIslands.add(island.getInternalName()); - player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.VISITED_ISLANDS, DatapointStringList.class).setValue(visitedIslands); - } - } - }); + PlayerFlow.run(player, "skyblock-data/post-spawn", () -> SkyBlockPlayerDataFlow.postSpawn(player)); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataLoad.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataLoad.java index 1664026e3..d3402c2a0 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataLoad.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataLoad.java @@ -2,105 +2,20 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; -import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; -import net.swofty.type.generic.data.datapoints.DatapointString; -import net.swofty.type.generic.data.mongodb.ProfilesDatabase; -import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; -import net.swofty.type.skyblockgeneric.data.datapoints.DatapointUUID; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.generic.user.flow.PlayerFlow; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import org.bson.Document; -import org.tinylog.Logger; - -import java.util.Objects; -import java.util.UUID; +import net.swofty.type.skyblockgeneric.user.flow.SkyBlockPlayerDataFlow; public class ActionPlayerSkyBlockDataLoad implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, phase = EventPhase.LOAD_DATA, order = 10) public void run(AsyncPlayerConfigurationEvent event) { - Logger.info("Loading SkyBlock data for: " + event.getPlayer().getUsername() + "..."); - - final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); - UUID playerUuid = player.getUuid(); - - // Check if player has ever joined SkyBlock before - SkyBlockPlayerProfiles profiles = new UserDatabase(playerUuid).getProfiles(); - UUID profileId; - - if (profiles == null) { - // Brand new SkyBlock player - initialize everything - Logger.info("New SkyBlock player detected: " + player.getUsername() + " - initializing..."); - - profileId = UUID.randomUUID(); - // Create new profiles object - profiles = new SkyBlockPlayerProfiles(playerUuid); - profiles.setCurrentlySelected(profileId); - profiles.addProfile(profileId); - - // Save the new profiles to database - UserDatabase userDb = new UserDatabase(playerUuid); - userDb.saveProfiles(profiles); - } else { - // Existing player - profileId = profiles.getCurrentlySelected(); - if (profileId == null) { - // Player has profiles but no selected profile - create new one - profileId = UUID.randomUUID(); - profiles.setCurrentlySelected(profileId); - profiles.addProfile(profileId); - - // Save updated profiles - UserDatabase userDb = new UserDatabase(playerUuid); - userDb.saveProfiles(profiles); - } - } - - // Load SkyBlock profile data - ProfilesDatabase profileDb = new ProfilesDatabase(profileId.toString()); - SkyBlockDataHandler handler; - boolean shouldPersistProfile = false; - - if (profileDb.exists()) { - Document profileDocument = profileDb.getDocument(); - handler = SkyBlockDataHandler.createFromProfile(playerUuid, profileId, profileDocument); - } else { - handler = SkyBlockDataHandler.initUserWithDefaultData(playerUuid, profileId); - shouldPersistProfile = true; - } - - DatapointUUID islandDatapoint = handler.get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class); - UUID islandUUID = islandDatapoint.getValue(); - if (islandUUID == null) { - islandUUID = profileId; - islandDatapoint.setValue(islandUUID); - shouldPersistProfile = true; - } - - DatapointString profileNameDatapoint = handler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class); - if (Objects.equals(profileNameDatapoint.getValue(), "null")) { - profileNameDatapoint.setValue(SkyBlockPlayerProfiles.getRandomName()); - shouldPersistProfile = true; - } - - // Put in SkyBlock cache - SkyBlockDataHandler.skyBlockCache.put(playerUuid, handler); - - if (shouldPersistProfile) { - profileDb.saveDocument(handler.toProfileDocument()); - } - - // Set up the island after the cache is populated so island init can see the player as loaded - SkyBlockIsland island = (SkyBlockIsland.getIsland(islandUUID) == null) - ? new SkyBlockIsland(islandUUID, profileId) - : SkyBlockIsland.getIsland(islandUUID); - player.setSkyBlockIsland(island); - - Logger.info("Successfully loaded SkyBlock (profile " + profileId + ") for: " + player.getUsername()); + SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); + PlayerFlow.run(player, "skyblock-data/load-profile", () -> SkyBlockPlayerDataFlow.load(player)); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataSave.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataSave.java index 3d69e46fb..11a165adb 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataSave.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataSave.java @@ -2,49 +2,20 @@ import lombok.SneakyThrows; import net.minestom.server.event.player.PlayerDisconnectEvent; -import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.generic.user.flow.PlayerFlow; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import org.bson.Document; -import org.tinylog.Logger; - -import java.util.UUID; - -import static com.mongodb.client.model.Filters.eq; +import net.swofty.type.skyblockgeneric.user.flow.SkyBlockPlayerDataFlow; public class ActionPlayerSkyBlockDataSave implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.PERSIST, order = 10) public void run(PlayerDisconnectEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); - UUID playerUuid = player.getUuid(); - SkyBlockDataHandler handler = SkyBlockDataHandler.skyBlockCache.get(playerUuid); - - if (handler == null) return; - - Logger.info("Saving SkyBlock data for: " + player.getUsername() + "..."); - - // Run onSave for SkyBlock data - handler.runOnSave(player); - - // Save profile-scoped data to ProfilesDatabase - UUID profileId = handler.getCurrentProfileId(); - ProfilesDatabase profileDb = new ProfilesDatabase(profileId.toString()); - Document newDoc = handler.toProfileDocument(); - - if (profileDb.exists()) { - ProfilesDatabase.collection.replaceOne(eq("_id", profileId.toString()), newDoc); - } else { - ProfilesDatabase.collection.insertOne(newDoc); - } - - // Evict from SkyBlock cache - SkyBlockDataHandler.skyBlockCache.remove(playerUuid); - - Logger.info("Successfully saved SkyBlock (profile " + profileId + ") for: " + player.getUsername()); + PlayerFlow.run(player, "skyblock-data/save-profile", () -> SkyBlockPlayerDataFlow.save(player)); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerFall.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerFall.java index 7fe31b18d..6e832cd6a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerFall.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerFall.java @@ -5,14 +5,15 @@ import net.minestom.server.entity.damage.DamageType; import net.minestom.server.event.player.PlayerMoveEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerFall implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); Pos newPosition = event.getNewPosition(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerVoid.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerVoid.java index ce5282c45..040a68a38 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerVoid.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/fall/ActionPlayerVoid.java @@ -4,13 +4,14 @@ import net.minestom.server.entity.damage.DamageType; import net.minestom.server.event.player.PlayerMoveEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerVoid implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerMoveEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerClickItemUpdate.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerClickItemUpdate.java index df1cecc4a..6261b1175 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerClickItemUpdate.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerClickItemUpdate.java @@ -2,15 +2,16 @@ import net.minestom.server.event.inventory.InventoryItemChangeEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerClickItemUpdate implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(InventoryItemChangeEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getInventory().getViewers().stream().toList().getFirst(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java index 277d537ac..5327ba823 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java @@ -4,13 +4,14 @@ import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUICrafting; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerInteractWithCrafting implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(InventoryPreClickEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); @@ -18,10 +19,21 @@ public void run(InventoryPreClickEvent event) { if (event.getSlot() < 37 || event.getSlot() > 40) return; event.setCancelled(true); - player.addAndUpdateItem(player.getInventory().getCursorItem()); - player.getInventory().setCursorItem(ItemStack.AIR); - player.getInventory().update(); + ItemStack cursor = player.getInventory().getCursorItem(); + if (!cursor.isAir()) { + player.addAndUpdateItem(cursor); + player.getInventory().setCursorItem(ItemStack.AIR); + } + + // Rescue any item already sitting in the vanilla crafting slot — see #777 + ItemStack inSlot = player.getInventory().getItemStack(event.getSlot()); + if (!inSlot.isAir()) { + player.addAndUpdateItem(inSlot); + player.getInventory().setItemStack(event.getSlot(), ItemStack.AIR); + } + + player.getInventory().update(); player.openView(new GUICrafting()); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionArrowDamageMob.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionArrowDamageMob.java index 31c932fa8..baa23976c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionArrowDamageMob.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionArrowDamageMob.java @@ -6,8 +6,9 @@ import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.commons.skyblock.statistics.ItemStatistics; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.entity.ArrowEntityImpl; import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; @@ -19,7 +20,7 @@ public class PlayerActionArrowDamageMob implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(ProjectileCollideWithEntityEvent event) { ArrowEntityImpl arrow; if (event.getEntity() instanceof ArrowEntityImpl arrowEntity) @@ -70,4 +71,4 @@ public void run(ProjectileCollideWithEntityEvent event) { collidedWith.damage(new Damage(DamageType.PLAYER_ATTACK, player, player, player.getPosition(), (float) damage)); } } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamageMob.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamageMob.java index 494ef25a2..fe5fda5e8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamageMob.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamageMob.java @@ -11,8 +11,9 @@ import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.commons.skyblock.statistics.ItemStatistics; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.utility.MathUtility; import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; @@ -33,7 +34,7 @@ public class PlayerActionDamageMob implements HypixelEventClass { private static final Random random = new Random(); private static final Map COOLDOWN = new HashMap<>(); - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(EntityAttackEvent event) { if (event.getTarget().getEntityType().equals(EntityType.PLAYER)) return; if (!event.getEntity().getEntityType().equals(EntityType.PLAYER)) return; @@ -95,4 +96,4 @@ public void run(EntityAttackEvent event) { } } } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamagedAttacked.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamagedAttacked.java index 39a5255cc..813def025 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamagedAttacked.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamagedAttacked.java @@ -5,9 +5,11 @@ import net.minestom.server.event.entity.EntityAttackEvent; import net.swofty.commons.skyblock.statistics.ItemStatistics; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; import net.swofty.type.skyblockgeneric.event.value.SkyBlockValueEvent; import net.swofty.type.skyblockgeneric.event.value.events.PlayerDamagedByMobValueUpdateEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -18,7 +20,7 @@ public class PlayerActionDamagedAttacked implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ENTITY, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ENTITY, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(EntityAttackEvent event) { if (!event.getTarget().getEntityType().equals(EntityType.PLAYER)) return; @@ -38,6 +40,10 @@ public void run(EntityAttackEvent event) { ((SkyBlockPlayer) event.getTarget()).damage(new EntityDamage(mob, (float) valueEvent.getValue())); + if (mob instanceof SlayerBossMob slayerBoss) { + slayerBoss.getAbility().onMeleeHit(slayerBoss, (SkyBlockPlayer) event.getTarget()); + } + new DamageIndicator() .damage((float) valueEvent.getValue()) .pos(event.getTarget().getPosition()) diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandHandClick.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandHandClick.java index afd60d685..d1af0a98b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandHandClick.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandHandClick.java @@ -3,12 +3,13 @@ import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.player.PlayerHandAnimationEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionOffhandHandClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerHandAnimationEvent event) { if (event.getHand().equals(PlayerHand.OFF)) { event.getPlayer().sendMessage("§cYou cannot use your offhand!"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandItemClick.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandItemClick.java index 5ffc38fbc..e90142851 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandItemClick.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/offhand/ActionOffhandItemClick.java @@ -2,11 +2,12 @@ import net.minestom.server.event.player.PlayerSwapItemEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionOffhandItemClick implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerSwapItemEvent event) { event.getPlayer().sendMessage("§cYou cannot use your offhand!"); event.setCancelled(true); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockBreak.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockBreak.java index 346b13229..fa882ad2d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockBreak.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockBreak.java @@ -10,8 +10,9 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.event.HypixelEventHandler; import net.swofty.type.skyblockgeneric.entity.DroppedItemEntityImpl; import net.swofty.type.skyblockgeneric.event.custom.CustomBlockBreakEvent; @@ -29,7 +30,7 @@ public class ActionRegionBlockBreak implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockBreakEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); final ItemStack stack = event.getPlayer().getItemInMainHand(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java index 7eba8c51a..b28c26386 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java @@ -5,8 +5,9 @@ import net.minestom.server.tag.Tag; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.generic.utility.MathUtility; @@ -14,7 +15,7 @@ public class ActionRegionBlockPlace implements HypixelEventClass { private static final int ISLAND_SIZE = 161; private static final Tag PLAYER_PLACED_TAG = Tag.Boolean("player_placed"); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockPlaceEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/race/RaceEvents.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/race/RaceEvents.java index 3b76e3c57..8418e1658 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/race/RaceEvents.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/race/RaceEvents.java @@ -8,8 +8,9 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.race.RaceInstance; import net.swofty.type.skyblockgeneric.race.RaceManager; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -21,7 +22,7 @@ public class RaceEvents implements HypixelEventClass { private final HashMap lastClickedTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerJoin(PlayerSpawnEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!(HypixelConst.getTypeLoader() instanceof RaceInstance raceInstance)) { @@ -33,7 +34,7 @@ public void onPlayerJoin(PlayerSpawnEvent event) { race.updateForPlayer(HypixelConst.getInstanceContainer(), player); } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onPlayerDisconnect(PlayerDisconnectEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!(HypixelConst.getTypeLoader() instanceof RaceInstance raceInstance)) { @@ -45,7 +46,7 @@ public void onPlayerDisconnect(PlayerDisconnectEvent event) { race.cancelRace(player); } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void onPlayerMove(PlayerMoveEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (!(HypixelConst.getTypeLoader() instanceof RaceInstance raceInstance)) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandFetchedFromDatabaseEvent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandFetchedFromDatabaseEvent.java deleted file mode 100644 index b10feab42..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandFetchedFromDatabaseEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.swofty.type.skyblockgeneric.event.custom; - -import lombok.Getter; -import net.minestom.server.event.Event; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; - -import java.util.List; -import java.util.UUID; - -@Getter -public class IslandFetchedFromDatabaseEvent implements Event { - private final SkyBlockIsland island; - private final boolean isCoop; - private final List membersOnline; - private final List allMembers; - - public IslandFetchedFromDatabaseEvent(SkyBlockIsland island, boolean isCoop, List membersOnline, List allMembers) { - this.island = island; - this.isCoop = isCoop; - this.membersOnline = membersOnline; - this.allMembers = allMembers; - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandFirstCreatedEvent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandFirstCreatedEvent.java deleted file mode 100644 index 86c297215..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandFirstCreatedEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.swofty.type.skyblockgeneric.event.custom; - -import lombok.Getter; -import net.minestom.server.event.Event; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; - -import java.util.List; -import java.util.UUID; - -@Getter -public class IslandFirstCreatedEvent implements Event { - private final SkyBlockIsland island; - private final boolean isCoop; - private final List allMembers; - - public IslandFirstCreatedEvent(SkyBlockIsland island, boolean isCoop, List allMembers) { - this.island = island; - this.isCoop = isCoop; - this.allMembers = allMembers; - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandPlayerLoadedEvent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandPlayerLoadedEvent.java deleted file mode 100644 index 4d182334d..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandPlayerLoadedEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.swofty.type.skyblockgeneric.event.custom; - -import lombok.Getter; -import net.minestom.server.event.Event; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; - -import java.util.List; -import java.util.UUID; - -@Getter -public class IslandPlayerLoadedEvent implements Event { - private final SkyBlockIsland island; - private final SkyBlockPlayer player; - private final boolean isCoop; - private final List membersOnline; - private final List allMembers; - - public IslandPlayerLoadedEvent(SkyBlockIsland island, SkyBlockPlayer player, boolean isCoop, List membersOnline, List allMembers) { - this.island = island; - this.player = player; - this.isCoop = isCoop; - this.membersOnline = membersOnline; - this.allMembers = allMembers; - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandSavedIntoDatabaseEvent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandSavedIntoDatabaseEvent.java deleted file mode 100644 index c05c46ae6..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/custom/IslandSavedIntoDatabaseEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.swofty.type.skyblockgeneric.event.custom; - -import lombok.Getter; -import net.minestom.server.event.Event; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; - -import java.util.List; -import java.util.UUID; - -@Getter -public class IslandSavedIntoDatabaseEvent implements Event { - private final SkyBlockIsland island; - private final boolean isCoop; - private final List allMembers; - - public IslandSavedIntoDatabaseEvent(SkyBlockIsland island, boolean isCoop, List allMembers) { - this.island = island; - this.isCoop = isCoop; - this.allMembers = allMembers; - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java new file mode 100644 index 000000000..d2d02c305 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +public record FishingContext( + SkyBlockPlayer player, + SkyBlockItem rod, + FishingMedium medium, + @Nullable FishingBaitComponent bait, + @Nullable FishingRodPartComponent hook, + @Nullable FishingRodPartComponent line, + @Nullable FishingRodPartComponent sinker, + @Nullable String regionId, + Pos hookPosition, + boolean hotspotActive, + ItemStatistics hotspotBuffs, + long castDurationMs +) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingMedium.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingMedium.java new file mode 100644 index 000000000..c9b135f64 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingMedium.java @@ -0,0 +1,30 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.minestom.server.instance.block.Block; +import org.jetbrains.annotations.Nullable; + +public enum FishingMedium { + WATER, + LAVA; + + public boolean matches(Block block) { + if (block == null || !block.isLiquid()) { + return false; + } + + String blockName = block.name(); + return switch (this) { + case WATER -> blockName.contains("water"); + case LAVA -> blockName.contains("lava"); + }; + } + + public static @Nullable FishingMedium fromBlock(Block block) { + for (FishingMedium medium : values()) { + if (medium.matches(block)) { + return medium; + } + } + return null; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java new file mode 100644 index 000000000..0c3b318fc --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java @@ -0,0 +1,169 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.skyblockgeneric.entity.FishingHook; +import net.swofty.type.skyblockgeneric.fishing.bait.FishingBaitService; +import net.swofty.type.skyblockgeneric.fishing.catches.CatchAwardContext; +import net.swofty.type.skyblockgeneric.fishing.catches.CatchPayload; +import net.swofty.type.skyblockgeneric.fishing.hotspot.FishingHotspotService; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.resolver.FishingCatchResolver; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingRodPartService; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingService { + private static final Map SESSIONS = new ConcurrentHashMap<>(); + + public static FishingSession beginCast(SkyBlockPlayer player, SkyBlockItem rod, FishingMedium medium) { + FishingBaitComponent bait = FishingBaitService.getFirstAvailableBait(player, medium); + FishingSession session = new FishingSession( + player.getUuid(), + rod.getAttributeHandler().getPotentialType().name(), + medium, + bait == null ? null : bait.getItemId(), + System.currentTimeMillis(), + 0L, + 0L, + false, + false + ); + SESSIONS.put(player.getUuid(), session); + return session; + } + + public static @Nullable FishingSession getSession(UUID playerUuid) { + return SESSIONS.get(playerUuid); + } + + public static void updateSession(FishingSession session) { + SESSIONS.put(session.ownerUuid(), session); + } + + public static void clearSession(UUID playerUuid) { + SESSIONS.remove(playerUuid); + } + + public static long computeWaitTicks(SkyBlockPlayer player, SkyBlockItem rod, @Nullable FishingBaitComponent bait) { + double fishingSpeed = player.getStatistics().allStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED) + + rod.getAttributeHandler().getStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED) + + FishingRodPartService.getStatistics(rod).getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED); + if (bait != null) { + SkyBlockItem baitItem = FishingItemSupport.getItem(bait.getItemId()); + if (baitItem != null) { + fishingSpeed += baitItem.getAttributeHandler().getStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED); + } + if ("CORRUPTED_BAIT".equals(bait.getItemId())) { + fishingSpeed /= 2.0D; + } + } + long baseTicks = 80L; + return Math.max(20L, Math.round(baseTicks - Math.min(50D, fishingSpeed / 2D))); + } + + public static @Nullable CatchPayload resolveCatch(SkyBlockPlayer player, SkyBlockItem rod, FishingHook hook) { + FishingSession session = getSession(player.getUuid()); + if (session == null || session.resolved()) { + return null; + } + + FishingBaitComponent bait = FishingItemSupport.getBait(session.baitItemId()); + SkyBlockRegion region = player.getRegion(); + var hotspotBuffs = FishingHotspotService.getActiveHotspotBuffs(player, session.medium(), hook.getSpawnPosition()); + boolean hotspotActive = hasAnyBuffValue(hotspotBuffs); + FishingContext context = new FishingContext( + player, + rod, + session.medium(), + bait, + FishingRodPartService.getHook(rod), + FishingRodPartService.getLine(rod), + FishingRodPartService.getSinker(rod), + region == null ? null : region.getType().name(), + hook.getSpawnPosition(), + hotspotActive, + hotspotBuffs, + System.currentTimeMillis() - session.castAt() + ); + + CatchPayload payload = FishingCatchResolver.resolve(context); + if (payload == null) { + return null; + } + + consumeBait(player, rod, session); + awardCatch(player, rod, hook, payload); + updateSession(session.withResolved(true)); + return payload; + } + + private static void consumeBait(SkyBlockPlayer player, SkyBlockItem rod, FishingSession session) { + if (session.baitItemId() == null) { + return; + } + if (rollBaitPreservation(rod)) { + return; + } + FishingBaitService.consumeOneBait(player, session.baitItemId()); + } + + private static boolean rollBaitPreservation(SkyBlockItem rod) { + var caster = rod.getAttributeHandler().getEnchantment(net.swofty.type.skyblockgeneric.enchantment.EnchantmentType.CASTER); + if (caster != null && Math.random() * 100 < caster.level()) { + return true; + } + FishingRodPartComponent sinker = FishingRodPartService.getSinker(rod); + return sinker != null + && sinker.getBaitPreservationChance() > 0 + && Math.random() * 100 < sinker.getBaitPreservationChance(); + } + + private static void awardCatch(SkyBlockPlayer player, SkyBlockItem rod, FishingHook hook, CatchPayload payload) { + markFirstFishToggle(player); + rollSinkerMaterialize(player, rod); + + payload.apply(new CatchAwardContext(player, rod, hook.getSpawnPosition())); + + if (!(payload instanceof CatchPayload.SeaCreature) && payload.skillXp() > 0) { + player.getSkills().increase(player, net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING, payload.skillXp()); + } + + player.setItemInHand(rod); + } + + private static void markFirstFishToggle(SkyBlockPlayer player) { + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_CAUGHT_FIRST_FISH)) { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_CAUGHT_FIRST_FISH, true); + } + } + + private static void rollSinkerMaterialize(SkyBlockPlayer player, SkyBlockItem rod) { + FishingRodPartComponent sinker = FishingRodPartService.getSinker(rod); + if (sinker == null || sinker.getMaterializedItemId() == null) { + return; + } + if (Math.random() <= sinker.getMaterializedChance()) { + player.addAndUpdateItem(net.swofty.commons.skyblock.item.ItemType.valueOf(sinker.getMaterializedItemId())); + } + } + + private static boolean hasAnyBuffValue(net.swofty.commons.skyblock.statistics.ItemStatistics statistics) { + for (net.swofty.commons.skyblock.statistics.ItemStatistic statistic : net.swofty.commons.skyblock.statistics.ItemStatistic.values()) { + if (statistics.getOverall(statistic) != 0.0D) { + return true; + } + } + return false; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingSession.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingSession.java new file mode 100644 index 000000000..41ce6ec9f --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingSession.java @@ -0,0 +1,28 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import java.util.UUID; +import org.jetbrains.annotations.Nullable; + +public record FishingSession( + UUID ownerUuid, + String rodItemId, + FishingMedium medium, + @Nullable String baitItemId, + long castAt, + long biteReadyAt, + long biteWindowEndsAt, + boolean biteReady, + boolean resolved +) { + public FishingSession withBiteTiming(long readyAt, long windowEndsAt) { + return new FishingSession(ownerUuid, rodItemId, medium, baitItemId, castAt, readyAt, windowEndsAt, biteReady, resolved); + } + + public FishingSession withBiteReady(boolean ready) { + return new FishingSession(ownerUuid, rodItemId, medium, baitItemId, castAt, biteReadyAt, biteWindowEndsAt, ready, resolved); + } + + public FishingSession withResolved(boolean nextResolved) { + return new FishingSession(ownerUuid, rodItemId, medium, baitItemId, castAt, biteReadyAt, biteWindowEndsAt, biteReady, nextResolved); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/bait/FishingBaitService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/bait/FishingBaitService.java new file mode 100644 index 000000000..d63975ffd --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/bait/FishingBaitService.java @@ -0,0 +1,58 @@ +package net.swofty.type.skyblockgeneric.fishing.bait; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.minestom.server.item.ItemStack; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingBaitService { + + public static @Nullable FishingBaitComponent getFirstAvailableBait(SkyBlockPlayer player, FishingMedium medium) { + for (int slot = 0; slot < 36; slot++) { + SkyBlockItem item = new SkyBlockItem(player.getInventory().getItemStack(slot)); + ItemType type = item.getAttributeHandler().getPotentialType(); + if (type == null) { + continue; + } + + FishingBaitComponent baitComponent = item.getComponent(FishingBaitComponent.class); + if (baitComponent == null) { + continue; + } + if (!baitComponent.getMediums().isEmpty() && !baitComponent.getMediums().contains(medium)) { + continue; + } + return baitComponent; + } + return null; + } + + public static boolean consumeOneBait(SkyBlockPlayer player, String baitItemId) { + for (int slot = 0; slot < 36; slot++) { + SkyBlockItem item = new SkyBlockItem(player.getInventory().getItemStack(slot)); + if (item.getAttributeHandler().getPotentialType() == null) { + continue; + } + if (!item.getAttributeHandler().getPotentialType().name().equals(baitItemId)) { + continue; + } + + if (item.getAmount() > 1) { + item.setAmount(item.getAmount() - 1); + player.getInventory().setItemStack(slot, PlayerItemUpdater.playerUpdate(player, item.getItemStack()).build()); + } else { + player.getInventory().setItemStack(slot, ItemStack.AIR); + } + return true; + } + return false; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/CatchAwardContext.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/CatchAwardContext.java new file mode 100644 index 000000000..a117300a8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/CatchAwardContext.java @@ -0,0 +1,14 @@ +package net.swofty.type.skyblockgeneric.fishing.catches; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +/** + * Side-effect surface a {@link CatchPayload} sees when it's applied. + * Keeps the payload variants free of FishingHook coupling while still + * giving them everything they need (player, the rod that pulled them + * up, and the bobber position for spawn placement). + */ +public record CatchAwardContext(SkyBlockPlayer player, SkyBlockItem rod, Pos hookPosition) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/CatchPayload.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/CatchPayload.java new file mode 100644 index 000000000..aff39b4b1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/CatchPayload.java @@ -0,0 +1,123 @@ +package net.swofty.type.skyblockgeneric.fishing.catches; + +import net.kyori.adventure.text.Component; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointCollection; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointTrophyFish; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.seacreature.SeaCreatureSpawner; +import net.swofty.type.skyblockgeneric.fishing.FishingService; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.List; + +/** + * Sealed view of what the rod can pull out of the water. Each variant + * carries exactly its own fields — no bag of nullable @Nullable strings — + * and owns its own {@link #apply(CatchAwardContext)} so the FishingService + * dispatches by polymorphism rather than switch-on-kind. + */ +public sealed interface CatchPayload { + + /** Fishing skill XP to award; sea creatures intentionally return 0 (their kill awards XP separately). */ + double skillXp(); + + /** Short human label for telemetry / chat — variants pick the format. */ + String summary(); + + /** Run the catch's side-effects on the player. */ + void apply(CatchAwardContext ctx); + + /* ------------------------------------------------------------------ */ + /* Variants */ + /* ------------------------------------------------------------------ */ + + record Multi(List payloads) implements CatchPayload { + @Override public double skillXp() { return payloads.stream().mapToDouble(CatchPayload::skillXp).sum(); } + @Override public String summary() { return payloads.stream().map(CatchPayload::summary).toList().toString(); } + @Override public void apply(CatchAwardContext ctx) { payloads.forEach(payload -> payload.apply(ctx)); } + } + + record Item(String itemId, int amount, double skillXp, boolean fromTreasure) implements CatchPayload { + @Override public String summary() { return (fromTreasure ? "treasure " : "") + amount + "x " + itemId; } + + @Override + public void apply(CatchAwardContext ctx) { + ItemType type = ItemType.valueOf(itemId); + ctx.player().addAndUpdateItem(type, amount); + ctx.player().getCollection().increase(type, amount); + ctx.player().getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.COLLECTION, DatapointCollection.class) + .setValue(ctx.player().getCollection()); + + String prefix = fromTreasure ? "§b§lTREASURE! §7" : "§b§lGOOD CATCH! §7"; + ctx.player().sendMessage(Component.text(prefix + "You found " + amount + "x §a" + itemId + "§7!")); + } + } + + record SeaCreature(String seaCreatureId, double skillXp, int spawnCount) implements CatchPayload { + public SeaCreature(String seaCreatureId, double skillXp) { + this(seaCreatureId, skillXp, 1); + } + + public SeaCreature withDoubleHook() { + return new SeaCreature(seaCreatureId, skillXp, 2); + } + + @Override public String summary() { + return spawnCount > 1 ? "double-hook " + seaCreatureId : "sea creature " + seaCreatureId; + } + + @Override + public void apply(CatchAwardContext ctx) { + if (spawnCount > 1) { + ctx.player().sendMessage(net.kyori.adventure.text.Component.text("§a§lDOUBLE HOOK!")); + } + for (int i = 0; i < spawnCount; i++) { + SeaCreatureSpawner.spawn(ctx.player(), seaCreatureId, ctx.hookPosition()); + } + } + } + + record TrophyFish(String definitionId, TrophyTier tier, String itemId, double skillXp) implements CatchPayload { + @Override public String summary() { return "trophy " + tier.name() + " " + definitionId; } + + @Override + public void apply(CatchAwardContext ctx) { + ItemType type = ItemType.valueOf(itemId); + ctx.player().addAndUpdateItem(type, 1); + + DatapointTrophyFish.TrophyFishData data = ctx.player().getTrophyFishData(); + data.getProgress(definitionId).increment(tier.name()); + ctx.player().getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.TROPHY_FISH, DatapointTrophyFish.class) + .setValue(data); + + ctx.player().sendMessage(Component.text("§b§lTROPHY FISH! §7You reeled in a " + + tier.colour() + tier.displayName() + " §a" + definitionId + "§7!")); + } + } + + record Quest(String itemId, int amount, double skillXp, String message) implements CatchPayload { + @Override public String summary() { return "quest " + itemId; } + + @Override + public void apply(CatchAwardContext ctx) { + ctx.player().addAndUpdateItem(ItemType.valueOf(itemId), amount); + ctx.player().sendMessage(Component.text("§d§lQUEST CATCH! §7" + message)); + } + } + + record Special(String itemId, int amount, double skillXp, boolean corrupted) implements CatchPayload { + @Override public String summary() { return "special " + itemId; } + + @Override + public void apply(CatchAwardContext ctx) { + ItemType type = ItemType.valueOf(itemId); + ctx.player().addAndUpdateItem(type, amount); + ctx.player().getCollection().increase(type, amount); + String prefix = corrupted ? "§5§lCORRUPTED! §7" : "§d§lWONDROUS CATCH! §7"; + ctx.player().sendMessage(Component.text(prefix + "You found §a" + itemId + "§7!")); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/TrophyTier.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/TrophyTier.java new file mode 100644 index 000000000..dfaeeebb8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/catches/TrophyTier.java @@ -0,0 +1,49 @@ +package net.swofty.type.skyblockgeneric.fishing.catches; + +import java.util.List; +import java.util.Optional; + +/** + * Enumerated trophy fish tier. Replaces the previous stringly-typed + * deduction that scanned item IDs for "_DIAMOND"/"_GOLD" substrings. + */ +public enum TrophyTier { + BRONZE("§c", "Bronze"), + SILVER("§7", "Silver"), + GOLD("§6", "Gold"), + DIAMOND("§b", "Diamond"); + + private final String colour; + private final String displayName; + + TrophyTier(String colour, String displayName) { + this.colour = colour; + this.displayName = displayName; + } + + public String colour() { + return colour; + } + + public String displayName() { + return displayName; + } + + public String suffix() { + return "_" + name(); + } + + public static Optional fromItemId(String itemId) { + if (itemId == null) return Optional.empty(); + for (TrophyTier tier : values()) { + if (itemId.contains(tier.suffix())) { + return Optional.of(tier); + } + } + return Optional.empty(); + } + + public static List orderedDescending() { + return List.of(DIAMOND, GOLD, SILVER, BRONZE); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/hotspot/FishingHotspotService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/hotspot/FishingHotspotService.java new file mode 100644 index 000000000..6a3d57322 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/hotspot/FishingHotspotService.java @@ -0,0 +1,79 @@ +package net.swofty.type.skyblockgeneric.fishing.hotspot; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.registry.FishingRegistry; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingRodPartService; +import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingHotspotService { + private static final double HOTSPOT_RADIUS_SQUARED = 25.0D; + + public static boolean isBobberInHotspot(SkyBlockPlayer player, FishingMedium medium, Pos bobberPos) { + ItemStatistics buffs = getActiveHotspotBuffs(player, medium, bobberPos); + for (ItemStatistic statistic : ItemStatistic.values()) { + if (buffs.getOverall(statistic) != 0.0D) { + return true; + } + } + return false; + } + + public static ItemStatistics getActiveHotspotBuffs(SkyBlockPlayer player, FishingMedium medium, Pos bobberPos) { + String serverType = HypixelConst.getTypeLoader().getType().name(); + SkyBlockRegion playerRegion = player.getRegion(); + String regionId = playerRegion == null ? null : playerRegion.getType().name(); + double sinkerMultiplier = 1.0D; + if (player.getItemInMainHand() != null) { + var heldItem = new net.swofty.type.skyblockgeneric.item.SkyBlockItem(player.getItemInMainHand()); + var sinker = FishingRodPartService.getSinker(heldItem); + if (sinker != null && sinker.getHotspotBuffMultiplier() > 0) { + sinkerMultiplier = sinker.getHotspotBuffMultiplier(); + } + } + + ItemStatistics.Builder builder = ItemStatistics.builder(); + for (HotspotDefinition hotspot : FishingRegistry.getHotspots()) { + if (hotspot.medium() != medium) { + continue; + } + if (!hotspot.regions().isEmpty() && (regionId == null || !hotspot.regions().contains(regionId))) { + continue; + } + if (!matchesAnyPoint(serverType, bobberPos, hotspot)) { + continue; + } + + for (ItemStatistic statistic : ItemStatistic.values()) { + double value = hotspot.buffs().getOverall(statistic) * sinkerMultiplier; + if (value != 0.0D) { + builder.withBase(statistic, value); + } + } + } + return builder.build(); + } + + private static boolean matchesAnyPoint(String serverType, Pos bobberPos, HotspotDefinition hotspot) { + for (HotspotDefinition.SpawnPoint point : hotspot.spawnPoints()) { + if (point.serverType() != null && !point.serverType().equals(serverType)) { + continue; + } + double dx = bobberPos.x() - point.x(); + double dy = bobberPos.y() - point.y(); + double dz = bobberPos.z() - point.z(); + if ((dx * dx) + (dy * dy) + (dz * dz) <= HOTSPOT_RADIUS_SQUARED) { + return true; + } + } + return false; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/hotspot/HotspotDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/hotspot/HotspotDefinition.java new file mode 100644 index 000000000..dc48d70bf --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/hotspot/HotspotDefinition.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing.hotspot; + +import java.util.List; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; + +public record HotspotDefinition( + String id, + String displayName, + List regions, + FishingMedium medium, + int maxActive, + int durationSeconds, + ItemStatistics buffs, + List seaCreatureIds, + List spawnPoints +) { + public record SpawnPoint( + String serverType, + double x, + double y, + double z + ) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/item/FishingItemSupport.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/item/FishingItemSupport.java new file mode 100644 index 000000000..28e3f30f6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/item/FishingItemSupport.java @@ -0,0 +1,94 @@ +package net.swofty.type.skyblockgeneric.fishing.item; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.item.ConfigurableSkyBlockItem; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodMetadataComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingShipPartComponent; +import org.jetbrains.annotations.Nullable; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingItemSupport { + + public static @Nullable FishingRodMetadataComponent getRodMetadata(@Nullable String itemId) { + return getComponent(itemId, FishingRodMetadataComponent.class); + } + + public static @Nullable FishingBaitComponent getBait(@Nullable String itemId) { + return getComponent(itemId, FishingBaitComponent.class); + } + + public static @Nullable FishingRodPartComponent getRodPart(@Nullable String itemId) { + return getComponent(itemId, FishingRodPartComponent.class); + } + + public static @Nullable FishingShipPartComponent getShipPart(@Nullable String itemId) { + return getComponent(itemId, FishingShipPartComponent.class); + } + + public static @Nullable SkyBlockItem getItem(@Nullable String itemId) { + if (itemId == null || itemId.isBlank()) { + return null; + } + ItemType type = ItemType.get(itemId); + return type == null ? null : new SkyBlockItem(type); + } + + public static List getBaits() { + return getItemsWith(FishingBaitComponent.class); + } + + public static List getRodParts() { + return getItemsWith(FishingRodPartComponent.class); + } + + public static List getShipParts() { + return getItemsWith(FishingShipPartComponent.class); + } + + private static @Nullable T getComponent(@Nullable String itemId, Class componentClass) { + if (itemId == null || itemId.isBlank()) { + return null; + } + + ItemType type = ItemType.get(itemId); + if (type == null) { + return null; + } + + SkyBlockItem item = new SkyBlockItem(type); + if (!item.hasComponent(componentClass)) { + return null; + } + return item.getComponent(componentClass); + } + + private static List getItemsWith(Class componentClass) { + List items = new ArrayList<>(); + for (String id : ConfigurableSkyBlockItem.getIDs()) { + ItemType type = ItemType.get(id); + if (type == null) { + continue; + } + + SkyBlockItem item = new SkyBlockItem(type); + if (!item.hasComponent(componentClass)) { + continue; + } + items.add(item); + } + + items.sort(Comparator.comparingInt(item -> item.getAttributeHandler().getRarity().ordinal()) + .thenComparing(SkyBlockItem::getDisplayName)); + return List.copyOf(items); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/FishingRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/FishingRegistry.java new file mode 100644 index 000000000..eb33fca0c --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/FishingRegistry.java @@ -0,0 +1,396 @@ +package net.swofty.type.skyblockgeneric.fishing.registry; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import net.swofty.commons.ServerType; +import net.swofty.commons.YamlFileUtils; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.hotspot.HotspotDefinition; +import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingRegistry { + private static final File FISHING_DIR = new File("./configuration/skyblock/fishing"); + + private static final Map TABLES = new LinkedHashMap<>(); + private static final Map TROPHY_FISH = new LinkedHashMap<>(); + private static final Map SEA_CREATURES = new LinkedHashMap<>(); + private static final Map HOTSPOTS = new LinkedHashMap<>(); + + public static void loadAll() { + TABLES.clear(); + TROPHY_FISH.clear(); + SEA_CREATURES.clear(); + HOTSPOTS.clear(); + + if (!YamlFileUtils.ensureDirectoryExists(FISHING_DIR)) { + throw new IllegalStateException("Unable to create fishing configuration directory"); + } + + try { + loadTables(new File(FISHING_DIR, "tables.yml")); + loadTrophyFish(new File(FISHING_DIR, "trophy_fish.yml")); + loadSeaCreatures(new File(FISHING_DIR, "sea_creatures.yml")); + loadHotspots(new File(FISHING_DIR, "hotspots.yml")); + } catch (Exception exception) { + Logger.error(exception, "Failed to load fishing configuration"); + } + } + + public static @Nullable FishingTableDefinition getTable(String tableId) { + return TABLES.get(tableId); + } + + public static @Nullable TrophyFishDefinition getTrophyFish(String id) { + return TROPHY_FISH.get(id); + } + + public static @Nullable SeaCreatureDefinition getSeaCreature(String id) { + return SEA_CREATURES.get(id); + } + + + public static List getTables() { + return List.copyOf(TABLES.values()); + } + + public static List getHotspots() { + return List.copyOf(HOTSPOTS.values()); + } + + public static List getTrophyFish() { + return List.copyOf(TROPHY_FISH.values()); + } + + public static List getSeaCreatures() { + return List.copyOf(SEA_CREATURES.values()); + } + + + @SuppressWarnings("unchecked") + private static void loadTables(File file) throws IOException { + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("tables", Collections.emptyList()); + for (Map entry : entries) { + String id = string(entry, "id"); + TABLES.put(id, new FishingTableDefinition( + id, + stringList(entry.get("regions")), + parseMediums((List) entry.get("mediums")), + parseLootEntries((List>) entry.get("items")), + parseLootEntries((List>) entry.get("treasures")), + parseLootEntries((List>) entry.get("junk")), + parseSeaCreatureRolls((List>) entry.get("seaCreatures")) + )); + } + } + + @SuppressWarnings("unchecked") + private static void loadTrophyFish(File file) throws IOException { + if (!file.exists()) { + return; + } + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("trophyFish", Collections.emptyList()); + for (Map entry : entries) { + String id = string(entry, "id"); + TROPHY_FISH.put(id, new TrophyFishDefinition( + id, + string(entry, "displayName"), + doubleValue(entry, "catchChance", 0.0D), + stringList(entry.get("regions")), + intValue(entry, "requiredFishingLevel", 0), + longValue(entry, "minimumCastTimeMs", 0L), + nullableString(entry, "requiredRodId"), + nullableString(entry, "requiredBaitId"), + nullableDouble(entry.get("minimumMana")), + nullableDouble(entry.get("minimumBobberDepth")), + nullableDouble(entry.get("maximumPlayerDistance")), + booleanValue(entry, "requiresStarterRodWithoutEnchantments", false), + booleanValue(entry, "specialGoldenFish", false), + nullableString(entry, "bronzeItemId"), + nullableString(entry, "silverItemId"), + nullableString(entry, "goldItemId"), + nullableString(entry, "diamondItemId") + )); + } + } + + @SuppressWarnings("unchecked") + private static void loadSeaCreatures(File file) throws IOException { + if (!file.exists()) { + return; + } + + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("seaCreatures", Collections.emptyList()); + for (Map entry : entries) { + String id = string(entry, "id"); + SEA_CREATURES.put(id, new SeaCreatureDefinition( + id, + intValue(entry, "requiredFishingLevel", 0), + doubleValue(entry, "skillXp", 0.0D), + net.swofty.type.skyblockgeneric.fishing.tag.FishingTagRegistry.resolve(stringList(entry.get("tags"))) + )); + } + } + + @SuppressWarnings("unchecked") + private static void loadHotspots(File file) throws IOException { + if (!file.exists()) { + return; + } + + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("hotspots", Collections.emptyList()); + for (Map entry : entries) { + String serverType = normalizeServerType(nullableString(entry, "serverType")); + List> rawSpawnPoints = (List>) entry.get("spawnPoints"); + List spawnPoints = new ArrayList<>(); + if (rawSpawnPoints == null || rawSpawnPoints.isEmpty()) { + spawnPoints.add(new HotspotDefinition.SpawnPoint( + serverType, + doubleValue(entry.get("x"), 0.0D), + doubleValue(entry.get("y"), 0.0D), + doubleValue(entry.get("z"), 0.0D) + )); + } else { + for (Map spawnPoint : rawSpawnPoints) { + spawnPoints.add(new HotspotDefinition.SpawnPoint( + normalizeServerType(nullableString(spawnPoint, "serverType"), serverType), + doubleValue(spawnPoint.get("x"), 0.0D), + doubleValue(spawnPoint.get("y"), 0.0D), + doubleValue(spawnPoint.get("z"), 0.0D) + )); + } + } + + String id = nullableString(entry, "id"); + if (id == null || id.isBlank()) { + id = serverType + "_" + HOTSPOTS.size(); + } + + Map buffs = castMap(entry.get("buffs")); + HOTSPOTS.put(id, new HotspotDefinition( + id, + nullableString(entry, "displayName") == null ? "Hotspot" : nullableString(entry, "displayName"), + stringList(entry.get("regions")), + entry.containsKey("medium") ? FishingMedium.valueOf(String.valueOf(entry.get("medium")).toUpperCase()) : FishingMedium.WATER, + intValue(entry, "maxActive", defaultMaxActiveForServer(serverType)), + intValue(entry, "durationSeconds", 120), + parseStatistics(buffs, defaultHotspotBuffs()), + stringList(entry.get("seaCreatures")), + spawnPoints + )); + } + } + + + private static ItemStatistics parseStatistics(@Nullable Map values) { + return parseStatistics(values, Map.of()); + } + + private static ItemStatistics parseStatistics(@Nullable Map values, Map defaults) { + if (values == null || values.isEmpty()) { + if (defaults.isEmpty()) { + return ItemStatistics.empty(); + } + values = new LinkedHashMap<>(); + } + + Map mergedValues = new LinkedHashMap<>(); + defaults.forEach(mergedValues::put); + mergedValues.putAll(values); + + if (mergedValues.isEmpty()) { + return ItemStatistics.empty(); + } + + ItemStatistics.Builder builder = ItemStatistics.builder(); + for (Map.Entry entry : mergedValues.entrySet()) { + builder.withBase(ItemStatistic.valueOf(entry.getKey().toUpperCase()), doubleValue(entry.getValue(), 0.0D)); + } + return builder.build(); + } + + + private static List parseMediums(@Nullable List mediums) { + if (mediums == null || mediums.isEmpty()) { + return List.of(FishingMedium.WATER); + } + + List result = new ArrayList<>(); + for (Object value : mediums) { + result.add(FishingMedium.valueOf(String.valueOf(value).toUpperCase())); + } + return result; + } + + @SuppressWarnings("unchecked") + private static @Nullable Map castMap(@Nullable Object value) { + if (value instanceof Map map) { + return (Map) map; + } + return null; + } + + private static List stringList(@Nullable Object value) { + if (!(value instanceof List values) || values.isEmpty()) { + return List.of(); + } + + List result = new ArrayList<>(); + for (Object entry : values) { + result.add(String.valueOf(entry)); + } + return result; + } + + private static String string(Map values, String key) { + String value = nullableString(values, key); + if (value == null) { + throw new IllegalArgumentException("Missing fishing config key: " + key); + } + return value; + } + + private static @Nullable String nullableString(Map values, String key) { + return nullableString(values.get(key)); + } + + private static @Nullable String nullableString(@Nullable Object value) { + if (value == null) { + return null; + } + String stringValue = String.valueOf(value); + return stringValue.isBlank() ? null : stringValue; + } + + private static int intValue(Map values, String key, int defaultValue) { + return intValue(values.get(key), defaultValue); + } + + private static int intValue(@Nullable Object value, int defaultValue) { + if (value == null) { + return defaultValue; + } + return ((Number) value).intValue(); + } + + private static long longValue(Map values, String key, long defaultValue) { + return longValue(values.get(key), defaultValue); + } + + private static long longValue(@Nullable Object value, long defaultValue) { + if (value == null) { + return defaultValue; + } + return ((Number) value).longValue(); + } + + private static double doubleValue(Map values, String key, double defaultValue) { + return doubleValue(values.get(key), defaultValue); + } + + private static double doubleValue(@Nullable Object value, double defaultValue) { + if (value == null) { + return defaultValue; + } + return ((Number) value).doubleValue(); + } + + private static @Nullable Double nullableDouble(@Nullable Object value) { + if (value == null) { + return null; + } + return ((Number) value).doubleValue(); + } + + private static boolean booleanValue(Map values, String key, boolean defaultValue) { + return booleanValue(values.get(key), defaultValue); + } + + private static boolean booleanValue(@Nullable Object value, boolean defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Boolean bool) { + return bool; + } + return Boolean.parseBoolean(String.valueOf(value)); + } + + private static String normalizeServerType(@Nullable String serverType) { + return normalizeServerType(serverType, null); + } + + private static String normalizeServerType(@Nullable String serverType, @Nullable String fallback) { + String value = serverType == null || serverType.isEmpty() ? fallback : serverType; + if (value == null || value.isEmpty()) { + return ServerType.SKYBLOCK_HUB.name(); + } + return ServerType.getSkyblockServer(value).name(); + } + + private static int defaultMaxActiveForServer(String serverType) { + return switch (serverType) { + case "SKYBLOCK_HUB", "SKYBLOCK_BACKWATER_BAYOU" -> 2; + case "SKYBLOCK_SPIDERS_DEN" -> 1; + case "SKYBLOCK_CRIMSON_ISLE" -> 3; + default -> 1; + }; + } + + private static Map defaultHotspotBuffs() { + Map defaults = new LinkedHashMap<>(); + defaults.put("FISHING_SPEED", 15.0D); + defaults.put("SEA_CREATURE_CHANCE", 5.0D); + defaults.put("DOUBLE_HOOK_CHANCE", 2.0D); + defaults.put("TROPHY_FISH_CHANCE", 5.0D); + defaults.put("TREASURE_CHANCE", 1.0D); + return defaults; + } + + private static List parseLootEntries(@Nullable List> entries) { + if (entries == null || entries.isEmpty()) { + return List.of(); + } + + List result = new ArrayList<>(); + for (Map entry : entries) { + result.add(new FishingTableDefinition.LootEntry( + string(entry, "itemId"), + doubleValue(entry, "chance", 0.0D), + intValue(entry, "amount", 1), + doubleValue(entry, "skillXp", 0.0D) + )); + } + return result; + } + + private static List parseSeaCreatureRolls(@Nullable List> entries) { + if (entries == null || entries.isEmpty()) { + return List.of(); + } + + List result = new ArrayList<>(); + for (Map entry : entries) { + result.add(new FishingTableDefinition.SeaCreatureRoll( + string(entry, "seaCreatureId"), + doubleValue(entry, "chance", 0.0D) + )); + } + return result; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/FishingTableDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/FishingTableDefinition.java new file mode 100644 index 000000000..36b3dd77b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/FishingTableDefinition.java @@ -0,0 +1,20 @@ +package net.swofty.type.skyblockgeneric.fishing.registry; + +import java.util.List; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; + +public record FishingTableDefinition( + String id, + List regions, + List mediums, + List items, + List treasures, + List junk, + List seaCreatures +) { + public record LootEntry(String itemId, double chance, int amount, double skillXp) { + } + + public record SeaCreatureRoll(String seaCreatureId, double chance) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/SeaCreatureDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/SeaCreatureDefinition.java new file mode 100644 index 000000000..dc5cd1c3a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/SeaCreatureDefinition.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing.registry; + +import java.util.List; +import net.swofty.type.skyblockgeneric.fishing.FishingContext; +import net.swofty.type.skyblockgeneric.fishing.tag.FishingTag; + +public record SeaCreatureDefinition( + String id, + int requiredFishingLevel, + double skillXp, + List tags +) { + public boolean hasTag(FishingTag tag) { + return tags.contains(tag); + } + + public boolean isAvailable(FishingContext context) { + for (FishingTag tag : tags) { + if (!tag.isAvailable(context)) { + return false; + } + } + return true; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/TrophyFishDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/TrophyFishDefinition.java new file mode 100644 index 000000000..a9df79e4f --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/registry/TrophyFishDefinition.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing.registry; + +import java.util.List; +import org.jetbrains.annotations.Nullable; + +public record TrophyFishDefinition( + String id, + String displayName, + double catchChance, + List regions, + int requiredFishingLevel, + long minimumCastTimeMs, + @Nullable String requiredRodId, + @Nullable String requiredBaitId, + @Nullable Double minimumMana, + @Nullable Double minimumBobberDepth, + @Nullable Double maximumPlayerDistance, + boolean requiresStarterRodWithoutEnchantments, + boolean specialGoldenFish, + @Nullable String bronzeItemId, + @Nullable String silverItemId, + @Nullable String goldItemId, + @Nullable String diamondItemId +) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/resolver/FishingCatchResolver.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/resolver/FishingCatchResolver.java new file mode 100644 index 000000000..2db68a4c6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/resolver/FishingCatchResolver.java @@ -0,0 +1,15 @@ +package net.swofty.type.skyblockgeneric.fishing.resolver; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.type.skyblockgeneric.fishing.FishingContext; +import net.swofty.type.skyblockgeneric.fishing.catches.CatchPayload; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingCatchResolver { + + public static CatchPayload resolve(FishingContext context) { + return FishingLootResolver.resolve(context); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/resolver/FishingLootResolver.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/resolver/FishingLootResolver.java new file mode 100644 index 000000000..fa53febf5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/resolver/FishingLootResolver.java @@ -0,0 +1,313 @@ +package net.swofty.type.skyblockgeneric.fishing.resolver; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.skyblockgeneric.fishing.FishingContext; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.catches.CatchPayload; +import net.swofty.type.skyblockgeneric.fishing.catches.TrophyTier; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.registry.FishingRegistry; +import net.swofty.type.skyblockgeneric.fishing.registry.FishingTableDefinition; +import net.swofty.type.skyblockgeneric.fishing.registry.SeaCreatureDefinition; +import net.swofty.type.skyblockgeneric.fishing.registry.TrophyFishDefinition; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingRodPartService; +import net.swofty.type.skyblockgeneric.fishing.tag.FishingTag; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingLootResolver { + + private static final CatchPayload DEFAULT_CATCH = + new CatchPayload.Item("RAW_FISH", 1, 5.0D, false); + + public static CatchPayload resolve(FishingContext context) { + Optional questCatch = tryResolveQuestCatch(context); + if (questCatch.isPresent()) { + return questCatch.get(); + } + + Optional seaCreature = tryResolveSeaCreature(context); + Optional trophyFish = tryResolveTrophyFish(context); + if (seaCreature.isPresent() && trophyFish.isPresent()) { + return new CatchPayload.Multi(List.of(seaCreature.get(), trophyFish.get())); + } + if (seaCreature.isPresent()) { + return seaCreature.get(); + } + if (trophyFish.isPresent()) { + return trophyFish.get(); + } + return resolveItem(context); + } + + private static Optional tryResolveTrophyFish(FishingContext context) { + if (context.medium() != FishingMedium.LAVA) { + return Optional.empty(); + } + + double bonus = getTotalStatistic(context, ItemStatistic.TROPHY_FISH_CHANCE); + if (context.bait() != null) { + bonus += context.bait().getTrophyFishChanceBonus(); + } + + List eligible = new ArrayList<>(); + for (TrophyFishDefinition definition : FishingRegistry.getTrophyFish()) { + if (!isEligibleForTrophyFish(context, definition)) { + continue; + } + eligible.add(definition); + } + + eligible.sort(Comparator.comparingDouble(TrophyFishDefinition::catchChance).thenComparing(TrophyFishDefinition::id)); + for (TrophyFishDefinition definition : eligible) { + if (Math.random() * 100 <= effectiveTrophyChance(context, definition, bonus)) { + TrophyTier tier = rollTrophyTier(context, definition); + String itemId = switch (tier) { + case DIAMOND -> definition.diamondItemId(); + case GOLD -> definition.goldItemId(); + case SILVER -> definition.silverItemId(); + case BRONZE -> definition.bronzeItemId(); + }; + if (itemId == null) { + continue; + } + return Optional.of(new CatchPayload.TrophyFish(definition.id(), tier, itemId, 300.0D)); + } + } + + return Optional.empty(); + } + + private static boolean isEligibleForTrophyFish(FishingContext context, TrophyFishDefinition definition) { + if (!definition.regions().isEmpty() && (context.regionId() == null || !definition.regions().contains(context.regionId()))) { + return false; + } + if (context.player().getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < definition.requiredFishingLevel()) { + return false; + } + if (context.castDurationMs() < definition.minimumCastTimeMs()) { + return false; + } + if (definition.requiredRodId() != null && !definition.requiredRodId().equals(context.rod().getAttributeHandler().getPotentialType().name())) { + return false; + } + if (definition.requiredBaitId() != null && (context.bait() == null || !definition.requiredBaitId().equals(context.bait().getItemId()))) { + return false; + } + if (definition.requiresStarterRodWithoutEnchantments() + && (!"STARTER_LAVA_ROD".equals(context.rod().getAttributeHandler().getPotentialType().name()) + || context.rod().getAttributeHandler().getEnchantments().findAny().isPresent())) { + return false; + } + if (definition.minimumMana() != null && context.player().getMaxMana() < definition.minimumMana()) { + return false; + } + if (definition.minimumBobberDepth() != null && context.player().getPosition().y() - context.hookPosition().y() < definition.minimumBobberDepth()) { + return false; + } + if (definition.maximumPlayerDistance() != null && context.player().getPosition().distance(context.hookPosition()) > definition.maximumPlayerDistance()) { + return false; + } + return true; + } + + private static double effectiveTrophyChance(FishingContext context, TrophyFishDefinition definition, double bonus) { + if (!definition.specialGoldenFish()) { + if ("MANA_RAY".equals(definition.id())) { + return (context.player().getMaxMana() / 1000.0D) * (1.0D + bonus / 100.0D); + } + return definition.catchChance() * (1.0D + bonus / 100.0D); + } + long duration = context.castDurationMs(); + if (duration < 480_000L) { + return 0.0D; + } + return Math.min(100.0D, ((duration - 480_000L) / 240_000.0D) * 100.0D); + } + + private static Optional tryResolveQuestCatch(FishingContext context) { + if (context.medium() != FishingMedium.WATER) return Optional.empty(); + if (context.regionId() == null) return Optional.empty(); + if (!"FISHING_OUTPOST".equals(context.regionId()) && !"FISHERMANS_HUT".equals(context.regionId())) { + return Optional.empty(); + } + if (!context.player().getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID)) { + return Optional.empty(); + } + if (context.player().getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + return Optional.empty(); + } + if (context.player().getShipState().getEngine() != null) return Optional.empty(); + if (context.player().countItem(ItemType.RUSTY_SHIP_ENGINE) > 0) return Optional.empty(); + if (Math.random() * 100 > 1.0D) return Optional.empty(); + + return Optional.of(new CatchPayload.Quest( + ItemType.RUSTY_SHIP_ENGINE.name(), + 1, + 15.0D, + "You fished up a Rusty Ship Engine!" + )); + } + + private static TrophyTier rollTrophyTier(FishingContext context, TrophyFishDefinition definition) { + var progress = context.player().getTrophyFishData().getProgress(definition.id()); + if (progress.getTotalCatches() + 1 >= 600 && !progress.hasTier(TrophyTier.DIAMOND.name())) { + return TrophyTier.DIAMOND; + } + if (progress.getTotalCatches() + 1 >= 100 && !progress.hasTier(TrophyTier.GOLD.name())) { + return TrophyTier.GOLD; + } + + double charmBonus = 0.0D; + var charm = context.rod().getAttributeHandler().getEnchantment(net.swofty.type.skyblockgeneric.enchantment.EnchantmentType.CHARM); + if (charm != null) { + charmBonus = charm.level() * 2.0D; + } + + if (Math.random() <= (0.002D * (1 + charmBonus / 100D))) return TrophyTier.DIAMOND; + if (Math.random() <= (0.02D * (1 + charmBonus / 100D))) return TrophyTier.GOLD; + if (Math.random() <= (0.25D * (1 + charmBonus / 100D))) return TrophyTier.SILVER; + return TrophyTier.BRONZE; + } + + private static Optional tryResolveSeaCreature(FishingContext context) { + Optional tableOpt = findTable(context); + if (tableOpt.isEmpty()) return Optional.empty(); + FishingTableDefinition table = tableOpt.get(); + + double seaCreatureChance = getTotalStatistic(context, ItemStatistic.SEA_CREATURE_CHANCE); + if (context.hook() != null && context.hook().isTreasureOnly()) { + return Optional.empty(); + } + + for (FishingTableDefinition.SeaCreatureRoll roll : table.seaCreatures()) { + SeaCreatureDefinition definition = FishingRegistry.getSeaCreature(roll.seaCreatureId()); + if (definition != null && context.player().getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < definition.requiredFishingLevel()) { + continue; + } + if (definition != null && !definition.isAvailable(context)) { + continue; + } + double tagBonus = definition == null ? 0.0D : getTagBonus(context, definition.tags()); + if (Math.random() * 100 <= roll.chance() + seaCreatureChance + tagBonus) { + double skillXp = definition == null ? 0.0D : definition.skillXp(); + CatchPayload.SeaCreature payload = new CatchPayload.SeaCreature(roll.seaCreatureId(), skillXp); + if (rollDoubleHook(context)) { + payload = payload.withDoubleHook(); + } + return Optional.of(payload); + } + } + return Optional.empty(); + } + + private static CatchPayload resolveItem(FishingContext context) { + Optional tableOpt = findTable(context); + if (tableOpt.isEmpty()) return DEFAULT_CATCH; + FishingTableDefinition table = tableOpt.get(); + + List pool = table.items(); + double treasureChance = getTotalStatistic(context, ItemStatistic.TREASURE_CHANCE); + if (context.bait() != null) { + treasureChance += context.bait().getTreasureChanceBonus(); + } + if (context.sinker() != null && context.sinker().isBayouTreasureToJunk()) { + treasureChance += 10.0D; + } + + if (!table.treasures().isEmpty() && Math.random() * 100 <= treasureChance) { + pool = context.sinker() != null && context.sinker().isBayouTreasureToJunk() ? table.junk() : table.treasures(); + return pick(pool, true).orElse(DEFAULT_CATCH); + } + + return pick(pool, false) + .or(() -> table.junk().isEmpty() ? Optional.empty() : pick(table.junk(), false)) + .orElse(DEFAULT_CATCH); + } + + private static Optional pick(List pool, boolean fromTreasure) { + if (pool.isEmpty()) return Optional.empty(); + + double roll = Math.random() * 100; + double cursor = 0; + for (FishingTableDefinition.LootEntry entry : pool) { + cursor += entry.chance(); + if (roll <= cursor) { + return Optional.of(new CatchPayload.Item(entry.itemId(), entry.amount(), entry.skillXp(), fromTreasure)); + } + } + FishingTableDefinition.LootEntry first = pool.getFirst(); + return Optional.of(new CatchPayload.Item(first.itemId(), first.amount(), first.skillXp(), fromTreasure)); + } + + private static Optional findTable(FishingContext context) { + FishingTableDefinition fallback = null; + for (FishingTableDefinition definition : FishingRegistry.getTables()) { + if (!definition.mediums().isEmpty() && !definition.mediums().contains(context.medium())) { + continue; + } + if (context.regionId() != null && definition.regions().contains(context.regionId())) { + return Optional.of(definition); + } + if (definition.regions().isEmpty() && fallback == null) { + fallback = definition; + } + } + return Optional.ofNullable(fallback); + } + + private static boolean rollDoubleHook(FishingContext context) { + double chance = getTotalStatistic(context, ItemStatistic.DOUBLE_HOOK_CHANCE); + if (context.bait() != null) { + chance += context.bait().getDoubleHookChanceBonus(); + } + return chance > 0 && Math.random() * 100 <= chance; + } + + private static double getTotalStatistic(FishingContext context, ItemStatistic statistic) { + double total = context.rod().getAttributeHandler().getStatistics().getOverall(statistic) + + FishingRodPartService.getStatistics(context.rod()).getOverall(statistic); + total += context.hotspotBuffs().getOverall(statistic); + if (context.bait() != null) { + SkyBlockItem baitItem = FishingItemSupport.getItem(context.bait().getItemId()); + if (baitItem != null) { + total += baitItem.getAttributeHandler().getStatistics().getOverall(statistic); + } + } + return total; + } + + private static double getTagBonus(FishingContext context, List tags) { + double total = 0.0D; + if (context.hook() != null) { + total += getTagBonus(context.hook().getTagBonuses(), tags); + } + if (context.line() != null) { + total += getTagBonus(context.line().getTagBonuses(), tags); + } + if (context.sinker() != null) { + total += getTagBonus(context.sinker().getTagBonuses(), tags); + } + if (context.bait() != null) { + total += getTagBonus(context.bait().getTagBonuses(), tags); + } + return total; + } + + private static double getTagBonus(java.util.Map bonuses, List tags) { + double total = 0.0D; + for (FishingTag tag : tags) { + total += bonuses.getOrDefault(tag.id(), 0.0D); + } + return total; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingPartCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingPartCategory.java new file mode 100644 index 000000000..ab1a92069 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingPartCategory.java @@ -0,0 +1,7 @@ +package net.swofty.type.skyblockgeneric.fishing.rod; + +public enum FishingPartCategory { + HOOK, + LINE, + SINKER +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingRodLoreBuilder.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingRodLoreBuilder.java new file mode 100644 index 000000000..edd0dfb45 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingRodLoreBuilder.java @@ -0,0 +1,111 @@ +package net.swofty.type.skyblockgeneric.fishing.rod; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import net.swofty.commons.StringUtility; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.DefaultSoulboundComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodMetadataComponent; +import net.swofty.type.skyblockgeneric.item.components.GemstoneComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingRodLoreBuilder { + private static final List STAT_ORDER = List.of( + ItemStatistic.DAMAGE, + ItemStatistic.STRENGTH, + ItemStatistic.FEROCITY, + ItemStatistic.FISHING_SPEED, + ItemStatistic.SEA_CREATURE_CHANCE, + ItemStatistic.DOUBLE_HOOK_CHANCE, + ItemStatistic.TROPHY_FISH_CHANCE + ); + + public static @Nullable FishingRodLore build(SkyBlockItem item, @Nullable SkyBlockPlayer player) { + if (!item.hasComponent(FishingRodMetadataComponent.class)) { + return null; + } + + FishingRodMetadataComponent metadata = item.getComponent(FishingRodMetadataComponent.class); + List lore = new ArrayList<>(); + if (metadata.getSubtitle() != null && !metadata.getSubtitle().isBlank()) { + lore.add(metadata.getSubtitle()); + } + + for (ItemStatistic statistic : STAT_ORDER) { + double amount = item.getAttributeHandler().getStatistics().getOverall(statistic) + + FishingRodPartService.getStatistics(item).getOverall(statistic); + if (amount == 0.0D) { + continue; + } + lore.add(formatStatistic(statistic, amount)); + } + + if (item.hasComponent(GemstoneComponent.class)) { + lore.add(renderGemSlots(item.getComponent(GemstoneComponent.class))); + } + + lore.add(partLine("ථ Hook ", item.getAttributeHandler().getFishingHook())); + lore.add(partLine("ꨃ Line ", item.getAttributeHandler().getFishingLine())); + lore.add(partLine("࿉ Sinker ", item.getAttributeHandler().getFishingSinker())); + + if (metadata.getLegacyConversionTarget() != null) { + lore.add("Talk to Roddy in the Backwater"); + lore.add("Bayou to convert this rod."); + } else if (metadata.isRodPartsEnabled()) { + lore.add("Talk to Roddy in the Backwater"); + lore.add("Bayou to apply parts to this rod."); + } + + if (item.hasComponent(net.swofty.type.skyblockgeneric.item.components.ReforgableComponent.class)) { + lore.add("This item can be reforged!"); + } + if (metadata.getRequiredFishingLevel() > 0) { + lore.add("❣ Requires Fishing Skill " + metadata.getRequiredFishingLevel() + "."); + } + if (metadata.getExtraRequirements() != null) { + lore.addAll(metadata.getExtraRequirements()); + } + if (item.hasComponent(DefaultSoulboundComponent.class)) { + lore.add("* Co-op Soulbound *"); + } + + lore.add(item.getAttributeHandler().getRarity().getDisplay() + " FISHING ROD"); + return new FishingRodLore(item.getDisplayName(), lore); + } + + private static String renderGemSlots(GemstoneComponent gemstone) { + return gemstone.getSlots().stream() + .map(slot -> "[" + slot.slot().getSymbol() + "]") + .reduce((left, right) -> left + " " + right) + .orElse(""); + } + + private static String partLine(String prefix, @Nullable String itemId) { + if (itemId == null) { + return prefix + "NONE"; + } + ItemType type = ItemType.get(itemId); + return prefix + (type == null ? "NONE" : type.getDisplayName().replace("§", "")); + } + + private static String formatStatistic(ItemStatistic statistic, double amount) { + return statistic.getDisplayName() + ": " + statistic.getPrefix() + format(amount) + statistic.getSuffix(); + } + + private static String format(double value) { + if (Math.abs(value - Math.rint(value)) < 0.0001D) { + return String.valueOf((long) Math.rint(value)); + } + return StringUtility.decimalify(value, 1); + } + + public record FishingRodLore(String displayName, List lore) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingRodPartService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingRodPartService.java new file mode 100644 index 000000000..b7d64707a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingRodPartService.java @@ -0,0 +1,66 @@ +package net.swofty.type.skyblockgeneric.fishing.rod; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import org.jetbrains.annotations.Nullable; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingRodPartService { + + public static @Nullable FishingRodPartComponent getHook(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingHook()); + } + + public static @Nullable FishingRodPartComponent getLine(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingLine()); + } + + public static @Nullable FishingRodPartComponent getSinker(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingSinker()); + } + + public static ItemStatistics getStatistics(SkyBlockItem rod) { + ItemStatistics.Builder builder = ItemStatistics.builder(); + append(builder, getHook(rod)); + append(builder, getLine(rod)); + append(builder, getSinker(rod)); + return builder.build(); + } + + public static void applyPart(SkyBlockItem rod, FishingRodPartComponent part) { + switch (part.getCategory()) { + case HOOK -> rod.getAttributeHandler().setFishingHook(part.getItemId()); + case LINE -> rod.getAttributeHandler().setFishingLine(part.getItemId()); + case SINKER -> rod.getAttributeHandler().setFishingSinker(part.getItemId()); + } + } + + public static void removePart(SkyBlockItem rod, FishingPartCategory category) { + switch (category) { + case HOOK -> rod.getAttributeHandler().setFishingHook(null); + case LINE -> rod.getAttributeHandler().setFishingLine(null); + case SINKER -> rod.getAttributeHandler().setFishingSinker(null); + } + } + + private static void append(ItemStatistics.Builder builder, @Nullable FishingRodPartComponent definition) { + if (definition == null) { + return; + } + SkyBlockItem item = FishingItemSupport.getItem(definition.getItemId()); + if (item == null) { + return; + } + for (var statistic : net.swofty.commons.skyblock.statistics.ItemStatistic.values()) { + double amount = item.getAttributeHandler().getStatistics().getOverall(statistic); + if (amount != 0) { + builder.withBase(statistic, amount); + } + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingShipPartSlot.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingShipPartSlot.java new file mode 100644 index 000000000..80bae36fd --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/rod/FishingShipPartSlot.java @@ -0,0 +1,7 @@ +package net.swofty.type.skyblockgeneric.fishing.rod; + +public enum FishingShipPartSlot { + HELM, + ENGINE, + HULL +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ship/FishingShipService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ship/FishingShipService.java new file mode 100644 index 000000000..653a507a9 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ship/FishingShipService.java @@ -0,0 +1,33 @@ +package net.swofty.type.skyblockgeneric.fishing.ship; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointShipState; +import net.swofty.type.skyblockgeneric.item.components.FishingShipPartComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingShipService { + + public static DatapointShipState.ShipState getState(SkyBlockPlayer player) { + return player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).getValue(); + } + + public static void installPart(SkyBlockPlayer player, String itemId, FishingShipPartComponent definition) { + DatapointShipState.ShipState state = getState(player); + switch (definition.getSlot()) { + case HELM -> state.setHelm(itemId); + case ENGINE -> state.setEngine(itemId); + case HULL -> state.setHull(itemId); + } + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).setValue(state); + } + + public static void unlockDestination(SkyBlockPlayer player, String destinationId) { + DatapointShipState.ShipState state = getState(player); + state.unlockDestination(destinationId); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).setValue(state); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/EventTag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/EventTag.java new file mode 100644 index 000000000..5228e5f6c --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/EventTag.java @@ -0,0 +1,26 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +import java.util.function.BooleanSupplier; +import net.swofty.type.skyblockgeneric.fishing.FishingContext; + +/** + * Gates loot behind a server-wide event being active (Spooky Festival, + * Fishing Festival, etc.). The actual liveness check is supplied at + * construction so the tag layer doesn't depend on event-specific code. + */ +public record EventTag(String id, BooleanSupplier activeCheck) implements FishingTag { + + public static EventTag of(String id, BooleanSupplier activeCheck) { + return new EventTag(id, activeCheck); + } + + /** Convenience: a never-active event tag for entries pending implementation. */ + public static EventTag dormant(String id) { + return new EventTag(id, () -> false); + } + + @Override + public boolean isAvailable(FishingContext context) { + return activeCheck.getAsBoolean(); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/FishingTag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/FishingTag.java new file mode 100644 index 000000000..5fa48ee48 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/FishingTag.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +import net.swofty.type.skyblockgeneric.fishing.FishingContext; + +/** + * A trait attached to a sea creature, trophy fish, or fishing-rod component + * that the loot resolver can reason about (gating, tag-bonus stacking, etc.). + * + * The sealed hierarchy carries gating logic on each implementation so the + * resolver never has to look at string identifiers to decide whether a tag's + * condition holds — that's the implementor's job. + */ +public sealed interface FishingTag + permits MediumTag, TimeOfDayTag, WeatherTag, RegionTag, RarityTag, EventTag { + + String id(); + + /** + * @return true if this tag's environmental condition currently holds. + * Informational tags (regional, rarity) always return true. + */ + default boolean isAvailable(FishingContext context) { + return true; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/FishingTagRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/FishingTagRegistry.java new file mode 100644 index 000000000..8f8761a87 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/FishingTagRegistry.java @@ -0,0 +1,102 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; + +/** + * Central lookup mapping YAML tag ids to the typed FishingTag instances + * the resolver uses. Built-in tags are pre-registered; custom tags (events, + * project-specific regions) can be added via {@link #register}. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingTagRegistry { + + private static final Map TAGS = new LinkedHashMap<>(); + + static { + registerAll( + MediumTag.WATER, + MediumTag.LAVA, + TimeOfDayTag.NIGHT, + TimeOfDayTag.DAY, + TimeOfDayTag.DAWN, + TimeOfDayTag.DUSK, + WeatherTag.RAINING, + WeatherTag.CLEAR, + WeatherTag.THUNDERSTORM, + RegionTag.CRIMSON_ISLE, + RegionTag.BACKWATER_BAYOU, + RegionTag.GALATEA, + RegionTag.PRIVATE_ISLAND, + RegionTag.HUB, + RegionTag.THE_END, + RarityTag.COMMON, + RarityTag.UNCOMMON, + RarityTag.RARE, + RarityTag.EPIC, + RarityTag.LEGENDARY, + RarityTag.MYTHIC + ); + } + + public static void register(FishingTag tag) { + TAGS.put(tag.id(), tag); + } + + public static void registerAll(FishingTag... tags) { + for (FishingTag tag : tags) { + register(tag); + } + } + + public static @Nullable FishingTag get(String id) { + return TAGS.get(id); + } + + public static List all() { + return List.copyOf(TAGS.values()); + } + + public static Set ids() { + return Set.copyOf(TAGS.keySet()); + } + + /** + * Resolves a list of YAML tag identifiers into typed tags. Unknown + * identifiers are surfaced as informational {@link RegionTag} entries + * (rather than dropped) so config typos remain visible in catalogs and + * tag-bonus maps still match by id; the resolver simply treats them as + * always-available. + */ + public static List resolve(List ids) { + if (ids == null || ids.isEmpty()) { + return List.of(); + } + return ids.stream() + .map(FishingTagRegistry::resolveOrSynth) + .toList(); + } + + private static FishingTag resolveOrSynth(String id) { + FishingTag known = TAGS.get(id); + if (known != null) { + return known; + } + Logger.debug("Unknown fishing tag id '{}', synthesising info-only tag", id); + RegionTag synthetic = RegionTag.info(id); + TAGS.put(id, synthetic); + return synthetic; + } + + public static Stream stream() { + return TAGS.values().stream(); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/MediumTag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/MediumTag.java new file mode 100644 index 000000000..be4e3e290 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/MediumTag.java @@ -0,0 +1,20 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +import net.swofty.type.skyblockgeneric.fishing.FishingContext; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; + +public record MediumTag(FishingMedium medium) implements FishingTag { + + public static final MediumTag WATER = new MediumTag(FishingMedium.WATER); + public static final MediumTag LAVA = new MediumTag(FishingMedium.LAVA); + + @Override + public String id() { + return medium.name(); + } + + @Override + public boolean isAvailable(FishingContext context) { + return context.medium() == medium; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/RarityTag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/RarityTag.java new file mode 100644 index 000000000..3cba9580a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/RarityTag.java @@ -0,0 +1,14 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +/** + * Pure data tag — rarity is informational, never gates rolls. + */ +public record RarityTag(String id, int weight) implements FishingTag { + + public static final RarityTag COMMON = new RarityTag("COMMON", 0); + public static final RarityTag UNCOMMON = new RarityTag("UNCOMMON", 1); + public static final RarityTag RARE = new RarityTag("RARE", 2); + public static final RarityTag EPIC = new RarityTag("EPIC", 3); + public static final RarityTag LEGENDARY = new RarityTag("LEGENDARY", 4); + public static final RarityTag MYTHIC = new RarityTag("MYTHIC", 5); +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/RegionTag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/RegionTag.java new file mode 100644 index 000000000..071ca0d88 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/RegionTag.java @@ -0,0 +1,34 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +import java.util.Set; +import net.swofty.type.skyblockgeneric.fishing.FishingContext; + +/** + * Marks loot that's themed to one or more SkyBlock regions. Acts as a + * gate when {@code requireMatch} is true, otherwise informational only. + */ +public record RegionTag(String id, Set regionIds, boolean requireMatch) implements FishingTag { + + public static final RegionTag CRIMSON_ISLE = require("CRIMSON", Set.of("CRIMSON_ISLE", "DRAGONTAIL", "STRONGHOLD")); + public static final RegionTag BACKWATER_BAYOU = require("BAYOU", Set.of("BACKWATER_BAYOU")); + public static final RegionTag GALATEA = require("GALATEA", Set.of("GALATEA")); + public static final RegionTag PRIVATE_ISLAND = require("ISLAND", Set.of("PRIVATE_ISLAND")); + public static final RegionTag HUB = require("HUB", Set.of("HUB")); + public static final RegionTag THE_END = require("END", Set.of("THE_END", "DRAGONS_NEST")); + + public static RegionTag require(String id, Set regionIds) { + return new RegionTag(id, Set.copyOf(regionIds), true); + } + + public static RegionTag info(String id) { + return new RegionTag(id, Set.of(), false); + } + + @Override + public boolean isAvailable(FishingContext context) { + if (!requireMatch || regionIds.isEmpty()) { + return true; + } + return context.regionId() != null && regionIds.contains(context.regionId()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/TimeOfDayTag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/TimeOfDayTag.java new file mode 100644 index 000000000..b846fc179 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/TimeOfDayTag.java @@ -0,0 +1,18 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +import java.util.function.IntPredicate; +import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; +import net.swofty.type.skyblockgeneric.fishing.FishingContext; + +public record TimeOfDayTag(String id, IntPredicate hourPredicate) implements FishingTag { + + public static final TimeOfDayTag NIGHT = new TimeOfDayTag("NIGHT", hour -> hour < 6 || hour >= 20); + public static final TimeOfDayTag DAY = new TimeOfDayTag("DAY", hour -> hour >= 6 && hour < 20); + public static final TimeOfDayTag DAWN = new TimeOfDayTag("DAWN", hour -> hour >= 5 && hour < 8); + public static final TimeOfDayTag DUSK = new TimeOfDayTag("DUSK", hour -> hour >= 17 && hour < 20); + + @Override + public boolean isAvailable(FishingContext context) { + return hourPredicate.test(SkyBlockCalendar.getHour()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/WeatherTag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/WeatherTag.java new file mode 100644 index 000000000..4c802a829 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/tag/WeatherTag.java @@ -0,0 +1,30 @@ +package net.swofty.type.skyblockgeneric.fishing.tag; + +import net.minestom.server.instance.Instance; +import net.minestom.server.instance.Weather; +import net.swofty.type.skyblockgeneric.fishing.FishingContext; + +public record WeatherTag(String id, Condition condition) implements FishingTag { + + public static final WeatherTag RAINING = new WeatherTag("RAINING", Condition.RAINING); + public static final WeatherTag CLEAR = new WeatherTag("CLEAR", Condition.CLEAR); + public static final WeatherTag THUNDERSTORM = new WeatherTag("THUNDERSTORM", Condition.THUNDERSTORM); + + @Override + public boolean isAvailable(FishingContext context) { + Instance instance = context.player().getInstance(); + if (instance == null) { + return condition == Condition.CLEAR; + } + Weather weather = instance.getWeather(); + return switch (condition) { + case RAINING -> weather.rainLevel() > 0.0f; + case CLEAR -> weather.rainLevel() == 0.0f; + case THUNDERSTORM -> weather.thunderLevel() > 0.0f; + }; + } + + public enum Condition { + RAINING, CLEAR, THUNDERSTORM + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java index 789545486..c05580870 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java @@ -14,7 +14,7 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemsProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemsProtocol; import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionItem; import net.swofty.commons.skyblock.auctions.AuctionsFilter; @@ -63,8 +63,8 @@ public GUIAuctionBrowser() { } private void updateItemsCache() { - AuctionFetchItemsProtocolObject.AuctionFetchItemsMessage message = - new AuctionFetchItemsProtocolObject.AuctionFetchItemsMessage( + AuctionFetchItemsProtocol.AuctionFetchItemsMessage message = + new AuctionFetchItemsProtocol.AuctionFetchItemsMessage( sorting, filter, category @@ -72,7 +72,7 @@ private void updateItemsCache() { new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest(message) .thenAccept(responseRaw -> { - AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse response = (AuctionFetchItemsProtocolObject.AuctionFetchItemsResponse) responseRaw; + AuctionFetchItemsProtocol.AuctionFetchItemsResponse response = (AuctionFetchItemsProtocol.AuctionFetchItemsResponse) responseRaw; List auctionItems = response.items(); // Items are already sorted, so just paginate them diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionCreateItem.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionCreateItem.java index f4bf753f9..383d3d9db 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionCreateItem.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionCreateItem.java @@ -10,7 +10,7 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; -import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocol; import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionItem; import net.swofty.proxyapi.ProxyService; @@ -167,9 +167,9 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { player.sendMessage(I18n.t("gui_auction.create.setup_message")); - AuctionAddItemProtocolObject.AuctionAddItemMessage message = - new AuctionAddItemProtocolObject.AuctionAddItemMessage(item, category); - CompletableFuture future = + AuctionAddItemProtocol.AuctionAddItemMessage message = + new AuctionAddItemProtocol.AuctionAddItemMessage(item, category); + CompletableFuture future = auctionService.handleRequest(message); UUID auctionUUID = future.join().uuid(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionViewItem.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionViewItem.java index 186ba4496..3b2865826 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionViewItem.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionViewItem.java @@ -7,7 +7,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocol; import net.swofty.commons.skyblock.auctions.AuctionItem; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; @@ -50,9 +50,9 @@ public void onOpen(InventoryGUIOpenEvent e) { } public void updateItems() { - AuctionFetchItemProtocolObject.AuctionFetchItemMessage message = - new AuctionFetchItemProtocolObject.AuctionFetchItemMessage(auctionID); - CompletableFuture future = + AuctionFetchItemProtocol.AuctionFetchItemMessage message = + new AuctionFetchItemProtocol.AuctionFetchItemMessage(auctionID); + CompletableFuture future = new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest(message); AuctionItem item = future.join().item(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIManageAuctions.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIManageAuctions.java index ab2fb1ca7..1ff586d33 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIManageAuctions.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIManageAuctions.java @@ -9,7 +9,7 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocol; import net.swofty.commons.skyblock.auctions.AuctionItem; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; @@ -61,13 +61,13 @@ public void onOpen(InventoryGUIOpenEvent e) { public void setItems() { List auctions = ((SkyBlockPlayer) getPlayer()).getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.AUCTION_ACTIVE_OWNED, DatapointUUIDList.class).getValue(); - List> futures = new ArrayList<>(auctions.size()); + List> futures = new ArrayList<>(auctions.size()); PaginationList auctionItems = new PaginationList<>(7); auctions.forEach(uuid -> { - AuctionFetchItemProtocolObject.AuctionFetchItemMessage message = - new AuctionFetchItemProtocolObject.AuctionFetchItemMessage(uuid); - CompletableFuture future = + AuctionFetchItemProtocol.AuctionFetchItemMessage message = + new AuctionFetchItemProtocol.AuctionFetchItemMessage(uuid); + CompletableFuture future = new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest(message); future.thenAccept(response -> { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIViewBids.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIViewBids.java index 12af4dd70..641260b3a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIViewBids.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIViewBids.java @@ -9,7 +9,7 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocol; import net.swofty.commons.skyblock.auctions.AuctionItem; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; @@ -46,13 +46,13 @@ public void onOpen(InventoryGUIOpenEvent e) { public void setItems() { List auctions = ((SkyBlockPlayer) getPlayer()).getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.AUCTION_ACTIVE_BIDS, DatapointUUIDList.class).getValue(); - List> futures = new ArrayList<>(auctions.size()); + List> futures = new ArrayList<>(auctions.size()); PaginationList auctionItems = new PaginationList<>(7); auctions.forEach(uuid -> { - AuctionFetchItemProtocolObject.AuctionFetchItemMessage message = - new AuctionFetchItemProtocolObject.AuctionFetchItemMessage(uuid); - CompletableFuture future = + AuctionFetchItemProtocol.AuctionFetchItemMessage message = + new AuctionFetchItemProtocol.AuctionFetchItemMessage(uuid); + CompletableFuture future = new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest(message); future.thenAccept(response -> { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdBin.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdBin.java index 72c1c491a..00df3929e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdBin.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdBin.java @@ -7,8 +7,8 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocolObject; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocol; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocol; import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionItem; import net.swofty.proxyapi.ProxyPlayer; @@ -107,8 +107,8 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { player.sendMessage(I18n.t("gui_auction.view_third_bin.processing")); - CompletableFuture future = new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest( - new AuctionFetchItemProtocolObject.AuctionFetchItemMessage(item.getUuid()) + CompletableFuture future = new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest( + new AuctionFetchItemProtocol.AuctionFetchItemMessage(item.getUuid()) ); AuctionItem item = future.join().item(); @@ -139,8 +139,8 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { }}); item.setEndTime(System.currentTimeMillis()); - AuctionAddItemProtocolObject.AuctionAddItemMessage message = - new AuctionAddItemProtocolObject.AuctionAddItemMessage( + AuctionAddItemProtocol.AuctionAddItemMessage message = + new AuctionAddItemProtocol.AuctionAddItemMessage( item, AuctionCategories.TOOLS); new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest(message).join(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdNormal.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdNormal.java index 029ea2af7..0e6d086f8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdNormal.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/view/AuctionViewThirdNormal.java @@ -8,8 +8,8 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; -import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocolObject; -import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocolObject; +import net.swofty.commons.protocol.objects.auctions.AuctionAddItemProtocol; +import net.swofty.commons.protocol.objects.auctions.AuctionFetchItemProtocol; import net.swofty.commons.skyblock.auctions.AuctionCategories; import net.swofty.commons.skyblock.auctions.AuctionItem; import net.swofty.proxyapi.ProxyPlayer; @@ -232,8 +232,8 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { player.sendMessage(I18n.t("gui_auction.view_third_normal.processing_bid")); Thread.startVirtualThread(() -> { - AuctionFetchItemProtocolObject.AuctionFetchItemResponse itemResponse = (AuctionFetchItemProtocolObject.AuctionFetchItemResponse) new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest( - new AuctionFetchItemProtocolObject.AuctionFetchItemMessage(item.getUuid()) + AuctionFetchItemProtocol.AuctionFetchItemResponse itemResponse = (AuctionFetchItemProtocol.AuctionFetchItemResponse) new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest( + new AuctionFetchItemProtocol.AuctionFetchItemMessage(item.getUuid()) ).join(); AuctionItem item = itemResponse.item(); @@ -258,8 +258,8 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { }}); item.setEndTime(item.getEndTime() + 120000); - AuctionAddItemProtocolObject.AuctionAddItemMessage message = - new AuctionAddItemProtocolObject.AuctionAddItemMessage( + AuctionAddItemProtocol.AuctionAddItemMessage message = + new AuctionAddItemProtocol.AuctionAddItemMessage( item, category); new ProxyService(ServiceType.AUCTION_HOUSE).handleRequest(message).join(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaar.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaar.java index a2cd9c0bb..3e270ced1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaar.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaar.java @@ -20,6 +20,7 @@ import net.swofty.type.skyblockgeneric.bazaar.BazaarCategories; import net.swofty.type.skyblockgeneric.bazaar.BazaarItemSet; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; @@ -158,8 +159,7 @@ private void rebuildCacheAndRender(SkyBlockPlayer player) { )); }) .exceptionally(throwable -> { - System.err.println("Failed to fetch bazaar data for " + type.name() + ": " + throwable.getMessage()); - // Store empty data on failure + Logger.error(throwable, "Failed to fetch bazaar data for {}", type.name()); setDataMap.get(set).put(type, new PriceData(type, 0, 0)); return null; }); @@ -207,7 +207,7 @@ private void rebuildCacheAndRender(SkyBlockPlayer player) { }, 1); }) .exceptionally(throwable -> { - System.err.println("Failed to rebuild bazaar cache: " + throwable.getMessage()); + Logger.error(throwable, "Failed to rebuild bazaar cache"); // Fallback: render with "Error loading" placeholders MathUtility.delay(() -> { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaarOrderCompletedOptions.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaarOrderCompletedOptions.java index b078293e0..e97bbde04 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaarOrderCompletedOptions.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/bazaar/GUIBazaarOrderCompletedOptions.java @@ -276,7 +276,7 @@ private void claimRewards(SkyBlockPlayer player) { } catch (Exception e) { player.sendMessage(I18n.string("gui_bazaar.order_completed.claim_failed", l, Component.text(e.getMessage()))); - System.err.println("Failed to claim bazaar rewards: " + e.getMessage()); + org.tinylog.Logger.error(e, "Failed to claim bazaar rewards"); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java new file mode 100644 index 000000000..f3a6070a6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java @@ -0,0 +1,155 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.commons.StringUtility; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FishingGuideStackFactory { + private static final List GUIDE_STAT_ORDER = List.of( + ItemStatistic.DAMAGE, + ItemStatistic.STRENGTH, + ItemStatistic.FEROCITY, + ItemStatistic.FISHING_SPEED, + ItemStatistic.SEA_CREATURE_CHANCE, + ItemStatistic.DOUBLE_HOOK_CHANCE, + ItemStatistic.TREASURE_CHANCE, + ItemStatistic.TROPHY_FISH_CHANCE, + ItemStatistic.MAGIC_FIND + ); + + public static net.minestom.server.item.ItemStack.Builder buildBaitStack(SkyBlockItem baitItem) { + FishingBaitComponent bait = baitItem.getComponent(FishingBaitComponent.class); + List lore = new ArrayList<>(); + lore.add("§8Fishing Bait"); + lore.add("§8Consumes on Cast"); + lore.add(""); + appendStatistics(lore, baitItem.getAttributeHandler().getStatistics()); + appendTagBonuses(lore, bait.getTagBonuses()); + + if (bait.getTreasureChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.getTreasureChanceBonus()) + " Treasure Chance§7."); + } + if (bait.getTreasureQualityBonus() > 0) { + lore.add("§7Increases treasure quality by §a" + format(bait.getTreasureQualityBonus()) + "%§7."); + } + if (bait.getTrophyFishChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.getTrophyFishChanceBonus()) + " Trophy Fish Chance§7."); + } + if (bait.getDoubleHookChanceBonus() > 0) { + lore.add("§7Grants §9+" + format(bait.getDoubleHookChanceBonus()) + " Double Hook Chance§7."); + } + if (bait.getMediums().size() == 1) { + lore.add("§7Usable in " + (bait.getMediums().getFirst() == FishingMedium.WATER ? "§bWater" : "§cLava") + "§7."); + } + finishFooter(lore, bait.getItemId(), "BAIT"); + + return ItemStackCreator.getStackHead( + coloredName(bait.getItemId(), bait.getDisplayName()), + bait.getTexture(), + 1, + lore.toArray(String[]::new) + ); + } + + public static net.minestom.server.item.ItemStack.Builder buildRodPartStack(SkyBlockItem partItem) { + FishingRodPartComponent part = partItem.getComponent(FishingRodPartComponent.class); + List lore = new ArrayList<>(); + lore.add("§8" + StringUtility.toNormalCase(part.getCategory().name()) + " Rod Part"); + lore.add(""); + appendStatistics(lore, partItem.getAttributeHandler().getStatistics()); + appendTagBonuses(lore, part.getTagBonuses()); + + if (part.isTreasureOnly()) { + lore.add("§7Only allows you to catch items and §6Treasure§7."); + } + if (part.isBayouTreasureToJunk()) { + lore.add("§7Replaces §6Treasure §7catches with §2Junk §7in the §2Backwater Bayou§7."); + } + if (part.getMaterializedItemId() != null) { + String itemName = ItemType.valueOf(part.getMaterializedItemId()).getDisplayName(); + if (part.getMaterializedChance() >= 1.0D) { + lore.add("§7Materializes §f" + itemName + " §7in your inventory whenever you catch something."); + } else { + lore.add("§7Has a §a" + format(part.getMaterializedChance() * 100.0D) + "% §7chance to materialize §f" + itemName + "§7."); + } + } + if (part.getBaitPreservationChance() > 0) { + lore.add("§7Grants a §a" + format(part.getBaitPreservationChance()) + "% §7chance to not consume Bait."); + } + if (part.getHotspotBuffMultiplier() > 1.0D) { + lore.add("§7Increases the bonuses of §dFishing Hotspots §7by §a" + format((part.getHotspotBuffMultiplier() - 1.0D) * 100.0D) + "%§7."); + } + if (part.getRequiredFishingLevel() > 0) { + lore.add(""); + lore.add("§4❣ §cRequires §aFishing Skill " + part.getRequiredFishingLevel() + "§c."); + } + finishFooter(lore, part.getItemId(), "ROD PART"); + + return ItemStackCreator.getStackHead( + coloredName(part.getItemId(), part.getDisplayName()), + part.getTexture(), + 1, + lore.toArray(String[]::new) + ); + } + + private static void appendStatistics(List lore, ItemStatistics statistics) { + for (ItemStatistic statistic : GUIDE_STAT_ORDER) { + double amount = statistics.getOverall(statistic); + if (amount == 0) { + continue; + } + lore.add("§7" + statistic.getDisplayName() + ": " + statistic.getLoreColor() + + statistic.getPrefix() + format(amount) + statistic.getSuffix()); + } + } + + private static void appendTagBonuses(List lore, Map bonuses) { + for (Map.Entry entry : bonuses.entrySet()) { + lore.add("§7Increases the chance to catch §e" + describeTag(entry.getKey()) + " §7by §a" + format(entry.getValue()) + "%§7."); + } + } + + private static void finishFooter(List lore, String itemId, String suffix) { + if (!lore.isEmpty() && !lore.getLast().isEmpty()) { + lore.add(""); + } + lore.add(ItemType.valueOf(itemId).rarity.getDisplay() + " " + suffix); + } + + private static String coloredName(String itemId, String displayName) { + return ItemType.valueOf(itemId).rarity.getColor() + displayName; + } + + private static String describeTag(String tag) { + return switch (tag.toUpperCase()) { + case "COMMON" -> "Common Sea Creatures"; + case "HOTSPOT" -> "Hotspot Sea Creatures"; + case "SPOOKY" -> "Spooky Sea Creatures"; + case "WINTER" -> "Winter Sea Creatures"; + case "SHARK" -> "Sharks"; + default -> StringUtility.toNormalCase(tag.toLowerCase().replace('_', ' ')); + }; + } + + private static String format(double value) { + if (Math.abs(value - Math.rint(value)) < 0.0001D) { + return String.valueOf((long) Math.rint(value)); + } + return StringUtility.decimalify(value, 1); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI13SeaCreatureGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI13SeaCreatureGuide.java new file mode 100644 index 000000000..3d266dd68 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI13SeaCreatureGuide.java @@ -0,0 +1,456 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.item.Material; + +import java.util.List; + +public final class GUI13SeaCreatureGuide extends SeaCreatureGuidePage { + + @Override + protected int pageNumber() { + return 1; + } + + @Override + protected List entries() { + return List.of( + head(10, "§7[Lvl 1] Squid (§f§lCommon§7)", "32581d564f01d712255125e1f101e534217f76e3599dab7f4ae0ffe328f729eb", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Ink Sac", + "§7- Lily Pad", + "", + "§cRequirements:", + "§7- §aFishing Skill 1", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b64"), + head(11, "§7[Lvl 4] Sea Walker (§f§lCommon§7)", "d88ba8bb50b79e441e47b7e452764d5fff6693779d2dadd9f7f52f98d7ea0", + "§9⚓ Aquatic§7, §2༕ Undead", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Rotten Flesh", + "", + "§cRequirements:", + "§7- §aFishing Skill 1", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b64"), + head(12, "§7[Lvl 6] Night Squid (§f§lCommon§7)", "32581d564f01d712255125e1f101e534217f76e3599dab7f4ae0ffe328f729eb", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Ink Sac", + "§7- Lily Pad", + "§7- §aFishing Exp Boost", + "§7- §aSquid Boots", + "§7- §9Fishing Exp Boost", + "", + "§cRequirements:", + "§7- §aFishing Skill 3", + "§7- §bWater", + "§7- Nighttime", + "§7- §fDark Bait"), + head(13, "§7[Lvl 10] Sea Guardian (§f§lCommon§7)", "221025434045bda7025b3e514b316a4b770c6faa4ba9adb4be3809526db77f9d", + "§9⚓ Aquatic§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Prismarine Crystals", + "§7- Prismarine Shard", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b48"), + head(14, "§7[Lvl 10] Frog Man (§f§lCommon§7)", "6157f19da077a3df49b2925fb6e8b400222ba6e559e86815f9b296d9e9667dd7", + "§9⚓ Aquatic§7, §a☮ Animal§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Tropical Fish", + "§7- §aHalf-Eaten Mushroom", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §dFishing Hotspot", + "", + "§cStats", + "§7- Kills: §b28"), + head(15, "§7[Lvl 8] Trash Gobbler (§f§lCommon§7)", "18ae7046da98dcb33f3ed42f1dc41d08ac8dfa5db3a3860de5b1b5c056804187", + "§9⚓ Aquatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- §aCan of Worms", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b57"), + head(16, "§7[Lvl 10] Bogged (§f§lCommon§7)", "a3b9003ba2d05562c75119b8a62185c67130e9282f7acbac4bc2824c21eb95d9", + "§f🦴 Skeletal§7, §9⚓ Aquatic", + "", + "§cDrops:", + "§7- Mangrove Log", + "§7- Sea Lumies", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §2Galatea"), + head(19, "§7[Lvl 7] Frozen Steve (§f§lCommon§7)", "54690f5aa6d0e800f9b8d1890fc158b921819a81dfd7342a2170e7efc46b9ed7", + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §9Ice Essence", + "§7- Ice", + "§7- Lily Pad", + "§7- Pufferfish", + "§7- Raw Cod", + "§7- Raw Salmon", + "§7- White Gift", + "§7- §aHunk of Ice", + "§7- §9Icy Sinker", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b9"), + head(20, "§7[Lvl 15] Dumpster Diver (§a§lUncommon§7)", "f5c5eb5ee072c06580986d12a029e28010c1290875534810c53140bc76dabfeb", + "§9⚓ Aquatic§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Sponge", + "§7- §aBronze Bowl", + "§7- §aOverflowing Trash Can", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b38"), + head(21, "§7[Lvl 6] Nurse Shark (§a§lUncommon§7)", "2067ccefba5d811f47e3e18438556b704393aafcafccedd5d0981999286f598a", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §aCarnival Ticket", + "§7- §aNurse Shark Tooth", + "§7- §9Shark Fin", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §bFishing Festival"), + block(22, "§7[Lvl 13] Frosty (§f§lCommon§7)", Material.CARVED_PUMPKIN, + "§9⚓ Aquatic§7, §f☃ Frozen§7, ⚙ Construct", + "", + "§cDrops:", + "§7- §9Ice Essence", + "§7- Carrot", + "§7- Ice", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Snow Block", + "§7- Sponge", + "§7- White Gift", + "§7- §aHunk of Ice", + "", + "§cRequirements:", + "§7- §aFishing Skill 6", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b9"), + head(23, "§7[Lvl 15] Mithril Grubber (§a§lUncommon§7)", "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + "§9⚓ Aquatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- §9Mithril Powder", + "§7- Mithril", + "§7- Raw Cod", + "§7- §9Enchanted Mithril", + "", + "§cRequirements:", + "§7- §aFishing Skill 6", + "§7- §bWater", + "§7- §2Abandoned Quarry"), + head(24, "§7[Lvl 18] Wetwing (§a§lUncommon§7)", "dbc0f7c9e926c320ba472d4a88763ef932a660c470f786ac0c04c15a78fd505f", + "§9⚓ Aquatic§7, §2༕ Undead§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Mangrove Log", + "§7- Sea Lumies", + "§7- §aWet Water", + "§7- §9Enchanted Mangrove Log", + "", + "§cRequirements:", + "§7- §aFishing Skill 7", + "§7- §bWater", + "§7- §2Galatea", + "", + "§cStats", + "§7- Kills: §b1"), + head(25, "§7[Lvl 15] Sea Witch (§a§lUncommon§7)", "fce6604157fc4ab5591e4bcf507a749918ee9c41e357d47376e0ee7342074c90", + "§9⚓ Aquatic§7, §e✰ Humanoid§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Salmon", + "§7- Tropical Fish", + "§7- §9Fairy's Fedora", + "§7- §9Fairy's Galoshes", + "§7- §9Fairy's Polo", + "§7- §9Fairy's Trousers", + "", + "§cRequirements:", + "§7- §aFishing Skill 7", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b52"), + block(28, "§7[Lvl 9] Scarecrow (§f§lCommon§7)", Material.CARVED_PUMPKIN, + "§9⚓ Aquatic§7, §6☽ Spooky", + "", + "§cDrops:", + "§7- Hay Bale", + "§7- Lily Pad", + "§7- §aGreen Candy", + "§7- §5Purple Candy", + "", + "§cRequirements:", + "§7- §aFishing Skill 9", + "§7- §bWater", + "§7- §6Spooky Festival"), + block(29, "§7[Lvl 15] Sea Archer (§a§lUncommon§7)", Material.SKELETON_SKULL, + "§9⚓ Aquatic§7, §f🦴 Skeletal", + "", + "§cDrops:", + "§7- Bone", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- §aEnchanted Bone", + "", + "§cRequirements:", + "§7- §aFishing Skill 9", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b48"), + head(30, "§7[Lvl 8] Tadgang (§9§lRare§7)", "1608d86ffb297bf93b7190d24bc3b2dc094f8086740f7541a752fbe661f175fc", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Mangrove Log", + "§7- Sea Lumies", + "§7- §aEnchanted Sea Lumies", + "§7- §aGill Membrane", + "§7- §9Enchanted Mangrove Log", + "", + "§cRequirements:", + "§7- §aFishing Skill 9", + "§7- §bWater", + "§7- §2Galatea", + "", + "§cStats", + "§7- Kills: §b1"), + head(31, "§7[Lvl 10] Oasis Sheep (§a§lUncommon§7)", "292df216ecd27624ac771bacfbfe006e1ed84a79e9270be0f88e9c8791d1ece4", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Mutton", + "§7- White Wool", + "§7- §aEnchanted Raw Mutton", + "§7- §9Enchanted Cooked Mutton", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §bOasis"), + head(32, "§7[Lvl 10] Oasis Rabbit (§a§lUncommon§7)", "b50459bcb08db5ce93e021079c1cfc038c9ebe7ad9a149516efe4d5ee8afb59f", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Rabbit Hide", + "§7- Rabbit's Foot", + "§7- Raw Rabbit", + "§7- §aEnchanted Raw Rabbit", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §bOasis"), + head(33, "§7[Lvl 10] Banshee (§9§lRare§7)", "30ccc3c9a06de657b98f881e23a57ecaeb252c364ddb7b92564f5ed2b8087e3b", + "§9⚓ Aquatic§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Lily Pad", + "§7- Raw Salmon", + "§7- Tropical Fish", + "§7- §aEnchanted Clay Ball", + "§7- §aTorn Cloth", + "§7- §9Calcified Heart", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b22"), + head(34, "§7[Lvl 20] Blue Shark (§9§lRare§7)", "381e1d06e5f0654a682a3264905b5dc4b8e7b613ab6697ac45f2e0da3bc9b4fd", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §aCarnival Ticket", + "§7- §9Blue Shark Tooth", + "§7- §9Shark Fin", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §bFishing Festival"), + head(37, "§7[Lvl 30] Snapping Turtle (§9§lRare§7)", "e08fc1ae87a7035d32b0b0da58de4801463aaf8b238618024aacb0c515ae3bba", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Gold Ingot", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- §aEnchanted Gold Ingot", + "§7- §9Broken Radar", + "§7- §9Edible Seaweed", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §dFishing Hotspot", + "", + "§cStats", + "§7- Kills: §b5"), + head(38, "§7[Lvl 20] Rider of the Deep (§a§lUncommon§7)", "cfb7dbbe002f69463768113c1e925848197f59b62694ce105792dd5a52dc17a1", + "§9⚓ Aquatic§7, §2༕ Undead§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Dark Bait", + "§7- Lily Pad", + "§7- Sponge", + "§7- §9Enchanted Book", + "§7 (Magnet VI)", + "§7- §aEnchanted Feather", + "§7- §aEnchanted Rotten Flesh", + "", + "§cRequirements:", + "§7- §aFishing Skill 11", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b36"), + head(39, "§7[Lvl 14] Ent (§5§lEpic§7)", "30519f79e5829136c3df10b6bd727db255717c87e5c102892ef67e7f46929515", + "§2⸙ Woodland§7, §9⚓ Aquatic", + "", + "§cDrops:", + "§7- Sea Lumies", + "§7- §aEnchanted Sea Lumies", + "§7- §9Enchanted Mangrove Log", + "§7- §5Foraging Exp Boost", + "§7- §5Mangcore", + "", + "§cRequirements:", + "§7- §aFishing Skill 12", + "§7- §bWater", + "§7- §2Galatea"), + head(40, "§7[Lvl 21] Grinch (§a§lUncommon§7)", "2508e4a2f88502c019652b2437b76c82fedff9091389d88118ecc673f628b547", + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §9Ice Essence", + "§7- White Gift", + "§7- §aGreen Gift", + "", + "§cRequirements:", + "§7- §aFishing Skill 13", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b2"), + head(41, "§7[Lvl 23] Catfish (§9§lRare§7)", "e18f77331b2cab64e2b430fa8e4273e4db7f78fcdfa4b1a9a418af47375056eb", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Pufferfish", + "§7- Raw Cod", + "§7- Raw Salmon", + "§7- Sponge", + "§7- Tropical Fish", + "§7- §9Enchanted Book", + "§7 (Frail VI)", + "", + "§cRequirements:", + "§7- §aFishing Skill 13", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b26"), + block(42, "§7[Lvl 30] Fried Chicken (§f§lCommon§7)", Material.COOKED_CHICKEN, + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Raw Chicken", + "§7- §aEnchanted Raw Chicken", + "§7- §aFried Feather", + "§7- §9Magmafish", + "", + "§cRequirements:", + "§7- §aFishing Skill 14", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle"), + head(43, "§7[Lvl 25] Carrot King (§9§lRare§7)", "b50459bcb08db5ce93e021079c1cfc038c9ebe7ad9a149516efe4d5ee8afb59f", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Sponge", + "§7- §9Enchanted Book", + "§7 (Caster VI)", + "§7- §aEnchanted Carrot", + "§7- §aRabbit Hat", + "§7- §9Enchanted Rabbit Foot", + "§7- §5Lucky Clover Core", + "", + "§cRequirements:", + "§7- §aFishing Skill 14", + "§7- §bWater", + "§7- §fCarrot Bait") + ); + } +} + diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI23SeaCreatureGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI23SeaCreatureGuide.java new file mode 100644 index 000000000..4c8872320 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI23SeaCreatureGuide.java @@ -0,0 +1,379 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.item.Material; + +import java.util.List; + +public final class GUI23SeaCreatureGuide extends SeaCreatureGuidePage { + + @Override + protected int pageNumber() { + return 2; + } + + @Override + protected List entries() { + return List.of( + head(10, "§7[Lvl 24] Nightmare (§9§lRare§7)", "578211e1b4d99d1c7bfda4838e48fc884c3eae376f58d932bc2f78b0a919f8e7", + "§9⚓ Aquatic§7, §6☽ Spooky§7, §2༕ Undead", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- §aEnchanted Rotten Flesh", + "§7- §aGreen Candy", + "§7- §aLucky Hoof", + "§7- §5Purple Candy", + "", + "§cRequirements:", + "§7- §aFishing Skill 14", + "§7- §bWater", + "§7- §6Spooky Festival"), + head(11, "§7[Lvl 35] Agarimoo (§9§lRare§7)", "3d597f77cde32c9ac9b06f82fcf7c9cb500facc14bff166222b24be39962f0ef", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Red Mushroom", + "§7- §9Agarimoo Tongue", + "", + "§cRequirements:", + "§7- §aFishing Skill 15", + "§7- §aChumcap Bucket", + "§7- §bWater"), + head(12, "§7[Lvl 20] Water Worm (§9§lRare§7)", "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + "§9⚓ Aquatic§7, §6⛏ Subterranean", + "", + "§cDrops:", + "§7- Hard Stone", + "§7- ⸕ Rough Amber Gemstone", + "§7- §aWorm Membrane", + "", + "§cRequirements:", + "§7- §aFishing Skill 15", + "§7- §bWater", + "§7- §6Goblin Holdout"), + head(13, "§7[Lvl 25] Bayou Sludge (§5§lEpic§7)", "895aeec6b842ada8669f846d65bc49762597824ab944f22f45bf3bbb941abe6c", + "§9⚓ Aquatic§7, §a⚂ Cubic", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Enchanted Book", + "§7 (Respite I)", + "§7- Lily Pad", + "§7- Slimeball", + "§7- §9Enchanted Book", + "§7 (Blessing VI)", + "§7- §aEnchanted Slimeball", + "§7- §aPoison Sample", + "§7- §9Enchanted Slime Block", + "", + "§cRequirements:", + "§7- §aFishing Skill 15", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b23"), + head(14, "§7[Lvl 30] Sea Leech (§9§lRare§7)", "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Sponge", + "§7- Tropical Fish", + "§7- §9Enchanted Book", + "§7 (Spiked Hook VI)", + "§7- §9Fishing Exp Boost", + "§7- §5Fishing Exp Boost", + "", + "§cRequirements:", + "§7- §aFishing Skill 16", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b15"), + head(15, "§7[Lvl 75] Fireproof Witch (§9§lRare§7)", "fce6604157fc4ab5591e4bcf507a749918ee9c41e357d47376e0ee7342074c90", + "§c♆ Magmatic§7, §e✰ Humanoid§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §9Enchanted Book", + "§7 (Fire Protection VI)", + "§7- §aEnchanted Glowstone", + "§7- §aEnchanted Glowstone Dust", + "§7- §aSinged Powder", + "§7- §9Magmafish", + "", + "§cRequirements:", + "§7- §aFishing Skill 16", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle"), + head(16, "§7[Lvl 21] Stridersurfer (§9§lRare§7)", "620971f4dd71592a6065944487da2adf22987d5d0cccf6085dff7a6767d1b21a", + "§c♆ Magmatic§7, §2༕ Undead§7, §2⸙ Woodland", + "", + "§cDrops:", + "§7- §aGill Membrane", + "§7- §9Sturdy Bone", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §cLava", + "§7- §2Galatea", + "", + "§cStats", + "§7- Kills: §b8"), + head(19, "§7[Lvl 25] Poisoned Water Worm (§9§lRare§7)", "18ae7046da98dcb33f3ed42f1dc41d08ac8dfa5db3a3860de5b1b5c056804187", + "§9⚓ Aquatic§7, §6⛏ Subterranean§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- Hard Stone", + "§7- ⸕ Rough Amber Gemstone", + "§7- §aWorm Membrane", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §bWater", + "§7- §6Goblin Holdout"), + head(20, "§7[Lvl 45] Guardian Defender (§5§lEpic§7)", "221025434045bda7025b3e514b316a4b770c6faa4ba9adb4be3809526db77f9d", + "§9⚓ Aquatic§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Sponge", + "§7- §9Enchanted Book", + "§7 (Lure VI)", + "§7- §aEnchanted Prismarine Crystals", + "§7- §aEnchanted Prismarine Shard", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b12"), + head(21, "§7[Lvl 50] Werewolf (§5§lEpic§7)", "ce4606c6d973a999aec1687c7e075f7d37db8185e88b844507f16b3e2b3eb690", + "§9⚓ Aquatic§7, §6☽ Spooky§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- §aGreen Candy", + "§7- §9Werewolf Skin", + "§7- §5Deep Sea Orb", + "§7- §5Purple Candy", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §bWater", + "§7- §6Spooky Festival"), + head(22, "§7[Lvl 50] Tiger Shark (§5§lEpic§7)", "ea575977e6bd0c7add94e2d8fdcc2af77e36c44d6b4c67788862a94000be6399", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §aCarnival Ticket", + "§7- §9Shark Fin", + "§7- §5Megalodon Pet", + "§7- §5Tiger Shark Tooth", + "", + "§cRequirements:", + "§7- §aFishing Skill 18", + "§7- §bWater", + "§7- §bFishing Festival"), + head(23, "§7[Lvl 60] Deep Sea Protector (§5§lEpic§7)", "22bcaceeb4162f400d44743315932ac820d3119ac8986a0161a726161ccc93fc", + "§9⚓ Aquatic§7, ⚙ Construct", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Sponge", + "§7- Tropical Fish", + "§7- §9Enchanted Book", + "§7 (Angler VI)", + "§7- §aEnchanted Iron Ingot", + "§7- §5Fishing Exp Boost", + "", + "§cRequirements:", + "§7- §aFishing Skill 18", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b7"), + head(24, "§7[Lvl §k?] §k????? (§9§lRare§7)", "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + "§c♆ Magmatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 19", + "§7- §cLava", + "§7- §bPrecursor Remnants"), + head(25, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "6d6bcd3bea0dff1f45d808e7a8550f95106af41b6d8d18a0793e19c9255ae845", + "§9⚓ Aquatic§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 19", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b1"), + head(28, "§7[Lvl §k?] §k????? (§5§lEpic§7)", "b78ef2e4cf2c41a2d14bfde9caff10219f5b1bf5b35a49eb51c6467882cb5f0", + "§c♆ Magmatic§7, §4♨ Infernal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 20", + "§7- §cLava", + "§7- §cMagma Fields"), + head(29, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "5cf6abfbc778b1fac0d6db161e74438a1b468323b6f93fa4d650e42cd0f5802a", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 20", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b6"), + head(30, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "46c15b527e4872249c91797435521cb77651b567e57518304f5f131e49ded652", + "§9⚓ Aquatic§7, §f🦴 Skeletal§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 20", + "§7- §bWater", + "§7- §2Galatea"), + head(31, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "6c9bc01f299f98d565a27ba10a1293915ae8beeefb8a67845e2331dbe6fd6fd6", + "§9⚓ Aquatic§7, §6☽ Spooky§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 21", + "§7- §bWater", + "§7- §6Spooky Festival"), + head(32, "§7[Lvl §k?] §k????? (§5§lEpic§7)", "74e9c6e98582ffd8ff8feb3322cd1849c43fb16b158abb11ca7b42eda7743eb", + "§c♆ Magmatic§7, §2༕ Undead", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 22", + "§7- §cLava", + "§7- §cMagma Fields"), + head(33, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "58be05cfae2c6a7d47da2ce88b3e00c72a145cc3218f041b3dd5bd5fa5ca827", + "§9⚓ Aquatic§7, §2༕ Undead§7, §6⛏ Subterranean", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 24", + "§7- §bWater", + "§7- §2Mithril Deposits", + "§7- §bPrecursor Remnants", + "§7- §2Jungle"), + head(34, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "de2e5865429dd2520bbc703e4a9f2f1abd5e1cc5d31b8a9acbf74b7a97c937aa", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 24", + "§7- §bWater", + "§7- §bFishing Festival"), + head(37, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "4dd2d3c6d01c276226c7b0d377122e1a647b2ffb5b9b54fa98eac37bb1d09d3a", + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 25", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b1"), + head(38, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "68a6194a5b217b9f5a3dfecce5f3efe6967405039b82fa0c4e8959175f32e75a", + "§9⚓ Aquatic§7, §6☽ Spooky§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 26", + "§7- §bWater", + "§7- §6Spooky Festival"), + head(39, "§7[Lvl §k?] §k????? (§a§lUncommon§7)", "38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429", + "§c♆ Magmatic§7, §a⚂ Cubic", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 27", + "§7- §cLava", + "§7- §cCrimson Isle", + "", + "§cStats", + "§7- Kills: §b1"), + head(40, "§7[Lvl §k?] §k????? (§a§lUncommon§7)", "47f1bc3fa91cd86cf4ba7745586d67207b58e7cf27bdf7a717780843785bf9b5", + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 28", + "§7- §cLava", + "§7- §cCrimson Isle"), + head(41, "§7[Lvl §k?] §k????? (§9§lRare§7)", "c2407e66c81b1443c2e7dfc4d6583eb19c622fa22f34fbf99fe6c45f76a", + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 28", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b2"), + head(42, "§7[Lvl §k?] §k????? (§9§lRare§7)", "18ae7046da98dcb33f3ed42f1dc41d08ac8dfa5db3a3860de5b1b5c056804187", + "§c♆ Magmatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 30", + "§7- §cLava", + "§7- §cCrimson Isle"), + head(43, "§7[Lvl §k?] §k????? (§d§lMythic§7)", "645f2c0bbfe3b8b19b7452072db69a5f59da38ff61415545156e5701e1be756d", + "§9⚓ Aquatic§7, §a☮ Animal§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 30", + "§7- §bWater", + "§7- §2Backwater Bayou") + ); + } +} + diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI33SeaCreatureGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI33SeaCreatureGuide.java new file mode 100644 index 000000000..222ec89f9 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI33SeaCreatureGuide.java @@ -0,0 +1,147 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.item.Material; + +import java.util.List; + +public final class GUI33SeaCreatureGuide extends SeaCreatureGuidePage { + + @Override + protected int pageNumber() { + return 3; + } + + @Override + protected List entries() { + return List.of( + head(10, "§7[Lvl §k?] §k????? (§9§lRare§7)", "38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429", + "§c♆ Magmatic§7, §a⚂ Cubic", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 31", + "§7- §cLava", + "§7- §cCrimson Isle"), + head(11, "§7[Lvl §k?] §k????? (§9§lRare§7)", "b78ef2e4cf2c41a2d14bfde9caff10219f5b1bf5b35a49eb51c6467882cb5f0", + "§c♆ Magmatic§7, §4♨ Infernal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 33", + "§7- §cLava", + "§7- §cCrimson Isle"), + head(12, "§7[Lvl §k?] §k????? (§9§lRare§7)", "c63704a7fc7d437f7b923e23e9a08ae3bbe28937df4dafa9e3e8725b2ce4afa5", + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 34", + "§7- §cLava", + "§7- §cCrimson Isle"), + head(13, "§7[Lvl §k?] §k????? (§5§lEpic§7)", "1642a06cd75ef307c1913ba7a224fb2082d8a2c5254fd1bf006125a087a9a868", + "§c♆ Magmatic§7, §e✰ Humanoid§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 35", + "§7- §cLava", + "§7- §cCrimson Isle"), + head(14, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "b2b6074d0c9d6b89a494cf4f74158282a64ee23ba8a0725633ad70932ada1a8f", + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 35", + "§7- §bWater", + "§7- §dFishing Hotspot", + "", + "§cStats", + "§7- Kills: §b1"), + block(15, "§7[Lvl §k?] §k????? (§d§lMythic§7)", Material.DRAGON_EGG, + "§f☃ Frozen§7, §e⛨ Shielded§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 35", + "§7- §bWater", + "§7- §cJerry's Workshop"), + head(16, "§7[Lvl §k?] §k????? (§d§lMythic§7)", "32581d564f01d712255125e1f101e534217f76e3599dab7f4ae0ffe328f729eb", + "§c♆ Magmatic§7, §d❃ Elusive§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 36", + "§7- §cLava", + "§7- §cCrimson Isle"), + head(19, "§7[Lvl §k?] §k????? (§d§lMythic§7)", "a3f925d274ec65e002028c898e11aa9b76d6d67aa305ad9c7c69fe61cec5e664", + "§c♆ Magmatic§7, §5♃ Arcane§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 36", + "§7- §cLava", + "§7- §cCrimson Isle", + "§7- §cNovice Trophy Fisher"), + head(20, "§7[Lvl §k?] §k????? (§6§lLegendary§7)", "55b194025806687642e2bc239895d646a6d8c193d9253b61bfce908f6ce1b84a", + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 37", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle"), + head(21, "§7[Lvl §k?] §k????? (§d§lMythic§7)", "f3c802e580bfefc18c4af94cceb82968b5b4aeab0d832346a633a7473a41dfac", + "§9⚓ Aquatic§7, ⚙ Construct, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 40", + "§7- §bWater", + "§7- §dFishing Hotspot"), + head(22, "§7[Lvl §k?] §k????? (§d§lMythic§7)", "22bcaceeb4162f400d44743315932ac820d3119ac8986a0161a726161ccc93fc", + "§c♆ Magmatic§7, ⚙ Construct, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 45", + "§7- §cLava", + "§7- §cCrimson Isle", + "§7- §cAdept Trophy Fisher"), + head(23, "§7[Lvl §k?] §k????? (§d§lMythic§7)", "a8e1fe214b71f6ea69c541a861c64bafda7bf9b85de5dd17ab2b6ccd1d32b039", + "§c♆ Magmatic§7, §f🦴 Skeletal§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 47", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle") + ); + } +} + diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIBaitGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIBaitGuide.java new file mode 100644 index 000000000..db464cbff --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIBaitGuide.java @@ -0,0 +1,42 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; + +public class GUIBaitGuide extends StatelessView { + private static final int[] BAIT_SLOTS = {10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Bait Guide", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§6Bait Guide", + Material.BOOK, + 1, + "§7View §6Baits§7 and the effects they add", + "§7to your fishing catches." + )); + + int index = 0; + for (var bait : FishingItemSupport.getBaits()) { + if (index >= BAIT_SLOTS.length) { + break; + } + layout.slot(BAIT_SLOTS[index++], FishingGuideStackFactory.buildBaitStack(bait)); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingRodParts.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingRodParts.java new file mode 100644 index 000000000..dd7202981 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingRodParts.java @@ -0,0 +1,101 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.ViewSession; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public class GUIFishingRodParts extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Fishing Rod Parts", InventoryType.CHEST_6_ROW); + } + + @Override + public void onClose(DefaultState state, ViewContext ctx, ViewSession.CloseReason reason) { + ItemStack rodItem = ctx.inventory().getItemStack(21); + if (!rodItem.isAir()) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + player.addAndUpdateItem(new SkyBlockItem(rodItem)); + ctx.inventory().setItemStack(21, ItemStack.AIR); + } + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.editable(21, (_, _) -> ItemStackCreator.createNamedItemStack( + Material.FISHING_ROD, + "§7Place your §aFishing Rod §7here!" + ), (_, oldItem, newItem, _) -> { + if (newItem.isAir()) { + return; + } + SkyBlockItem rod = new SkyBlockItem(newItem); + ItemType type = rod.getAttributeHandler().getPotentialType(); + var metadata = type == null ? null : FishingItemSupport.getRodMetadata(type.name()); + if (metadata == null || !metadata.isRodPartsEnabled() || metadata.getLegacyConversionTarget() != null) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + player.sendMessage("§cThat fishing rod does not support rod parts."); + ctx.inventory().setItemStack(21, oldItem); + if (!newItem.isAir()) { + player.addAndUpdateItem(new SkyBlockItem(newItem)); + } + } + }); + + layout.slot(22, ItemStackCreator.getStack( + "§9ථ Hook", + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + 1, + "§7Place a §aFishing Rod §7in the slot to the", + "§7left to view and modify its §9Hook§7!", + "", + "§eClick to browse Hooks!" + ), (_, viewCtx) -> viewCtx.push(new GUIHookGuide())); + + layout.slot(23, ItemStackCreator.getStack( + "§9ꨃ Line", + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + 1, + "§7Place a §aFishing Rod §7in the slot to the", + "§7left to view and modify its §9Line§7!", + "", + "§eClick to browse Lines!" + ), (_, viewCtx) -> viewCtx.push(new GUILineGuide())); + + layout.slot(24, ItemStackCreator.getStack( + "§9࿉ Sinker", + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + 1, + "§7Place a §aFishing Rod §7in the slot to the", + "§7left to view and modify its §9Sinker§7!", + "", + "§eClick to browse Sinkers!" + ), (_, viewCtx) -> viewCtx.push(new GUISinkerGuide())); + + layout.slot(50, ItemStackCreator.getStack( + "§9Rod Part Guide", + Material.BOOK, + 1, + "§7View all of the §9Rod Parts §7that can be", + "§7applied to §aFishing Rods§7! Can also be", + "§7accessed with §a/rodparts§7!", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUIRodPartGuide())); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingShip.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingShip.java new file mode 100644 index 000000000..abf7518be --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingShip.java @@ -0,0 +1,155 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.event.inventory.InventoryPreClickEvent; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.inventory.item.GUIItem; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.ship.FishingShipService; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public class GUIFishingShip extends HypixelInventoryGUI { + + public GUIFishingShip() { + super("{Fishing Ship}", InventoryType.CHEST_5_ROW); + } + + @Override + public void onOpen(InventoryGUIOpenEvent e) { + fill(FILLER_ITEM); + set(new GUIItem(4) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + var state = FishingShipService.getState(skyBlockPlayer); + return ItemStackCreator.getStack( + "§6{Fishing Ship}", + Material.OAK_BOAT, + 1, + "§7Your §6Ship §7will help you travel to", + "§7different §9fishing islands §7in SkyBlock.", + "", + "§7For now, it can only get you to the", + "§2Backwater Bayou§7.", + "", + "§7Helm: §f" + resolvePartName(state.getHelm(), "Cracked Ship Helm"), + "§7Engine: §f" + resolvePartName(state.getEngine(), "Missing Engine"), + "§7Hull: §f" + resolvePartName(state.getHull(), "Rusty Ship Hull") + ); + } + }); + set(new GUIItem(21) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return buildShipPartStack( + FishingShipService.getState(skyBlockPlayer).getHelm(), + "Cracked Ship Helm", + "d8d4a54d1fcf47b2efc99ba4cc772250aee5c2f26ed1a19052213e0f3323ca1d", + "§7A cracked ship helm, incapable of", + "§7changing its heading which appears", + "§7due east." + ); + } + }); + set(new GUIItem(22) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return buildShipPartStack( + FishingShipService.getState(skyBlockPlayer).getEngine(), + "Missing Engine", + "53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c", + "§7This ship still needs an engine before", + "§7it can get you anywhere." + ); + } + }); + set(new GUIItem(23) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return buildShipPartStack( + FishingShipService.getState(skyBlockPlayer).getHull(), + "Rusty Ship Hull", + "f42d53ca6e7d80a99a699c2036dcf6e233394feb9f46fb2ff9d9a819690894a9", + "§7A hull rusted and dilapidated beyond", + "§7repair. It's a miracle the ship", + "§7remains afloat." + ); + } + }); + set(new GUIClickableItem(31) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + boolean unlocked = FishingShipService.getState(skyBlockPlayer).hasDestination("BACKWATER_BAYOU"); + return ItemStackCreator.getStack( + unlocked ? "§aOpen Navigator" : "§cNavigator Locked", + Material.COMPASS, + 1, + "§7Choose where to set sail next.", + "", + unlocked ? "§eClick to browse destinations!" : "§cInstall an engine first." + ); + } + + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + if (!FishingShipService.getState(skyBlockPlayer).hasDestination("BACKWATER_BAYOU")) { + player.sendMessage("§cYour ship cannot travel anywhere yet."); + return; + } + skyBlockPlayer.openView(new GUINavigator()); + } + }); + set(new GUIItem(44) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return ItemStackCreator.getStack( + "§aRename Ship", + Material.NAME_TAG, + 1, + "§7You may be going on long voyages", + "§7with your §6Ship§7, best to give it a name!", + "", + "§7Current Name: §6" + FishingShipService.getState(skyBlockPlayer).getShipName(), + "", + "§7Renaming is not implemented yet." + ); + } + }); + set(GUIClickableItem.getCloseItem(40)); + updateItemStacks(getInventory(), getPlayer()); + } + + @Override + public boolean allowHotkeying() { + return false; + } + + @Override + public void onBottomClick(InventoryPreClickEvent e) { + e.setCancelled(true); + } + + private static String resolvePartName(String itemId, String fallback) { + var definition = FishingItemSupport.getShipPart(itemId); + return definition == null ? fallback : definition.getDisplayName(); + } + + private static ItemStack.Builder buildShipPartStack(String itemId, String fallbackName, String fallbackTexture, String... fallbackLore) { + var definition = FishingItemSupport.getShipPart(itemId); + String name = definition == null ? fallbackName : definition.getDisplayName(); + String texture = definition == null || definition.getTexture() == null ? fallbackTexture : definition.getTexture(); + String[] lore = fallbackLore; + return ItemStackCreator.getStackHead("§f" + name, texture, 1, lore); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIHookGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIHookGuide.java new file mode 100644 index 000000000..8347b19ce --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIHookGuide.java @@ -0,0 +1,47 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingPartCategory; + +public class GUIHookGuide extends StatelessView { + private static final int[] PART_SLOTS = {10, 11, 12, 13, 14, 15, 16}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Hook", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + layout.slot(4, ItemStackCreator.getStackHead( + "§9ථ Hooks", + "9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e", + 1, + "§9Hooks §7change what your rod is better at catching." + )); + + int index = 0; + for (var part : FishingItemSupport.getRodParts()) { + if (part.getComponent(net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent.class).getCategory() != FishingPartCategory.HOOK || index >= PART_SLOTS.length) { + continue; + } + layout.slot(PART_SLOTS[index++], FishingGuideStackFactory.buildRodPartStack(part)); + } + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Rod Part Guide" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUILineGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUILineGuide.java new file mode 100644 index 000000000..6113c6239 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUILineGuide.java @@ -0,0 +1,47 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingPartCategory; + +public class GUILineGuide extends StatelessView { + private static final int[] PART_SLOTS = {10, 11, 12, 13, 14, 15, 16}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Line", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + layout.slot(4, ItemStackCreator.getStackHead( + "§9ꨃ Lines", + "9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9", + 1, + "§9Lines §7grant stat bonuses to your rod everywhere." + )); + + int index = 0; + for (var part : FishingItemSupport.getRodParts()) { + if (part.getComponent(net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent.class).getCategory() != FishingPartCategory.LINE || index >= PART_SLOTS.length) { + continue; + } + layout.slot(PART_SLOTS[index++], FishingGuideStackFactory.buildRodPartStack(part)); + } + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Rod Part Guide" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUINavigator.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUINavigator.java new file mode 100644 index 000000000..f47c10a82 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUINavigator.java @@ -0,0 +1,89 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.commons.ServerType; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.Layouts; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public class GUINavigator extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Navigator", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + ServerType currentServer = HypixelConst.getTypeLoader().getType(); + boolean inBayou = currentServer == ServerType.SKYBLOCK_BACKWATER_BAYOU; + boolean unlocked = inBayou || player.getShipState().hasDestination("BACKWATER_BAYOU"); + + layout.slots(Layouts.row(0), (_, _) -> Components.FILLER); + layout.slots(Layouts.row(5), (_, _) -> Components.FILLER); + layout.slots(Layouts.rectangle(9, 45), (_, _) -> Components.FILLER.material(Material.BLUE_STAINED_GLASS_PANE)); + Components.close(layout, 49); + + if (inBayou) { + layout.slot(10, ItemStackCreator.getStackHead( + "§bFishing Outpost", + "d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8", + 1, + "§7Your base of operations.", + "", + "§eClick to travel!" + ), (_, viewCtx) -> ((SkyBlockPlayer) viewCtx.player()).sendTo(ServerType.SKYBLOCK_HUB)); + layout.slot(40, ItemStackCreator.getStackHead( + "§2Backwater Bayou", + "1c0cd33590f64d346d98cdd01606938742e715dda6737353306a44f81c8ba426", + 1, + "§7A small, marshy outlet in the middle", + "§7of nowhere. Due to its isolated", + "§7nature, people frequently come here", + "§7to dump their trash.", + "", + "§a§lYOU ARE HERE!" + )); + return; + } + + layout.slot(10, ItemStackCreator.getStackHead( + "§2Backwater Bayou", + "1c0cd33590f64d346d98cdd01606938742e715dda6737353306a44f81c8ba426", + 1, + "§7A small, marshy outlet in the middle", + "§7of nowhere. Due to its isolated", + "§7nature, people frequently come here", + "§7to dump their trash.", + "", + "§7Activities:", + "§8 ■ §7Fish up §2Junk §7and trade it with §2Junker", + " §2Joel §7for useful items!", + "§8 ■ §7Apply §9Rod Parts §7with §2Roddy§7.", + "§8 ■ §7Fish §2Bayou Sea Creatures§7.", + "§8 ■ §7Learn about §dFishing Hotspots §7from", + " §dHattie§7.", + "", + unlocked ? "§eClick to travel!" : "§cDestination Locked" + ), unlocked + ? (_, viewCtx) -> ((SkyBlockPlayer) viewCtx.player()).sendTo(ServerType.SKYBLOCK_BACKWATER_BAYOU) + : (_, viewCtx) -> viewCtx.player().sendMessage("§cYou have not unlocked this destination yet.")); + layout.slot(40, ItemStackCreator.getStackHead( + "§bFishing Outpost", + "d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8", + 1, + "§7Your base of operations.", + "", + "§a§lYOU ARE HERE!" + )); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIRodPartGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIRodPartGuide.java new file mode 100644 index 000000000..9dbeca20b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIRodPartGuide.java @@ -0,0 +1,64 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +public class GUIRodPartGuide extends StatelessView { + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Rod Part Guide", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§9Rod Part Guide", + Material.BOOK, + 1, + "§7View all §9Rod Parts §7that can be applied", + "§7to your upgraded fishing rods." + )); + layout.slot(20, ItemStackCreator.getStackHead( + "§9ථ Hooks", + "9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e", + 1, + "§9Hooks §7make you more likely to catch", + "§7certain things.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUIHookGuide())); + layout.slot(22, ItemStackCreator.getStackHead( + "§9ꨃ Lines", + "9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9", + 1, + "§9Lines §7grant you stat bonuses", + "§7everywhere.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUILineGuide())); + layout.slot(24, ItemStackCreator.getStackHead( + "§9࿉ Sinkers", + "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", + 1, + "§9Sinkers §7add special fishing effects", + "§7to your rod.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUISinkerGuide())); + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Fishing Rod Parts" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUISinkerGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUISinkerGuide.java new file mode 100644 index 000000000..e37c1c213 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUISinkerGuide.java @@ -0,0 +1,47 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingPartCategory; + +public class GUISinkerGuide extends StatelessView { + private static final int[] PART_SLOTS = {10, 11, 12, 13, 14, 15, 16, 19, 20}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Sinker", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + layout.slot(4, ItemStackCreator.getStackHead( + "§9࿉ Sinkers", + "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", + 1, + "§9Sinkers §7add special fishing effects to your rod." + )); + + int index = 0; + for (var part : FishingItemSupport.getRodParts()) { + if (part.getComponent(net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent.class).getCategory() != FishingPartCategory.SINKER || index >= PART_SLOTS.length) { + continue; + } + layout.slot(PART_SLOTS[index++], FishingGuideStackFactory.buildRodPartStack(part)); + } + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Rod Part Guide" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/SeaCreatureGuidePage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/SeaCreatureGuidePage.java new file mode 100644 index 000000000..575c71408 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/SeaCreatureGuidePage.java @@ -0,0 +1,169 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; + +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +import java.util.List; + +/** + * Shared chrome for the 3-page sea creature guide. Subclasses only need to + * declare which page they are and which entries to show; layout, navigation, + * sort/filter/category buttons all live here. + * + * Entries are modelled as a sealed {@link Entry} hierarchy: {@code Head} for + * player heads (the common case — most creatures use one) and {@code Block} + * for the handful that render as a regular item (dragon eggs, etc.). + */ +public abstract sealed class SeaCreatureGuidePage extends StatelessView + permits GUI13SeaCreatureGuide, GUI23SeaCreatureGuide, GUI33SeaCreatureGuide { + + private static final int TOTAL_PAGES = 3; + + protected abstract int pageNumber(); + + protected abstract List entries(); + + @Override + public final ViewConfiguration configuration() { + return new ViewConfiguration<>( + "(" + pageNumber() + "/" + TOTAL_PAGES + ") Sea Creature Guide", + InventoryType.CHEST_6_ROW + ); + } + + @Override + public final void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§aSea Creature Guide", + Material.BOOK, + 1, + "§7Your guide to the creatures of the", + "§7deep! Can also be accessed with", + "§a/scg§7!", + "", + "§7Beware, Sea Creatures spawn much", + "§7less often on your private island.", + "", + "§7Your Fishing: §aLevel XVIII" + )); + + for (Entry entry : entries()) { + layout.slot(entry.slot(), entry.render()); + } + + if (pageNumber() > 1) { + layout.slot(45, ItemStackCreator.getStack( + "§aPrevious Page", + Material.ARROW, + 1, + "§ePage " + (pageNumber() - 1) + )); + } + + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Fishing Skill" + )); + + layout.slot(50, ItemStackCreator.getStack( + "§aSort", + Material.HOPPER, + 1, + "", + "§b▶ Fishing Level Req", + "§7 Alphabetical", + "§7 Mob Level", + "§7 Killed Most", + "§7 Ascending Rarity", + "§7 Descending Rarity", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + + layout.slot(51, ItemStackCreator.getStack( + "§aFilter", + Material.ENDER_EYE, + 1, + "", + "§f▶ All Sea Creatures", + "§7 Has Level Requirement", + "§7 Has Never Killed", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + + layout.slot(52, ItemStackCreator.getStack( + "§aCategory", + Material.CAULDRON, + 1, + "", + "§a▶ Any Category", + "§7 Water", + "§7 Lava", + "§7 Winter", + "§7 Spooky", + "§7 Shark", + "§7 Oasis", + "§7 Bayou", + "§7 Hotspot", + "§7 Galatea", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + + if (pageNumber() < TOTAL_PAGES) { + layout.slot(53, ItemStackCreator.getStack( + "§aNext Page", + Material.ARROW, + 1, + "§ePage " + (pageNumber() + 1) + )); + } + } + + /** Convenience builder for a head-rendered entry. */ + protected static Entry head(int slot, String name, String texture, String... lore) { + return new Entry.Head(slot, name, texture, lore); + } + + /** Convenience builder for a material-rendered entry. */ + protected static Entry block(int slot, String name, Material material, String... lore) { + return new Entry.Block(slot, name, material, lore); + } + + public sealed interface Entry { + int slot(); + + ItemStack.Builder render(); + + record Head(int slot, String name, String texture, String... lore) implements Entry { + @Override + public ItemStack.Builder render() { + return ItemStackCreator.getStackHead(name, texture, 1, lore); + } + } + + record Block(int slot, String name, Material material, String... lore) implements Entry { + @Override + public ItemStack.Builder render() { + return ItemStackCreator.getStack(name, material, 1, lore); + } + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumArmorCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumArmorCategory.java index fbe6c127e..f924fd05d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumArmorCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumArmorCategory.java @@ -11,7 +11,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; import net.swofty.commons.TrackedItem; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocolObject; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocol; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; @@ -206,11 +206,11 @@ public void performSearch(HypixelPlayer player, String query, int page, int maxP continue; if (armorSets.contains(ArmorSetRegistry.getArmorSet(item.getAttributeHandler().getPotentialType()))) { - TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage( + TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage( UUID.fromString(item.getAttributeHandler().getUniqueTrackedID()) ); ProxyService proxyService = new ProxyService(ServiceType.ITEM_TRACKER); - TrackedItemRetrieveProtocolObject.TrackedItemResponse trackedItemResponse = (TrackedItemRetrieveProtocolObject.TrackedItemResponse) proxyService.handleRequest(message).join(); + TrackedItemRetrieveProtocol.TrackedItemResponse trackedItemResponse = (TrackedItemRetrieveProtocol.TrackedItemResponse) proxyService.handleRequest(message).join(); TrackedItem trackedItem = trackedItemResponse.trackedItem(); ItemStack.Builder toReturn = item.getItemStackBuilder(); @@ -295,13 +295,13 @@ public ItemStack.Builder getItem(HypixelPlayer p) { UUID leggingsUUID = UUID.fromString(leggings.getAttributeHandler().getUniqueTrackedID()); UUID bootsUUID = UUID.fromString(boots.getAttributeHandler().getUniqueTrackedID()); - TrackedItemRetrieveProtocolObject.TrackedItemResponse helmetResponse = (TrackedItemRetrieveProtocolObject.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage(helmetUUID)).join(); + TrackedItemRetrieveProtocol.TrackedItemResponse helmetResponse = (TrackedItemRetrieveProtocol.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage(helmetUUID)).join(); TrackedItem trackedHelmet = helmetResponse.trackedItem(); - TrackedItemRetrieveProtocolObject.TrackedItemResponse chestplateResponse = (TrackedItemRetrieveProtocolObject.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage(chestplateUUID)).join(); + TrackedItemRetrieveProtocol.TrackedItemResponse chestplateResponse = (TrackedItemRetrieveProtocol.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage(chestplateUUID)).join(); TrackedItem trackedChestplate = chestplateResponse.trackedItem(); - TrackedItemRetrieveProtocolObject.TrackedItemResponse leggingsResponse = (TrackedItemRetrieveProtocolObject.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage(leggingsUUID)).join(); + TrackedItemRetrieveProtocol.TrackedItemResponse leggingsResponse = (TrackedItemRetrieveProtocol.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage(leggingsUUID)).join(); TrackedItem trackedLeggings = leggingsResponse.trackedItem(); - TrackedItemRetrieveProtocolObject.TrackedItemResponse bootsResponse = (TrackedItemRetrieveProtocolObject.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage(bootsUUID)).join(); + TrackedItemRetrieveProtocol.TrackedItemResponse bootsResponse = (TrackedItemRetrieveProtocol.TrackedItemResponse) itemTracker.handleRequest(new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage(bootsUUID)).join(); TrackedItem trackedBoots = bootsResponse.trackedItem(); int helmetValue = new ItemPriceCalculator(helmet).calculateCleanPrice().intValue(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumCategory.java index 7818835dc..3867728c5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumCategory.java @@ -11,7 +11,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; import net.swofty.commons.TrackedItem; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocolObject; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocol; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; @@ -135,10 +135,10 @@ public void performSearch(HypixelPlayer p, String query, int page, int maxPage) } if (category.contains(item.getAttributeHandler().getPotentialType())) { - TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage( + TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage( UUID.fromString(item.getAttributeHandler().getUniqueTrackedID()) ); - TrackedItem trackedItem = ((TrackedItemRetrieveProtocolObject.TrackedItemResponse) new ProxyService(ServiceType.ITEM_TRACKER).handleRequest(message).join()).trackedItem(); + TrackedItem trackedItem = ((TrackedItemRetrieveProtocol.TrackedItemResponse) new ProxyService(ServiceType.ITEM_TRACKER).handleRequest(message).join()).trackedItem(); ItemStack.Builder toReturn = item.getItemStackBuilder(); List lore = new ArrayList<>(item.getLore(player)); @@ -201,8 +201,8 @@ public ItemStack.Builder getItem(HypixelPlayer p) { } UUID trackedItemUUID = UUID.fromString(skyBlockItem.getAttributeHandler().getUniqueTrackedID()); - TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage(trackedItemUUID); - TrackedItem trackedItem = ((TrackedItemRetrieveProtocolObject.TrackedItemResponse) new ProxyService(ServiceType.ITEM_TRACKER) + TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage(trackedItemUUID); + TrackedItem trackedItem = ((TrackedItemRetrieveProtocol.TrackedItemResponse) new ProxyService(ServiceType.ITEM_TRACKER) .handleRequest(message).join()).trackedItem(); Locale l = player.getLocale(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumEmptyDisplay.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumEmptyDisplay.java index b81dab567..e0d4e8ffb 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumEmptyDisplay.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumEmptyDisplay.java @@ -8,7 +8,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; import net.swofty.commons.TrackedItem; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocolObject; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; @@ -171,11 +171,11 @@ public ItemStack.Builder getItem(HypixelPlayer p) { } private GUIClickableItem createIndividualItemDisplay(SkyBlockItem item, int slot, SkyBlockPlayer player) { - TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage( + TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage message = new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage( UUID.fromString(item.getAttributeHandler().getUniqueTrackedID()) ); ProxyService proxyService = new ProxyService(ServiceType.ITEM_TRACKER); - TrackedItemRetrieveProtocolObject.TrackedItemResponse trackedItemResponse = (TrackedItemRetrieveProtocolObject.TrackedItemResponse) proxyService.handleRequest(message).join(); + TrackedItemRetrieveProtocol.TrackedItemResponse trackedItemResponse = (TrackedItemRetrieveProtocol.TrackedItemResponse) proxyService.handleRequest(message).join(); TrackedItem trackedItem = trackedItemResponse.trackedItem(); return new GUIClickableItem(slot) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumNonEmptyDisplay.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumNonEmptyDisplay.java index d9975b496..6b8f5c94c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumNonEmptyDisplay.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/museum/GUIMuseumNonEmptyDisplay.java @@ -9,7 +9,7 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.StringUtility; import net.swofty.commons.TrackedItem; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocolObject; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemRetrieveProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; @@ -135,13 +135,13 @@ private ItemStack.Builder createItemDisplay(SkyBlockItem item, SkyBlockPlayer pl // Get tracked item info TrackedItem trackedItem = null; try { - TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage message = - new TrackedItemRetrieveProtocolObject.TrackedItemRetrieveMessage( + TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage message = + new TrackedItemRetrieveProtocol.TrackedItemRetrieveMessage( UUID.fromString(item.getAttributeHandler().getUniqueTrackedID()) ); ProxyService proxyService = new ProxyService(ServiceType.ITEM_TRACKER); - TrackedItemRetrieveProtocolObject.TrackedItemResponse response = - (TrackedItemRetrieveProtocolObject.TrackedItemResponse) proxyService.handleRequest(message).join(); + TrackedItemRetrieveProtocol.TrackedItemResponse response = + (TrackedItemRetrieveProtocol.TrackedItemResponse) proxyService.handleRequest(message).join(); trackedItem = response.trackedItem(); } catch (Exception e) { Logger.error(e, "Error displaying museum items"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java index da84784c6..bf565dea8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java @@ -2,7 +2,7 @@ import net.minestom.server.color.Color; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemUpdateProtocolObject; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemUpdateProtocol; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.commons.skyblock.item.Rarity; import net.swofty.commons.skyblock.item.attribute.attributes.*; @@ -85,6 +85,41 @@ public void setRuneData(ItemAttributeRuneInfusedWith.RuneData data) { ((ItemAttributeRuneInfusedWith) item.getAttribute("rune_infused_with")).setValue(data); } + public @Nullable String getFishingHook() { + String value = ((ItemAttributeFishingHook) item.getAttribute("fishing_hook")).getValue(); + return value == null || value.equalsIgnoreCase("none") ? null : value; + } + + public void setFishingHook(@Nullable String hookId) { + item.getAttribute("fishing_hook").setValue(hookId == null ? "none" : hookId); + } + + public @Nullable String getFishingLine() { + String value = ((ItemAttributeFishingLine) item.getAttribute("fishing_line")).getValue(); + return value == null || value.equalsIgnoreCase("none") ? null : value; + } + + public void setFishingLine(@Nullable String lineId) { + item.getAttribute("fishing_line").setValue(lineId == null ? "none" : lineId); + } + + public @Nullable String getFishingSinker() { + String value = ((ItemAttributeFishingSinker) item.getAttribute("fishing_sinker")).getValue(); + return value == null || value.equalsIgnoreCase("none") ? null : value; + } + + public void setFishingSinker(@Nullable String sinkerId) { + item.getAttribute("fishing_sinker").setValue(sinkerId == null ? "none" : sinkerId); + } + + public long getFishingExpertiseKills() { + return ((ItemAttributeFishingExpertiseKills) item.getAttribute("fishing_expertise_kills")).getValue(); + } + + public void setFishingExpertiseKills(long kills) { + item.getAttribute("fishing_expertise_kills").setValue(kills); + } + public boolean isPet() { return item.hasComponent(PetComponent.class); } @@ -208,15 +243,15 @@ public void setUniqueTrackedID(String uniqueTrackedID, SkyBlockPlayer player) { ProxyService itemTracker = new ProxyService(ServiceType.ITEM_TRACKER); if (!itemTracker.isOnline().join()) return; - TrackedItemUpdateProtocolObject.TrackedItemUpdateMessage message = - new TrackedItemUpdateProtocolObject.TrackedItemUpdateMessage( + TrackedItemUpdateProtocol.TrackedItemUpdateMessage message = + new TrackedItemUpdateProtocol.TrackedItemUpdateMessage( UUID.fromString(uniqueTrackedID), player.getUuid(), player.getProfiles().getCurrentlySelected(), item.getAttributeHandler().getTypeAsString() ); - CompletableFuture future + CompletableFuture future = itemTracker.handleRequest(message); }); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java index 329980e18..be4b4bf03 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java @@ -11,6 +11,9 @@ import net.swofty.commons.skyblock.item.reforge.ReforgeType; import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingPartCategory; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingShipPartSlot; import net.swofty.type.skyblockgeneric.gems.GemRarity; import net.swofty.type.skyblockgeneric.gems.Gemstone; import net.swofty.type.skyblockgeneric.item.components.*; @@ -71,11 +74,10 @@ public static ConfigurableSkyBlockItem parseItem(Map config) { return item; } catch (SafeConfig.ConfigParseException e) { - Logger.error("Failed to parse item: {}", e.getMessage()); + Logger.error(e, "Failed to parse item"); return null; } catch (Exception e) { - Logger.error("Unexpected error parsing item: {}", e.getMessage()); - e.printStackTrace(); + Logger.error(e, "Unexpected error parsing item"); Sentry.captureException(e); return null; } @@ -162,6 +164,74 @@ yield new EnchantableComponent( showLores ); } + case "FISHING_ROD" -> new FishingRodComponent(); + case "FISHING_ROD_METADATA" -> { + FishingMedium medium = safeConfig.containsKey("medium") + ? safeConfig.getEnum("medium", FishingMedium.class) + : FishingMedium.WATER; + int requiredFishingLevel = safeConfig.getInt("required_fishing_level", 0); + boolean rodPartsEnabled = safeConfig.getBoolean("rod_parts_enabled", true); + String legacyConversionTarget = safeConfig.getString("legacy_conversion_target", null); + String subtitle = safeConfig.getString("subtitle", null); + List extraRequirements = safeConfig.getList("extra_requirements", String.class); + yield new FishingRodMetadataComponent( + medium, + requiredFishingLevel, + rodPartsEnabled, + legacyConversionTarget, + subtitle, + extraRequirements + ); + } + case "FISHING_ROD_PART" -> { + String displayName = safeConfig.getString("display_name"); + FishingPartCategory category = safeConfig.getEnum("category", FishingPartCategory.class); + int requiredFishingLevel = safeConfig.getInt("required_fishing_level", 0); + Map tagBonuses = new java.util.LinkedHashMap<>(); + for (Map.Entry entry : safeConfig.getMap("tag_bonuses").entrySet()) { + tagBonuses.put(entry.getKey(), ((Number) entry.getValue()).doubleValue()); + } + yield new FishingRodPartComponent( + itemId, + displayName, + category, + requiredFishingLevel, + tagBonuses, + safeConfig.getBoolean("treasure_only", false), + safeConfig.getBoolean("bayou_treasure_to_junk", false), + safeConfig.getString("materialized_item_id", null), + safeConfig.getDouble("materialized_chance", 1.0), + safeConfig.getDouble("bait_preservation_chance", 0.0), + safeConfig.getDouble("hotspot_buff_multiplier", 1.0), + safeConfig.getString("texture", null) + ); + } + case "FISHING_BAIT" -> { + String displayName = safeConfig.getString("display_name"); + Map tagBonuses = new java.util.LinkedHashMap<>(); + for (Map.Entry entry : safeConfig.getMap("tag_bonuses").entrySet()) { + tagBonuses.put(entry.getKey(), ((Number) entry.getValue()).doubleValue()); + } + List mediums = safeConfig.containsKey("mediums") + ? safeConfig.getList("mediums", String.class).stream().map(value -> FishingMedium.valueOf(value.toUpperCase())).toList() + : List.of(FishingMedium.WATER, FishingMedium.LAVA); + yield new FishingBaitComponent( + itemId, + displayName, + tagBonuses, + safeConfig.getDouble("treasure_chance_bonus", 0.0), + safeConfig.getDouble("treasure_quality_bonus", 0.0), + safeConfig.getDouble("trophy_fish_chance_bonus", 0.0), + safeConfig.getDouble("double_hook_chance_bonus", 0.0), + mediums, + safeConfig.getString("texture", null) + ); + } + case "FISHING_SHIP_PART" -> { + String displayName = safeConfig.getString("display_name"); + FishingShipPartSlot slot = safeConfig.getEnum("slot", FishingShipPartSlot.class); + yield new FishingShipPartComponent(itemId, displayName, slot, safeConfig.getString("texture", null)); + } case "ENCHANTED" -> { if (safeConfig.containsKey("recipes")) { List> recipeConfigs = safeConfig.getMapList("recipes"); @@ -604,11 +674,10 @@ yield new PetComponent( default -> throw new IllegalArgumentException("Unknown component type: " + id); }; } catch (SafeConfig.ConfigParseException e) { - Logger.error("Failed to parse component {} for item {}: {}", id, itemId, e.getMessage()); + Logger.error(e, "Failed to parse component {} for item {}", id, itemId); return null; } catch (Exception e) { - Logger.error("Unexpected error parsing component {} for item {}: {}", id, itemId, e.getMessage()); - e.printStackTrace(); + Logger.error(e, "Unexpected error parsing component {} for item {}", id, itemId); return null; } } @@ -663,4 +732,4 @@ private static List parseGemstoneEntries(List 3 && !parts[3].isBlank()) { + getAttributeHandler().setFishingExpertiseKills(Long.parseLong(parts[3])); + } + } + + private @Nullable String readLegacyFishingPart(String[] parts, int index) { + if (index >= parts.length) { + return null; + } + String value = parts[index]; + return value == null || value.isBlank() || value.equalsIgnoreCase("none") ? null : value; + } + public ItemStack.Builder getDisplayItem() { ItemStack.Builder builder; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java new file mode 100644 index 000000000..30328eed6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java @@ -0,0 +1,54 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; + +import java.util.List; +import java.util.Map; + +@Getter +public class FishingBaitComponent extends SkyBlockItemComponent { + private final String itemId; + private final String displayName; + private final Map tagBonuses; + private final double treasureChanceBonus; + private final double treasureQualityBonus; + private final double trophyFishChanceBonus; + private final double doubleHookChanceBonus; + private final List mediums; + private final String texture; + + public FishingBaitComponent( + String itemId, + String displayName, + Map tagBonuses, + double treasureChanceBonus, + double treasureQualityBonus, + double trophyFishChanceBonus, + double doubleHookChanceBonus, + List mediums, + String texture + ) { + this.itemId = itemId; + ItemType type = ItemType.get(itemId); + this.displayName = displayName == null || displayName.isBlank() + ? (type == null ? itemId : type.getDisplayName()) + : displayName; + this.tagBonuses = Map.copyOf(tagBonuses); + this.treasureChanceBonus = treasureChanceBonus; + this.treasureQualityBonus = treasureQualityBonus; + this.trophyFishChanceBonus = trophyFishChanceBonus; + this.doubleHookChanceBonus = doubleHookChanceBonus; + this.mediums = List.copyOf(mediums); + this.texture = texture; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + addInheritedComponent(new ExtraUnderNameComponent(List.of("Fishing Bait", "Consumes on Cast"))); + addInheritedComponent(new ExtraRarityComponent("BAIT")); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java new file mode 100644 index 000000000..5b8749e9f --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java @@ -0,0 +1,43 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; +import net.swofty.type.skyblockgeneric.entity.FishingHook; +import net.swofty.type.skyblockgeneric.fishing.item.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingService; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; + +public class FishingRodComponent extends SkyBlockItemComponent { + + public FishingRodComponent() { + addInheritedComponent(new InteractableComponent( + null, + (player, item) -> { + FishingHook hook = FishingHook.getFishingHookForOwner(player); + if (hook != null) { + hook.tryRetrieve(item); + hook.remove(); + FishingService.clearSession(player.getUuid()); + float pitch = 0.8f + (float) (Math.random() * 0.4f); + player.playSound( + Sound.sound() + .type(Key.key("entity.fishing_bobber.retrieve")) + .source(Sound.Source.NEUTRAL) + .volume(1f) + .pitch(pitch) + .build() + ); + } else { + String itemId = item.getAttributeHandler().getPotentialType() == null ? null : item.getAttributeHandler().getPotentialType().name(); + var metadata = FishingItemSupport.getRodMetadata(itemId); + if (metadata != null && metadata.getLegacyConversionTarget() != null) { + return; + } + new FishingHook(player, item).spawn(player.getInstance()); + } + }, + null + )); + } + +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java new file mode 100644 index 000000000..ccb7f8c8c --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java @@ -0,0 +1,42 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.reforge.ReforgeType; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@Getter +public class FishingRodMetadataComponent extends SkyBlockItemComponent { + private final FishingMedium medium; + private final int requiredFishingLevel; + private final boolean rodPartsEnabled; + private final @Nullable String legacyConversionTarget; + private final @Nullable String subtitle; + private final List extraRequirements; + + public FishingRodMetadataComponent( + FishingMedium medium, + int requiredFishingLevel, + boolean rodPartsEnabled, + @Nullable String legacyConversionTarget, + @Nullable String subtitle, + List extraRequirements + ) { + this.medium = medium; + this.requiredFishingLevel = requiredFishingLevel; + this.rodPartsEnabled = rodPartsEnabled; + this.legacyConversionTarget = legacyConversionTarget; + this.subtitle = subtitle; + this.extraRequirements = List.copyOf(extraRequirements); + addInheritedComponent(new FishingRodComponent()); + addInheritedComponent(new EnchantableComponent(List.of(EnchantItemGroups.FISHING_ROD), true)); + addInheritedComponent(new ReforgableComponent(ReforgeType.FISHING_RODS)); + addInheritedComponent(new DefaultSoulboundComponent(true)); + addInheritedComponent(new ExtraRarityComponent("FISHING ROD")); + addInheritedComponent(new LoreUpdateComponent("FISHING_ROD", true)); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java new file mode 100644 index 000000000..43307b3db --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java @@ -0,0 +1,60 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingPartCategory; + +import java.util.Map; + +@Getter +public class FishingRodPartComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + private final String itemId; + private final String displayName; + private final FishingPartCategory category; + private final int requiredFishingLevel; + private final Map tagBonuses; + private final boolean treasureOnly; + private final boolean bayouTreasureToJunk; + private final String materializedItemId; + private final double materializedChance; + private final double baitPreservationChance; + private final double hotspotBuffMultiplier; + private final String texture; + + public FishingRodPartComponent( + String itemId, + String displayName, + FishingPartCategory category, + int requiredFishingLevel, + Map tagBonuses, + boolean treasureOnly, + boolean bayouTreasureToJunk, + String materializedItemId, + double materializedChance, + double baitPreservationChance, + double hotspotBuffMultiplier, + String texture + ) { + this.itemId = itemId; + ItemType type = ItemType.get(itemId); + this.displayName = displayName == null || displayName.isBlank() + ? (type == null ? itemId : type.getDisplayName()) + : displayName; + this.category = category; + this.requiredFishingLevel = requiredFishingLevel; + this.tagBonuses = Map.copyOf(tagBonuses); + this.treasureOnly = treasureOnly; + this.bayouTreasureToJunk = bayouTreasureToJunk; + this.materializedItemId = materializedItemId; + this.materializedChance = materializedChance; + this.baitPreservationChance = baitPreservationChance; + this.hotspotBuffMultiplier = hotspotBuffMultiplier; + this.texture = texture; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + addInheritedComponent(new ExtraRarityComponent("ROD PART")); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java new file mode 100644 index 000000000..7ae781930 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java @@ -0,0 +1,28 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingShipPartSlot; + +@Getter +public class FishingShipPartComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + private final String itemId; + private final String displayName; + private final FishingShipPartSlot slot; + private final String texture; + + public FishingShipPartComponent(String itemId, String displayName, FishingShipPartSlot slot, String texture) { + this.itemId = itemId; + ItemType type = ItemType.get(itemId); + this.displayName = displayName == null || displayName.isBlank() + ? (type == null ? itemId : type.getDisplayName()) + : displayName; + this.slot = slot; + this.texture = texture; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/events/RuneItemEvent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/events/RuneItemEvent.java index 3700ba03e..a35c63598 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/events/RuneItemEvent.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/events/RuneItemEvent.java @@ -4,14 +4,15 @@ import net.minestom.server.particle.Particle; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerKilledSkyBlockMobEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class RuneItemEvent implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void run(PlayerKilledSkyBlockMobEvent event) { SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/anvilcombine/AnvilCombineRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/anvilcombine/AnvilCombineRegistry.java index 772304067..934b5cafe 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/anvilcombine/AnvilCombineRegistry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/anvilcombine/AnvilCombineRegistry.java @@ -34,8 +34,6 @@ public class AnvilCombineRegistry { }, (player, upgradeItem, sacrificeItem) -> { if (upgradeItem.hasComponent(HotPotatoableComponent.class)) { - System.out.println(upgradeItem.getAttributeHandler().getPotentialType()); - var type = sacrificeItem.getAttributeHandler().getPotentialType(); HotPotatoableComponent hotPotatoable = upgradeItem.getComponent(HotPotatoableComponent.class); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java index 55f273779..1379325ec 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java @@ -5,7 +5,7 @@ import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.entity.hologram.ServerHolograms; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; +import net.swofty.type.skyblockgeneric.user.island.SkyBlockIsland; import net.swofty.type.skyblockgeneric.utility.JerryInformation; import java.util.HashMap; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java index 432c0a787..b9aee99cd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java @@ -3,9 +3,15 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.PotatoType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; +import net.swofty.type.skyblockgeneric.fishing.rod.FishingRodLoreBuilder; import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; public class LoreRegistry { @@ -70,6 +76,16 @@ public class LoreRegistry { "§eClick to open!" ), (item, player) -> "§aSkyBlock Menu §7(Click)")); register("HOT_POTATO_BOOK", new LoreConfig((item, player) -> PotatoType.allLores(), null)); + register("FISHING_ROD", new LoreConfig( + (item, player) -> { + var lore = FishingRodLoreBuilder.build(item, player); + return lore == null ? List.of() : lore.lore(); + }, + (item, player) -> { + var lore = FishingRodLoreBuilder.build(item, player); + return lore == null ? item.getDisplayName() : lore.displayName(); + } + )); register("MIDAS_SWORD", new LoreConfig((item, player) -> { List lore = new ArrayList<>(); long pricePaid = item.getAttributeHandler().getDarkAuctionPrice(); @@ -115,4 +131,4 @@ public static void register(String id, LoreConfig handler) { public static LoreConfig getHandler(String id) { return REGISTERED_HANDLERS.get(id); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/orbs/ServerOrbRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/orbs/ServerOrbRegistry.java index 270c51078..64ab5b670 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/orbs/ServerOrbRegistry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/orbs/ServerOrbRegistry.java @@ -16,7 +16,7 @@ public class ServerOrbRegistry { registerHandler("WHEAT_CRYSTAL_ORB_HANDLER", new ServerOrbHandler(crystalImpl -> Block.WHEAT)); registerHandler("FLOWER_CRYSTAL_ORB_HANDLER", new ServerOrbHandler(crystalImpl -> { List flowers = Groups.FLOWERS; - Material randomMaterial = flowers.get(new Random().nextInt(flowers.size())); + Material randomMaterial = flowers.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(flowers.size())); return randomMaterial.block(); })); registerHandler("PUMPKIN_AND_MELON_CRYSTAL_ORB_HANDLER", new ServerOrbHandler(crystalImpl -> { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/SkyBlockLevelLoader.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/SkyBlockLevelLoader.java index 20dd3c5c8..205d2b647 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/SkyBlockLevelLoader.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/SkyBlockLevelLoader.java @@ -154,7 +154,7 @@ private static SkyBlockLevelStatisticUnlock parseStatisticUnlock(LevelUnlockData builder.withMultiplicativePercentage(stat, value.multiplicativePercentage); } } catch (IllegalArgumentException e) { - System.err.println("Unknown statistic: " + entry.getKey()); + Logger.warn("Unknown statistic: {}", entry.getKey()); } } } @@ -167,7 +167,7 @@ private static CustomLevelUnlock parseCustomUnlock(LevelUnlockData data) { CustomLevelAward award = CustomLevelAward.valueOf(data.customAward.toUpperCase()); return new CustomLevelUnlock(award); } catch (IllegalArgumentException e) { - System.err.println("Unknown custom award: " + data.customAward); + Logger.error("Unknown custom award: {}", data.customAward); throw new RuntimeException("Unknown custom award: " + data.customAward); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/IslandMinionData.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/IslandMinionData.java index 9c0ed6c15..8ed0b46bf 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/IslandMinionData.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/IslandMinionData.java @@ -15,7 +15,8 @@ import net.swofty.type.skyblockgeneric.item.components.MinionUpgradeComponent; import net.swofty.type.skyblockgeneric.minion.extension.MinionExtensionData; import net.swofty.type.skyblockgeneric.minion.extension.extensions.MinionFuelExtension; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; +import net.swofty.type.skyblockgeneric.user.island.SkyBlockIsland; +import org.tinylog.Logger; import java.util.*; @@ -96,8 +97,8 @@ public boolean addItem(SkyBlockItem item) { } else { // If the item does not exist, add it as a new entry. if (item.getAttributeHandler().getPotentialType() == null) { - System.out.println(item.getAttributeHandler().getTypeAsString()); - throw new NullPointerException("Item type is null"); + throw new NullPointerException( + "Item type is null for " + item.getAttributeHandler().getTypeAsString()); } itemsInMinion.add(new ItemQuantifiable(item.getAttributeHandler().getPotentialType(), item.getAmount())); } @@ -172,7 +173,7 @@ public static IslandMinion deserialize(Map data) { try { amount = Integer.parseInt(item.substring(splitIndex + 1)); } catch (NumberFormatException e) { - System.err.println("Failed to parse item amount: " + item); + Logger.error("Failed to parse item amount: {}", item); throw new RuntimeException("Failed to parse item amount: " + item, e); } itemsInMinion.add(new ItemQuantifiable( @@ -180,7 +181,7 @@ public static IslandMinion deserialize(Map data) { amount )); } else { - System.err.println("Invalid item format: " + item); + Logger.error("Invalid item format: {}", item); throw new RuntimeException("Invalid item format: " + item); } }); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/MinionHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/MinionHandler.java index 34af4a329..2ea0d3299 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/MinionHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/minion/MinionHandler.java @@ -53,13 +53,12 @@ private void minionLoop() { if (!instance.isChunkLoaded(minionEntity.getPosition().chunkX(), minionEntity.getPosition().chunkZ())) return; - /** seems like I need this debug every other week, so keep it here for now - System.out.println("Minion loop"); - System.out.println("Time between actions: " + timeBetweenActions); - System.out.println("Current time diff: " + (System.currentTimeMillis() - lastAction)); - System.out.println("Tier: " + islandMinion.getTier()); - System.out.println("State: " + tags.getState()); - System.out.println("Step: " + tags.getCurrentStep());*/ + // Diagnostic trace — enable via tinylog debug level instead of uncommenting prints. + if (Logger.isDebugEnabled()) { + Logger.debug("Minion loop tier={} state={} step={} timeBetween={}ms timeSince={}ms", + islandMinion.getTier(), tags.getState(), tags.getCurrentStep(), + timeBetweenActions, System.currentTimeMillis() - lastAction); + } //Get the extra minion range granted from minion expanders int extraMinionRange = islandMinion.getBonusRange(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionBreakLog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionBreakLog.java index 32fa31055..dc94715df 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionBreakLog.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionBreakLog.java @@ -2,7 +2,6 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.CustomBlockBreakEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -13,9 +12,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionBreakLog extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void endMission(CustomBlockBreakEvent event) { if (event.getPlayerPlaced()) return; @@ -27,7 +28,7 @@ public void endMission(CustomBlockBreakEvent event) { data.endMission(MissionBreakLog.class); } - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, isAsync = true, phase = EventPhase.GAMEPLAY) public void startMission(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; MissionData data = ((SkyBlockPlayer) event.getPlayer()).getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWoodenPickaxe.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWoodenPickaxe.java index 58e55d11b..e19db5311 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWoodenPickaxe.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWoodenPickaxe.java @@ -2,7 +2,6 @@ import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.ItemCraftEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -13,9 +12,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCraftWoodenPickaxe extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onCraftEvent(ItemCraftEvent event) { MissionData data = event.getPlayer().getMissionData(); @@ -52,4 +53,4 @@ public void onEnd(SkyBlockPlayer player, Map customData, Mission public Set getValidRegions() { return Collections.singleton(RegionType.PRIVATE_ISLAND); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWorkbench.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWorkbench.java index b8310562f..a514aec0e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWorkbench.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionCraftWorkbench.java @@ -2,7 +2,6 @@ import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.ItemCraftEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -13,9 +12,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCraftWorkbench extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onCraftEvent(ItemCraftEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionKillZombies.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionKillZombies.java index da481f265..86560b0e8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionKillZombies.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionKillZombies.java @@ -2,7 +2,6 @@ import net.minestom.server.entity.EntityType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerKilledSkyBlockMobEvent; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.mission.MissionData; @@ -12,9 +11,11 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.*; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionKillZombies extends SkyBlockProgressMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onKilledZombie(PlayerKilledSkyBlockMobEvent event) { if (event.getKilledMob().getEntityType() != EntityType.ZOMBIE) return; @@ -64,4 +65,4 @@ public Double getAttachedSkyBlockXP() { public int getMaxProgress() { return 10; } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkJerry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkJerry.java index 5228d8d5b..a8a7e55e3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkJerry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkJerry.java @@ -5,7 +5,6 @@ import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.JerryClickedEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -16,10 +15,12 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkJerry extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onJerryClicked(JerryClickedEvent event) { MissionData data = event.getPlayer().getMissionData(); SkyBlockPlayer player = event.getPlayer(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToAuctionMaster.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToAuctionMaster.java index 6d44f3c7f..a192f15dd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToAuctionMaster.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToAuctionMaster.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -12,9 +11,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToAuctionMaster extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onRegionChange(PlayerRegionChangeEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToBanker.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToBanker.java index ce71c3255..6fbacd0e1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToBanker.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToBanker.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -12,9 +11,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToBanker extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onRegionChange(PlayerRegionChangeEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToLibrarian.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToLibrarian.java index ccf13dd20..80df6282e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToLibrarian.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionTalkToLibrarian.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -12,9 +11,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToLibrarian extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onRegionChange(PlayerRegionChangeEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionUseTeleporter.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionUseTeleporter.java index 3fee87900..9ba574a7e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionUseTeleporter.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/MissionUseTeleporter.java @@ -2,7 +2,6 @@ import net.swofty.type.generic.data.datapoints.DatapointDouble; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -10,10 +9,12 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.*; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionUseTeleporter extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onRegionChange(PlayerRegionChangeEvent event) { if (event.getTo() == null || !event.getTo().equals(RegionType.VILLAGE)) { return; @@ -55,4 +56,4 @@ public void onEnd(SkyBlockPlayer player, Map customData, Mission public Set getValidRegions() { return Collections.singleton(RegionType.PRIVATE_ISLAND); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionCraftWheatMinion.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionCraftWheatMinion.java index c82f10e8d..12de1f185 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionCraftWheatMinion.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionCraftWheatMinion.java @@ -2,7 +2,6 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.ItemCraftEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -11,9 +10,11 @@ import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCraftWheatMinion extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onCraftEvent(ItemCraftEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionTalkToFarmHand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionTalkToFarmHand.java index 9a78b086b..1da7c6a90 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionTalkToFarmHand.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/barn/MissionTalkToFarmHand.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions.barn; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.mission.MissionData; @@ -11,9 +10,11 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.*; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToFarmHand extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onRegionChange(PlayerRegionChangeEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionMineCoal.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionMineCoal.java index eee49bc0a..0cd0b2bf8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionMineCoal.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionMineCoal.java @@ -2,7 +2,6 @@ import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.CustomBlockBreakEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockProgressMission; @@ -11,9 +10,11 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.*; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionMineCoal extends SkyBlockProgressMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockBreak(CustomBlockBreakEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionTalkToBlacksmith.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionTalkToBlacksmith.java index 786d965ca..50ad2d2be 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionTalkToBlacksmith.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/blacksmith/MissionTalkToBlacksmith.java @@ -2,7 +2,6 @@ import net.minestom.server.coordinate.Pos; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.LocationAssociatedMission; import net.swofty.type.skyblockgeneric.mission.MissionData; @@ -13,10 +12,12 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToBlacksmith extends SkyBlockMission implements LocationAssociatedMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionCollectWheat.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionCollectWheat.java index 420cdbce7..4686be137 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionCollectWheat.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionCollectWheat.java @@ -2,7 +2,6 @@ import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.CustomBlockBreakEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockProgressMission; @@ -11,9 +10,11 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.*; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCollectWheat extends SkyBlockProgressMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockBreak(CustomBlockBreakEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionTalkToFarmer.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionTalkToFarmer.java index a44c84a9f..cb3d7b33b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionTalkToFarmer.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/farmer/MissionTalkToFarmer.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions.farmer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -11,9 +10,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToFarmer extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onRegionChange(PlayerRegionChangeEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionBreakOaklog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionBreakOaklog.java index 25c85720d..072b7db40 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionBreakOaklog.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionBreakOaklog.java @@ -3,7 +3,6 @@ import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.mission.MissionData; @@ -17,11 +16,13 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionBreakOaklog extends SkyBlockProgressMission { private final Map testTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onTick(PlayerTickEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (testTimes.containsKey(player.getUuid())) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionTalkToLumberjack.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionTalkToLumberjack.java index fb23c9254..b4b91c287 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionTalkToLumberjack.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/lumber/MissionTalkToLumberjack.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions.lumber; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -11,9 +10,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToLumberjack extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onRegionChange(PlayerRegionChangeEvent event) { MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionShearSheep.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionShearSheep.java index ee7446904..3854c5bc3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionShearSheep.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionShearSheep.java @@ -2,7 +2,6 @@ import net.minestom.server.entity.EntityType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerKilledSkyBlockMobEvent; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.mission.MissionData; @@ -12,10 +11,12 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.*; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionShearSheep extends SkyBlockProgressMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onKilledSheep(PlayerKilledSkyBlockMobEvent event) { if (event.getKilledMob().getEntityType() != EntityType.SHEEP) return; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionTalkToShepherd.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionTalkToShepherd.java index bd2f3623f..efafc60c2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionTalkToShepherd.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/sheperd/MissionTalkToShepherd.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions.sheperd; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -11,9 +10,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionTalkToShepherd extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onVillagerSpokenTo(NPCInteractEvent event) { MissionData data = ((SkyBlockPlayer) event.getPlayer()).getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionCollectBirchLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionCollectBirchLogs.java index 79fe162a6..c10d01ce3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionCollectBirchLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionCollectBirchLogs.java @@ -3,7 +3,6 @@ import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockProgressMission; @@ -14,12 +13,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCollectBirchLogs extends SkyBlockProgressMission { private final Map testTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onTick(PlayerTickEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (testTimes.containsKey(player.getUuid())) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionCollectDarkOakLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionCollectDarkOakLogs.java index 029d757d2..96d5732c8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionCollectDarkOakLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionCollectDarkOakLogs.java @@ -3,7 +3,6 @@ import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockProgressMission; @@ -14,12 +13,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCollectDarkOakLogs extends SkyBlockProgressMission { private final Map testTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onTick(PlayerTickEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (testTimes.containsKey(player.getUuid())) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionCollectJungleLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionCollectJungleLogs.java index c3d3743a7..dab93813b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionCollectJungleLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionCollectJungleLogs.java @@ -3,7 +3,6 @@ import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockProgressMission; @@ -14,12 +13,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCollectJungleLogs extends SkyBlockProgressMission { private final Map testTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onTick(PlayerTickEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (testTimes.containsKey(player.getUuid())) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheArea.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheArea.java index 545c07638..3c2388e86 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheArea.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheArea.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions.thepark.jungle; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -10,10 +9,12 @@ import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionLeaveTheArea extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { if (event.getTo() == null) return; MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheAreaAgain.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheAreaAgain.java index ab1c462d1..e43bd6fd0 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheAreaAgain.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionLeaveTheAreaAgain.java @@ -1,7 +1,6 @@ package net.swofty.type.skyblockgeneric.mission.missions.thepark.jungle; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -10,10 +9,12 @@ import java.util.Map; import java.util.Set; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionLeaveTheAreaAgain extends SkyBlockMission { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { if (event.getTo() == null) return; MissionData data = event.getPlayer().getMissionData(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCollectAcaciaLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCollectAcaciaLogs.java index 49d5d9c66..82d10edaa 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCollectAcaciaLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCollectAcaciaLogs.java @@ -3,7 +3,6 @@ import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockProgressMission; @@ -14,12 +13,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCollectAcaciaLogs extends SkyBlockProgressMission { private final Map testTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onTick(PlayerTickEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (testTimes.containsKey(player.getUuid())) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionCollectSpruceLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionCollectSpruceLogs.java index b80487da8..f464da797 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionCollectSpruceLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionCollectSpruceLogs.java @@ -3,7 +3,6 @@ import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.item.Material; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockProgressMission; @@ -14,12 +13,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class MissionCollectSpruceLogs extends SkyBlockProgressMission { private final Map testTimes = new HashMap<>(); - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onTick(PlayerTickEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); if (testTimes.containsKey(player.getUuid())) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/particle/ParticleEngine.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/particle/ParticleEngine.java index c78b7a2a0..a532fbb09 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/particle/ParticleEngine.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/particle/ParticleEngine.java @@ -59,7 +59,7 @@ public ParticleEngine offsets(Vec offsets) { public ParticleEngine shape(ParticleShape shape) { if (offsets != Vec.ZERO) - System.out.println("[WARNING] Particle offsets overridden by shape preset."); + org.tinylog.Logger.warn("Particle offsets overridden by shape preset."); this.shape = shape; return this; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/potion/handler/UtilityEffectHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/potion/handler/UtilityEffectHandler.java index ed98aa3c0..5031e0264 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/potion/handler/UtilityEffectHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/potion/handler/UtilityEffectHandler.java @@ -12,7 +12,7 @@ * Handler for utility potions (Night Vision, Fire Resistance, Water Breathing, etc.) * These primarily provide visual effects via Minestom and optionally stat bonuses. */ -public class UtilityEffectHandler implements PotionEffectHandler { +public final class UtilityEffectHandler implements PotionEffectHandler { private final PotionEffectType effectType; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisHasIslandLoaded.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisHasIslandLoaded.java index d3ceae626..0515d6c30 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisHasIslandLoaded.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisHasIslandLoaded.java @@ -1,20 +1,21 @@ package net.swofty.type.skyblockgeneric.redis; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.DoesServerHaveIslandProtocol; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.type.skyblockgeneric.user.SkyBlockIsland; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.type.skyblockgeneric.user.island.SkyBlockIsland; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisHasIslandLoaded implements TypedProxyHandler { +public class RedisHasIslandLoaded implements RedisMessageHandler { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new DoesServerHaveIslandProtocol(); } @Override - public DoesServerHaveIslandProtocol.Response onMessage(DoesServerHaveIslandProtocol.Request message) { + public DoesServerHaveIslandProtocol.Response handle(DoesServerHaveIslandProtocol.Request message, RedisMessageContext context) { UUID islandUUID = UUID.fromString(message.islandUuid()); return new DoesServerHaveIslandProtocol.Response(SkyBlockIsland.hasIsland(islandUUID), true, null); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRefreshCoopData.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRefreshCoopData.java index 98787f01f..10a3f8bcb 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRefreshCoopData.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRefreshCoopData.java @@ -1,8 +1,8 @@ package net.swofty.type.skyblockgeneric.redis; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.RefreshCoopDataProtocol; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; @@ -11,15 +11,16 @@ import org.bson.Document; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisRefreshCoopData implements TypedProxyHandler { +public class RedisRefreshCoopData implements RedisMessageHandler { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new RefreshCoopDataProtocol(); } @Override - public RefreshCoopDataProtocol.Response onMessage(RefreshCoopDataProtocol.Request message) { + public RefreshCoopDataProtocol.Response handle(RefreshCoopDataProtocol.Request message, RedisMessageContext context) { UUID uuid = UUID.fromString(message.uuid()); String datapoint = message.datapoint(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRunEvent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRunEvent.java index d00fe36fb..bac32fba4 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRunEvent.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/RedisRunEvent.java @@ -1,9 +1,9 @@ package net.swofty.type.skyblockgeneric.redis; import net.minestom.server.event.Event; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.RunEventProtocol; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.generic.event.HypixelEventHandler; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -11,15 +11,16 @@ import java.lang.reflect.InvocationTargetException; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class RedisRunEvent implements TypedProxyHandler { +public class RedisRunEvent implements RedisMessageHandler { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new RunEventProtocol(); } @Override - public RunEventProtocol.Response onMessage(RunEventProtocol.Request message) { + public RunEventProtocol.Response handle(RunEventProtocol.Request message, RedisMessageContext context) { UUID uuid = UUID.fromString(message.uuid()); String eventClassName = message.event(); String eventArgs = message.data(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedBazaarTransactionHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/BazaarTransactionHandler.java similarity index 93% rename from type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedBazaarTransactionHandler.java rename to type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/BazaarTransactionHandler.java index 75d9a35d2..c6cd36ec8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedBazaarTransactionHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/BazaarTransactionHandler.java @@ -1,13 +1,13 @@ package net.swofty.type.skyblockgeneric.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.bazaar.BazaarTransactionPushProtocol; import net.swofty.commons.protocol.objects.bazaar.BazaarTransactionPushProtocol.Request; import net.swofty.commons.protocol.objects.bazaar.BazaarTransactionPushProtocol.Response; import net.swofty.commons.skyblock.bazaar.BazaarTransaction; import net.swofty.commons.skyblock.bazaar.OrderExpiredBazaarTransaction; import net.swofty.commons.skyblock.bazaar.SuccessfulBazaarTransaction; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.bazaar.BazaarAwarder; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -15,18 +15,19 @@ import org.tinylog.Logger; import java.util.UUID; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedBazaarTransactionHandler implements TypedServiceHandler { +public class BazaarTransactionHandler implements RedisMessageHandler { private static final BazaarTransactionPushProtocol PROTOCOL = new BazaarTransactionPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { try { String transactionType = message.transactionType(); JSONObject data = new JSONObject(message.transactionJson()); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedDarkAuctionEventHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/DarkAuctionEventHandler.java similarity index 89% rename from type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedDarkAuctionEventHandler.java rename to type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/DarkAuctionEventHandler.java index 649745efb..62fd15b38 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedDarkAuctionEventHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/DarkAuctionEventHandler.java @@ -1,29 +1,30 @@ package net.swofty.type.skyblockgeneric.redis.service; import net.swofty.commons.ServerType; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.darkauction.DarkAuctionEventPushProtocol; import net.swofty.commons.protocol.objects.darkauction.DarkAuctionEventPushProtocol.Request; import net.swofty.commons.protocol.objects.darkauction.DarkAuctionEventPushProtocol.Response; import net.swofty.commons.protocol.objects.darkauction.DarkAuctionEventProtocol; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.skyblockgeneric.darkauction.DarkAuctionHandler; import org.json.JSONArray; import org.json.JSONObject; import org.tinylog.Logger; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedDarkAuctionEventHandler implements TypedServiceHandler { +public class DarkAuctionEventHandler implements RedisMessageHandler { private static final DarkAuctionEventPushProtocol PROTOCOL = new DarkAuctionEventPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request request) { + public Response handle(Request request, RedisMessageContext context) { if (HypixelConst.getTypeLoader().getType() != ServerType.SKYBLOCK_HUB) { return null; } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedGetPlayerDataHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/GetPlayerDataHandler.java similarity index 80% rename from type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedGetPlayerDataHandler.java rename to type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/GetPlayerDataHandler.java index bf28c31af..890a74874 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedGetPlayerDataHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/GetPlayerDataHandler.java @@ -1,26 +1,27 @@ package net.swofty.type.skyblockgeneric.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.data.GetPlayerDataPushProtocol; import net.swofty.commons.protocol.objects.data.GetPlayerDataPushProtocol.Request; import net.swofty.commons.protocol.objects.data.GetPlayerDataPushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedGetPlayerDataHandler implements TypedServiceHandler { +public class GetPlayerDataHandler implements RedisMessageHandler { private static final GetPlayerDataPushProtocol PROTOCOL = new GetPlayerDataPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { SkyBlockPlayer player = SkyBlockGenericLoader.getFromUUID(message.playerUUID()); if (player == null) { return Response.failure("Player not found on this server"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedLockPlayerDataHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/LockPlayerDataHandler.java similarity index 75% rename from type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedLockPlayerDataHandler.java rename to type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/LockPlayerDataHandler.java index 50b266928..5f23265ba 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedLockPlayerDataHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/LockPlayerDataHandler.java @@ -1,25 +1,26 @@ package net.swofty.type.skyblockgeneric.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.data.LockPlayerDataPushProtocol; import net.swofty.commons.protocol.objects.data.LockPlayerDataPushProtocol.Request; import net.swofty.commons.protocol.objects.data.LockPlayerDataPushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.redis.service.manager.ServerLockManager; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedLockPlayerDataHandler implements TypedServiceHandler { +public class LockPlayerDataHandler implements RedisMessageHandler { private static final LockPlayerDataPushProtocol PROTOCOL = new LockPlayerDataPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { SkyBlockPlayer player = SkyBlockGenericLoader.getFromUUID(message.playerUUID()); if (player == null) { return Response.failure("Player not found on this server"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedUnlockPlayerDataHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/UnlockPlayerDataHandler.java similarity index 66% rename from type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedUnlockPlayerDataHandler.java rename to type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/UnlockPlayerDataHandler.java index b60fc632c..2cbdaa3d4 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedUnlockPlayerDataHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/UnlockPlayerDataHandler.java @@ -1,23 +1,24 @@ package net.swofty.type.skyblockgeneric.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.data.UnlockPlayerDataPushProtocol; import net.swofty.commons.protocol.objects.data.UnlockPlayerDataPushProtocol.Request; import net.swofty.commons.protocol.objects.data.UnlockPlayerDataPushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.skyblockgeneric.redis.service.manager.ServerLockManager; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedUnlockPlayerDataHandler implements TypedServiceHandler { +public class UnlockPlayerDataHandler implements RedisMessageHandler { private static final UnlockPlayerDataPushProtocol PROTOCOL = new UnlockPlayerDataPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { String lockKey = message.playerUUID() + ":" + message.dataKey(); ServerLockManager.releaseLock(lockKey); return Response.success(System.currentTimeMillis()); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedUpdatePlayerDataHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/UpdatePlayerDataHandler.java similarity index 82% rename from type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedUpdatePlayerDataHandler.java rename to type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/UpdatePlayerDataHandler.java index f9da00e09..1bdbcd852 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/TypedUpdatePlayerDataHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/redis/service/UpdatePlayerDataHandler.java @@ -1,26 +1,27 @@ package net.swofty.type.skyblockgeneric.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.data.UpdatePlayerDataPushProtocol; import net.swofty.commons.protocol.objects.data.UpdatePlayerDataPushProtocol.Request; import net.swofty.commons.protocol.objects.data.UpdatePlayerDataPushProtocol.Response; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.data.Datapoint; import net.swofty.type.generic.data.HypixelDataHandler; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedUpdatePlayerDataHandler implements TypedServiceHandler { +public class UpdatePlayerDataHandler implements RedisMessageHandler { private static final UpdatePlayerDataPushProtocol PROTOCOL = new UpdatePlayerDataPushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request message) { + public Response handle(Request message, RedisMessageContext context) { SkyBlockPlayer player = SkyBlockGenericLoader.getFromUUID(message.playerUUID()); if (player == null) { return Response.failure("Player not found on this server"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java index f7eb978a2..429c4e9de 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java @@ -132,6 +132,17 @@ public enum RegionType { MURKWATER_SHALLOWS("Murkwater Shallows", "§3"), NORTH_WETLANDS("North Wetlands", "§2"), + // Backwater Bayou + BACKWATER_BAYOU("Backwater Bayou", "§2"), + CRIMSON_ISLE("Crimson Isle", "§c"), + BLAZING_VOLCANO("Blazing Volcano", "§4"), + DOJO("Dojo", "§6"), + MYSTIC_MARSH("Mystic Marsh", "§2"), + SCARLETON("Scarleton", "§c"), + BURNING_DESERT("Burning Desert", "§6"), + DRAGONTAIL("Dragontail", "§4"), + STRONGHOLD("Stronghold", "§4"), + DWARVEN_VILLAGE("Dwarven Village", DwarvenMinesConfiguration.class), DWARVEN_MINES("Dwarven Mines", "§2", DwarvenMinesConfiguration.class), GOBLIN_BURROWS("Goblin Burrows", DwarvenMinesConfiguration.class), diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerDefinition.java new file mode 100644 index 000000000..3d5304e3d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerDefinition.java @@ -0,0 +1,29 @@ +package net.swofty.type.skyblockgeneric.slayer; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; + +public record SlayerDefinition( + SlayerType type, + boolean enabled, + Optional unlockRequirement, + List targetMobTypes, + List levels, + Map tiers +) { + public boolean accepts(List mobTypes) { + return mobTypes.stream().anyMatch(targetMobTypes::contains); + } + + public int levelForXp(int xp) { + int level = 0; + for (SlayerLevelReward reward : levels) { + if (xp >= reward.requiredXp()) { + level = reward.level(); + } + } + return level; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerLevelReward.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerLevelReward.java new file mode 100644 index 000000000..babff5ac1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerLevelReward.java @@ -0,0 +1,4 @@ +package net.swofty.type.skyblockgeneric.slayer; + +public record SlayerLevelReward(int level, int requiredXp, String title) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerQuest.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerQuest.java new file mode 100644 index 000000000..03a78d9ea --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerQuest.java @@ -0,0 +1,21 @@ +package net.swofty.type.skyblockgeneric.slayer; + +import java.util.UUID; +import org.jetbrains.annotations.Nullable; + +public record SlayerQuest( + SlayerType type, + SlayerTier tier, + long startedAt, + int combatXp, + boolean bossSpawned, + @Nullable UUID bossUuid +) { + public SlayerQuest addCombatXp(int amount, int requiredCombatXp) { + return new SlayerQuest(type, tier, startedAt, Math.min(requiredCombatXp, combatXp + amount), false, null); + } + + public SlayerQuest markBossSpawned(UUID bossUuid) { + return new SlayerQuest(type, tier, startedAt, combatXp, true, bossUuid); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerRegistry.java new file mode 100644 index 000000000..48ee62148 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerRegistry.java @@ -0,0 +1,140 @@ +package net.swofty.type.skyblockgeneric.slayer; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.swofty.commons.YamlFileUtils; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.entity.mob.MobType; +import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SlayerRegistry { + private static final File SLAYERS_FILE = new File("./configuration/skyblock/slayers.yml"); + private static final Map DEFINITIONS = new LinkedHashMap<>(); + + public static void loadAll() { + DEFINITIONS.clear(); + + try { + Map root = YamlFileUtils.loadYaml(SLAYERS_FILE); + List> slayers = (List>) root.getOrDefault("slayers", Collections.emptyList()); + for (Map entry : slayers) { + SlayerType type = SlayerType.valueOf(string(entry, "id")); + DEFINITIONS.put(type, new SlayerDefinition( + type, + booleanValue(entry, "enabled", true), + unlock((Map) entry.get("unlock")), + mobTypes((List) entry.getOrDefault("targetMobTypes", Collections.emptyList())), + levels((List>) entry.getOrDefault("levels", Collections.emptyList())), + tiers((List>) entry.getOrDefault("tiers", Collections.emptyList())) + )); + } + } catch (Exception exception) { + Logger.error(exception, "Failed to load slayer configuration"); + } + } + + public static @Nullable SlayerDefinition get(SlayerType type) { + return DEFINITIONS.get(type); + } + + public static List all() { + return List.copyOf(DEFINITIONS.values()); + } + + private static List mobTypes(List values) { + List result = new ArrayList<>(); + for (Object value : values) { + result.add(MobType.valueOf(String.valueOf(value))); + } + return result; + } + + private static Optional unlock(@Nullable Map entry) { + if (entry == null || entry.isEmpty()) { + return Optional.empty(); + } + return Optional.of(new SlayerUnlockRequirement( + SlayerType.valueOf(string(entry, "type")), + SlayerTier.valueOf(string(entry, "tier")) + )); + } + + private static List levels(List> entries) { + List result = new ArrayList<>(); + for (Map entry : entries) { + result.add(new SlayerLevelReward( + intValue(entry, "level", 0), + intValue(entry, "requiredXp", 0), + string(entry, "title") + )); + } + return result; + } + + private static Map tiers(List> entries) { + Map result = new EnumMap<>(SlayerTier.class); + for (Map entry : entries) { + SlayerTier tier = SlayerTier.valueOf(string(entry, "tier")); + result.put(tier, new SlayerTierDefinition( + tier, + intValue(entry, "cost", 0), + intValue(entry, "requiredCombatXp", 0), + intValue(entry, "slayerXp", 0), + intValue(entry, "bossLevel", 1), + doubleValue(entry, "bossHealth", 100D), + doubleValue(entry, "bossDamage", 5D), + doubleValue(entry, "bossSpeed", 100D), + intValue(entry, "tokenDrops", 0), + optionalItem(entry.get("tokenItem")) + )); + } + return result; + } + + private static Optional optionalItem(Object value) { + if (value == null || String.valueOf(value).isBlank()) { + return Optional.empty(); + } + return Optional.of(ItemType.valueOf(String.valueOf(value))); + } + + private static String string(Map map, String key) { + Object value = map.get(key); + if (value == null) { + throw new IllegalArgumentException("Missing required slayer key '" + key + "'"); + } + return String.valueOf(value); + } + + private static int intValue(Map map, String key, int fallback) { + Object value = map.get(key); + if (value == null) return fallback; + if (value instanceof Number number) return number.intValue(); + return Integer.parseInt(String.valueOf(value)); + } + + private static double doubleValue(Map map, String key, double fallback) { + Object value = map.get(key); + if (value == null) return fallback; + if (value instanceof Number number) return number.doubleValue(); + return Double.parseDouble(String.valueOf(value)); + } + + private static boolean booleanValue(Map map, String key, boolean fallback) { + Object value = map.get(key); + if (value == null) return fallback; + if (value instanceof Boolean bool) return bool; + return Boolean.parseBoolean(String.valueOf(value)); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerService.java new file mode 100644 index 000000000..b7a12a20d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerService.java @@ -0,0 +1,237 @@ +package net.swofty.type.skyblockgeneric.slayer; + +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.kyori.adventure.text.Component; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.instance.Instance; +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSlayer; +import net.swofty.type.skyblockgeneric.elections.ElectionManager; +import net.swofty.type.skyblockgeneric.elections.SkyBlockMayor; +import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossMob; +import net.swofty.type.skyblockgeneric.entity.mob.mobs.slayer.SlayerBossProfile; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SlayerService { + public static StartResult startQuest(SkyBlockPlayer player, SlayerType type, SlayerTier tier) { + DatapointSlayer.SlayerData data = data(player); + if (data.getActiveQuest() != null) { + return StartResult.alreadyActive(data.getActiveQuest()); + } + + SlayerDefinition definition = SlayerRegistry.get(type); + if (definition == null || !definition.enabled()) { + return StartResult.unavailable(type); + } + + SlayerTierDefinition tierDefinition = definition.tiers().get(tier); + if (tierDefinition == null) { + return StartResult.missingTier(type, tier); + } + + if (definition.unlockRequirement().isPresent()) { + SlayerUnlockRequirement requirement = definition.unlockRequirement().get(); + if (data.progress(requirement.type()).completions(requirement.tier()) <= 0) { + return StartResult.locked(requirement); + } + } + + int cost = questCost(tierDefinition); + if (player.getCoins() < cost) { + return StartResult.notEnoughCoins(cost); + } + + player.removeCoins(cost); + SlayerQuest quest = new SlayerQuest(type, tier, System.currentTimeMillis(), 0, false, null); + data.setActiveQuest(quest); + save(player, data); + player.sendMessage("§5§lSLAYER QUEST STARTED!"); + player.sendMessage("§7Slay " + type.categoryName() + " mobs to summon §c" + tierDefinition.displayName(type) + "§7."); + return StartResult.started(quest); + } + + public static void cancelQuest(SkyBlockPlayer player) { + DatapointSlayer.SlayerData data = data(player); + if (data.getActiveQuest() == null) { + player.sendMessage("§cYou do not have an active Slayer quest."); + return; + } + data.setActiveQuest(null); + save(player, data); + player.sendMessage("§cSlayer quest cancelled!"); + } + + public static void handleMobKill(SkyBlockPlayer player, SkyBlockMob mob) { + DatapointSlayer.SlayerData data = data(player); + SlayerQuest quest = data.getActiveQuest(); + if (quest == null || mob == null) { + return; + } + + if (mob instanceof SlayerBossMob bossMob) { + completeBoss(player, data, quest, bossMob); + return; + } + + if (quest.bossSpawned()) { + return; + } + + SlayerDefinition definition = SlayerRegistry.get(quest.type()); + if (definition == null || !definition.accepts(mob.getMobTypes())) { + return; + } + + SlayerTierDefinition tierDefinition = definition.tiers().get(quest.tier()); + if (tierDefinition == null) { + return; + } + + int gainedXp = Math.max(1, (int) mob.getOtherLoot().getSkillXPAmount()); + SlayerQuest progressedQuest = quest.addCombatXp(gainedXp, tierDefinition.requiredCombatXp()); + if (progressedQuest.combatXp() >= tierDefinition.requiredCombatXp()) { + SlayerBossMob boss = spawnBoss(player, definition, tierDefinition, mob.getPosition()); + if (boss != null) { + progressedQuest = progressedQuest.markBossSpawned(boss.getUuid()); + player.sendMessage("§c§lSLAYER BOSS SPAWNED!"); + player.sendMessage("§7Kill §c" + tierDefinition.displayName(quest.type()) + "§7 to complete your quest."); + } + } else { + int remaining = tierDefinition.requiredCombatXp() - progressedQuest.combatXp(); + player.sendMessage("§5Slayer Quest §7" + progressedQuest.combatXp() + "§8/§7" + + tierDefinition.requiredCombatXp() + " Combat XP §8(§e" + remaining + " left§8)"); + } + + data.setActiveQuest(progressedQuest); + save(player, data); + } + + public static QuestStatus status(SkyBlockPlayer player) { + DatapointSlayer.SlayerData data = data(player); + SlayerQuest quest = data.getActiveQuest(); + if (quest == null) { + return QuestStatus.none(); + } + + SlayerDefinition definition = SlayerRegistry.get(quest.type()); + SlayerTierDefinition tier = definition == null ? null : definition.tiers().get(quest.tier()); + return new QuestStatus(quest, definition, tier); + } + + private static void completeBoss(SkyBlockPlayer player, DatapointSlayer.SlayerData data, SlayerQuest quest, SlayerBossMob bossMob) { + if (!bossMob.getOwnerUuid().equals(player.getUuid())) { + return; + } + + SlayerDefinition definition = SlayerRegistry.get(quest.type()); + SlayerTierDefinition tierDefinition = definition == null ? null : definition.tiers().get(quest.tier()); + if (definition == null || tierDefinition == null) { + return; + } + + DatapointSlayer.SlayerProgress progress = data.progress(quest.type()); + int slayerXp = slayerXpReward(tierDefinition); + progress.setXp(progress.getXp() + slayerXp); + progress.addCompletion(quest.tier()); + data.setActiveQuest(null); + save(player, data); + + int level = definition.levelForXp(progress.getXp()); + player.sendMessage("§a§lSLAYER QUEST COMPLETE!"); + player.sendMessage("§7You gained §d" + slayerXp + " " + quest.type().categoryName() + " Slayer XP§7."); + player.sendMessage("§7" + quest.type().categoryName() + " Slayer Level: §e" + level + " §8(§d" + progress.getXp() + " XP§8)"); + } + + private static int questCost(SlayerTierDefinition tierDefinition) { + if (ElectionManager.isPerkActive(SkyBlockMayor.Perk.SLASHED_PRICING)) { + return Math.max(1, tierDefinition.cost() / 2); + } + return tierDefinition.cost(); + } + + private static int slayerXpReward(SlayerTierDefinition tierDefinition) { + if (ElectionManager.isPerkActive(SkyBlockMayor.Perk.SLAYER_XP_BUFF)) { + return (int) Math.round(tierDefinition.slayerXp() * 1.25D); + } + return tierDefinition.slayerXp(); + } + + private static @Nullable SlayerBossMob spawnBoss(SkyBlockPlayer player, SlayerDefinition definition, SlayerTierDefinition tierDefinition, Pos position) { + Instance instance = player.getInstance(); + if (instance == null) { + return null; + } + + SlayerBossProfile profile = new SlayerBossProfile( + definition.type(), + tierDefinition, + definition.targetMobTypes(), + definition.type().entityType() + ); + SlayerBossMob mob = SlayerBossMob.create(player.getUuid(), profile); + mob.setInstance(instance, position); + broadcastSpawn(player, tierDefinition.displayName(definition.type()), instance, position); + return mob; + } + + private static void broadcastSpawn(SkyBlockPlayer player, String bossName, Instance instance, Pos position) { + Component message = Component.text("§c§lSLAYER BOSS! §7" + player.getUsername() + " spawned §c" + bossName + "§7!"); + instance.getPlayers().stream() + .filter(nearby -> nearby.getPosition().distance(position) <= 32) + .forEach(nearby -> nearby.sendMessage(message)); + } + + private static DatapointSlayer.SlayerData data(SkyBlockPlayer player) { + return player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SLAYER, DatapointSlayer.class).getValue(); + } + + private static void save(SkyBlockPlayer player, DatapointSlayer.SlayerData data) { + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SLAYER, DatapointSlayer.class).setValue(data); + } + + public record QuestStatus( + @Nullable SlayerQuest quest, + @Nullable SlayerDefinition definition, + @Nullable SlayerTierDefinition tier + ) { + public static QuestStatus none() { + return new QuestStatus(null, null, null); + } + + public boolean active() { + return quest != null; + } + } + + public record StartResult(boolean success, String message, Optional quest) { + public static StartResult started(SlayerQuest quest) { + return new StartResult(true, "Started", Optional.of(quest)); + } + + public static StartResult alreadyActive(SlayerQuest quest) { + return new StartResult(false, "You already have an active Slayer quest.", Optional.of(quest)); + } + + public static StartResult unavailable(SlayerType type) { + return new StartResult(false, type.displayName() + " is not available here.", Optional.empty()); + } + + public static StartResult missingTier(SlayerType type, SlayerTier tier) { + return new StartResult(false, type.displayName() + " " + tier.numeral() + " is not configured.", Optional.empty()); + } + + public static StartResult notEnoughCoins(int cost) { + return new StartResult(false, "You need " + cost + " coins to start this quest.", Optional.empty()); + } + + public static StartResult locked(SlayerUnlockRequirement requirement) { + return new StartResult(false, "You must slay " + requirement.type().displayName() + " " + + requirement.tier().numeral() + " first.", Optional.empty()); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerTier.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerTier.java new file mode 100644 index 000000000..ae630c172 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerTier.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.slayer; + +public enum SlayerTier { + I(1, "I"), + II(2, "II"), + III(3, "III"), + IV(4, "IV"), + V(5, "V"); + + private final int number; + private final String numeral; + + SlayerTier(int number, String numeral) { + this.number = number; + this.numeral = numeral; + } + + public int number() { + return number; + } + + public String numeral() { + return numeral; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerTierDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerTierDefinition.java new file mode 100644 index 000000000..84eb8f31f --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerTierDefinition.java @@ -0,0 +1,21 @@ +package net.swofty.type.skyblockgeneric.slayer; + +import java.util.Optional; +import net.swofty.commons.skyblock.item.ItemType; + +public record SlayerTierDefinition( + SlayerTier tier, + int cost, + int requiredCombatXp, + int slayerXp, + int bossLevel, + double bossHealth, + double bossDamage, + double bossSpeed, + int tokenDrops, + Optional tokenItem +) { + public String displayName(SlayerType type) { + return type.displayName() + " " + tier.numeral(); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerType.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerType.java new file mode 100644 index 000000000..6a8000bda --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerType.java @@ -0,0 +1,47 @@ +package net.swofty.type.skyblockgeneric.slayer; + +import net.minestom.server.entity.EntityType; +import net.minestom.server.item.Material; + +public enum SlayerType { + REVENANT_HORROR("Zombie", "Revenant Horror", "§c", EntityType.ZOMBIE, Material.ROTTEN_FLESH), + TARANTULA_BROODFATHER("Spider", "Tarantula Broodfather", "§5", EntityType.SPIDER, Material.SPIDER_EYE), + SVEN_PACKMASTER("Wolf", "Sven Packmaster", "§f", EntityType.WOLF, Material.BONE), + VOIDGLOOM_SERAPH("Enderman", "Voidgloom Seraph", "§5", EntityType.ENDERMAN, Material.ENDER_PEARL), + RIFTSTALKER_BLOODFIEND("Vampire", "Riftstalker Bloodfiend", "§4", EntityType.ZOMBIE, Material.RED_DYE), + INFERNO_DEMONLORD("Blaze", "Inferno Demonlord", "§6", EntityType.BLAZE, Material.BLAZE_ROD); + + private final String categoryName; + private final String displayName; + private final String color; + private final EntityType entityType; + private final Material menuMaterial; + + SlayerType(String categoryName, String displayName, String color, EntityType entityType, Material menuMaterial) { + this.categoryName = categoryName; + this.displayName = displayName; + this.color = color; + this.entityType = entityType; + this.menuMaterial = menuMaterial; + } + + public String categoryName() { + return categoryName; + } + + public String displayName() { + return displayName; + } + + public String coloredName() { + return color + displayName; + } + + public EntityType entityType() { + return entityType; + } + + public Material menuMaterial() { + return menuMaterial; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerUnlockRequirement.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerUnlockRequirement.java new file mode 100644 index 000000000..289ca8a2b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/slayer/SlayerUnlockRequirement.java @@ -0,0 +1,4 @@ +package net.swofty.type.skyblockgeneric.slayer; + +public record SlayerUnlockRequirement(SlayerType type, SlayerTier tier) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockIsland.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockIsland.java deleted file mode 100644 index 4ae326c89..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockIsland.java +++ /dev/null @@ -1,203 +0,0 @@ -package net.swofty.type.skyblockgeneric.user; - -import lombok.Getter; -import lombok.Setter; -import net.hollowcube.polar.PolarLoader; -import net.hollowcube.polar.PolarReader; -import net.hollowcube.polar.PolarWorld; -import net.hollowcube.polar.PolarWriter; -import net.kyori.adventure.key.Key; -import net.minestom.server.MinecraftServer; -import net.minestom.server.instance.InstanceContainer; -import net.minestom.server.instance.InstanceManager; -import net.minestom.server.instance.SharedInstance; -import net.minestom.server.registry.RegistryKey; -import net.minestom.server.timer.ExecutionType; -import net.minestom.server.timer.Scheduler; -import net.minestom.server.timer.TaskSchedule; -import net.minestom.server.world.DimensionType; -import net.swofty.commons.CustomWorlds; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.event.HypixelEventHandler; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.MathUtility; -import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; -import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; -import net.swofty.type.skyblockgeneric.data.monogdb.IslandDatabase; -import net.swofty.type.skyblockgeneric.event.custom.IslandFetchedFromDatabaseEvent; -import net.swofty.type.skyblockgeneric.event.custom.IslandFirstCreatedEvent; -import net.swofty.type.skyblockgeneric.event.custom.IslandSavedIntoDatabaseEvent; -import net.swofty.type.skyblockgeneric.minion.IslandMinionData; -import net.swofty.type.skyblockgeneric.utility.JerryInformation; -import org.bson.types.Binary; -import org.jetbrains.annotations.Nullable; -import org.tinylog.Logger; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -@Getter -public class SkyBlockIsland { - private static final Path ISLAND_TEMPLATE_PATH = CustomWorlds.SKYBLOCK_ISLAND_TEMPLATE.getPath(); - private static final Map loadedIslands = new HashMap<>(); - - // Internal Island Data - private final IslandDatabase database; - private final CoopDatabase.Coop coop; - private final UUID islandID; - private Boolean created = false; - private SharedInstance islandInstance; - private PolarWorld world; - - // External Island Data - @Setter - private JerryInformation jerryInformation = null; - @Setter - private IslandMinionData minionData = null; - @Setter - private long lastSaved = 0; - @Setter - private Integer islandVersion; - - public SkyBlockIsland(UUID islandID, UUID profileID) { - this.islandID = islandID; - this.database = new IslandDatabase(islandID.toString()); - this.coop = CoopDatabase.getFromMemberProfile(profileID); - - loadedIslands.put(islandID, this); - } - - public CompletableFuture getSharedInstance() { - InstanceManager manager = MinecraftServer.getInstanceManager(); - CompletableFuture future = new CompletableFuture<>(); - - new Thread(() -> { - if (created) { - future.complete(islandInstance); - return; - } - RegistryKey dimensionTypeKey = MinecraftServer.getDimensionTypeRegistry().getKey( - Key.key("skyblock:island") - ); - InstanceContainer temporaryInstance = manager.createInstanceContainer(dimensionTypeKey); - islandInstance = manager.createSharedInstance(temporaryInstance); - - List onlinePlayers; - if (coop != null) { - onlinePlayers = coop.getOnlineMembers(); - } else { - // Island ID will be the same as the profile ID if the island is not a coop - try { - onlinePlayers = List.of(SkyBlockGenericLoader.getPlayerFromProfileUUID(islandID)); - } catch (NullPointerException e) { - // Player doesn't have their data loaded yet - onlinePlayers = List.of(); - } - } - - if (!database.exists()) { - islandVersion = HypixelConst.getCurrentIslandVersion(); - try { - world = new PolarLoader(ISLAND_TEMPLATE_PATH).world(); - } catch (IOException e) { - Logger.error("Failed to create island world", e); - throw new RuntimeException("Failed to create island world", e); - } - - HypixelEventHandler.callCustomEvent(new IslandFirstCreatedEvent( - this, coop != null, coop != null ? coop.memberProfiles() : List.of(islandID) - )); - } else { - if (database.has("version")) - islandVersion = (int) database.get("version", Integer.class); - else islandVersion = 0; - - switch (islandVersion) { - case 0: - lastSaved = System.currentTimeMillis(); - try { - world = new PolarLoader(ISLAND_TEMPLATE_PATH).world(); - } catch (IOException e) { - throw new RuntimeException(e); - } - break; - case 1: - world = PolarReader.read(((Binary) database.get("data", Binary.class)).getData()); - lastSaved = (long) database.get("lastSaved", Long.class); - break; - } - - int oldVersion = islandVersion; - if (islandVersion < HypixelConst.getCurrentIslandVersion()) { - MathUtility.delay(() -> { - SkyBlockGenericLoader.getLoadedPlayers().stream().filter(player -> player.getSkyBlockIsland().getIslandID() == islandID).forEach(player -> { - player.getLogHandler().debug("Your island was migrated from version §c" + oldVersion + " §fto §a" + HypixelConst.getCurrentIslandVersion() + "§f!"); - }); - }, 20); - islandVersion = HypixelConst.getCurrentIslandVersion(); - } - } - temporaryInstance.setChunkLoader(new PolarLoader(world)); - - this.created = true; - - HypixelEventHandler.callCustomEvent(new IslandFetchedFromDatabaseEvent( - this, coop != null, onlinePlayers, coop != null ? coop.memberProfiles() : List.of(islandID)) - ); - - future.complete(islandInstance); - onlinePlayers.forEach(HypixelPlayer::setReadyForEvents); - }).start(); - - return future; - } - - public void runVacantCheck() { - if (islandInstance == null) return; - - if (islandInstance.getPlayers().isEmpty()) { - HypixelEventHandler.callCustomEvent(new IslandSavedIntoDatabaseEvent( - this, coop != null, coop != null ? coop.memberProfiles() : List.of(islandID) - )); - - save(); - this.created = false; - islandInstance.getChunks().forEach(chunk -> { - islandInstance.unloadChunk(chunk); - }); - this.islandInstance = null; - this.world = null; - } - } - - private void save() { - new PolarLoader(world).saveInstance(islandInstance); - database.insertOrUpdate("data", new Binary(PolarWriter.write(world))); - database.insertOrUpdate("lastSaved", System.currentTimeMillis()); - database.insertOrUpdate("version", islandVersion); - } - - public static boolean hasIsland(UUID islandID) { - return loadedIslands.containsKey(islandID); - } - - public static @Nullable SkyBlockIsland getIsland(UUID islandID) { - if (!loadedIslands.containsKey(islandID)) return null; - return loadedIslands.get(islandID); - } - - public static void runVacantLoop(Scheduler scheduler) { - scheduler.submitTask(() -> { - SkyBlockGenericLoader.getLoadedPlayers().forEach(player -> { - if (player.isOnIsland()) - player.getSkyBlockIsland().runVacantCheck(); - }); - return TaskSchedule.tick(4); - }, ExecutionType.TICK_END); - } -} \ No newline at end of file diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java index b570aaf60..82eb87372 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java @@ -19,8 +19,8 @@ import net.minestom.server.network.packet.server.play.UpdateHealthPacket; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.tag.Tag; import net.swofty.commons.StringUtility; +import net.minestom.server.tag.Tag; import net.swofty.commons.skyblock.PlayerShopData; import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; import net.swofty.commons.skyblock.item.ItemType; @@ -65,6 +65,7 @@ import net.swofty.type.skyblockgeneric.region.mining.MineableBlock; import net.swofty.type.skyblockgeneric.region.mining.handler.SkyBlockMiningHandler; import net.swofty.type.skyblockgeneric.skill.skills.RunecraftingSkill; +import net.swofty.type.skyblockgeneric.user.island.SkyBlockIsland; import net.swofty.type.skyblockgeneric.user.statistics.PlayerStatistics; import net.swofty.type.skyblockgeneric.utility.DeathMessageCreator; import org.intellij.lang.annotations.MagicConstant; @@ -551,6 +552,18 @@ public DatapointQuiver.PlayerQuiver getQuiver() { return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.QUIVER, DatapointQuiver.class).getValue(); } + public DatapointShipState.ShipState getShipState() { + return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).getValue(); + } + + public DatapointTrophyFish.TrophyFishData getTrophyFishData() { + return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.TROPHY_FISH, DatapointTrophyFish.class).getValue(); + } + + public DatapointSlayer.SlayerData getSlayerData() { + return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SLAYER, DatapointSlayer.class).getValue(); + } + public DatapointAccessoryBag.PlayerAccessoryBag getAccessoryBag() { return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.ACCESSORY_BAG, DatapointAccessoryBag.class).getValue(); } @@ -669,7 +682,7 @@ public int getMaxSackStorage(ItemType sack) { if (matcher.find()) { sackCategory = matcher.group(2); } else { - System.out.println("Invalid sack name: " + sack.name()); + org.tinylog.Logger.warn("Invalid sack name: {}", sack.name()); return 0; } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/flow/SkyBlockPlayerDataFlow.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/flow/SkyBlockPlayerDataFlow.java new file mode 100644 index 000000000..af7afe754 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/flow/SkyBlockPlayerDataFlow.java @@ -0,0 +1,228 @@ +package net.swofty.type.skyblockgeneric.user.flow; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; +import net.minestom.server.MinecraftServer; +import net.minestom.server.network.packet.server.play.UpdateHealthPacket; +import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; +import net.swofty.packer.packs.TestingTexture; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.generic.data.datapoints.DatapointBoolean; +import net.swofty.type.generic.data.datapoints.DatapointString; +import net.swofty.type.generic.data.datapoints.DatapointStringList; +import net.swofty.type.generic.data.mongodb.ProfilesDatabase; +import net.swofty.type.generic.data.mongodb.UserDatabase; +import net.swofty.type.generic.event.HypixelEventHandler; +import net.swofty.type.generic.user.categories.CustomGroups; +import net.swofty.type.generic.user.categories.Rank; +import net.swofty.type.generic.utility.MathUtility; +import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointUUID; +import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; +import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; +import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.user.island.SkyBlockIsland; +import net.swofty.type.skyblockgeneric.warps.TravelScrollIslands; +import org.bson.Document; + +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class SkyBlockPlayerDataFlow { + + public static void load(SkyBlockPlayer player) { + UUID playerUuid = player.getUuid(); + SkyBlockPlayerProfiles profiles = loadProfiles(player); + UUID profileId = profiles.getCurrentlySelected(); + + ProfilesDatabase profileDb = new ProfilesDatabase(profileId.toString()); + SkyBlockDataHandler handler; + boolean shouldPersistProfile = false; + + if (profileDb.exists()) { + Document profileDocument = profileDb.getDocument(); + handler = SkyBlockDataHandler.createFromProfile(playerUuid, profileId, profileDocument); + } else { + handler = SkyBlockDataHandler.initUserWithDefaultData(playerUuid, profileId); + shouldPersistProfile = true; + } + + DatapointUUID islandDatapoint = handler.get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class); + UUID islandUuid = islandDatapoint.getValue(); + if (islandUuid == null) { + islandUuid = profileId; + islandDatapoint.setValue(islandUuid); + shouldPersistProfile = true; + } + + DatapointString profileNameDatapoint = handler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class); + if (Objects.equals(profileNameDatapoint.getValue(), "null")) { + profileNameDatapoint.setValue(SkyBlockPlayerProfiles.getRandomName()); + shouldPersistProfile = true; + } + + SkyBlockDataHandler.skyBlockCache.put(playerUuid, handler); + + if (shouldPersistProfile) { + profileDb.saveDocument(handler.toProfileDocument()); + } + + player.setSkyBlockIsland(SkyBlockIsland.getOrCreate(islandUuid, profileId)); + } + + public static void postSpawn(SkyBlockPlayer player) { + SkyBlockPlayerProfiles profiles = player.getProfiles(); + SkyBlockDataHandler handler = player.getSkyblockDataHandler(); + handler.runOnLoad(player); + + syncCoopValues(player, profiles, handler); + scheduleRegionRefresh(player); + sendProfileIntro(player); + } + + public static void save(SkyBlockPlayer player) { + UUID playerUuid = player.getUuid(); + SkyBlockDataHandler handler = SkyBlockDataHandler.skyBlockCache.get(playerUuid); + + if (handler == null) return; + + handler.runOnSave(player); + + UUID profileId = handler.getCurrentProfileId(); + ProfilesDatabase profileDb = new ProfilesDatabase(profileId.toString()); + Document newDoc = handler.toProfileDocument(); + + if (profileDb.exists()) { + ProfilesDatabase.collection.replaceOne(com.mongodb.client.model.Filters.eq("_id", profileId.toString()), newDoc); + } else { + ProfilesDatabase.collection.insertOne(newDoc); + } + + SkyBlockDataHandler.skyBlockCache.remove(playerUuid); + } + + private static SkyBlockPlayerProfiles loadProfiles(SkyBlockPlayer player) { + UserDatabase userDatabase = new UserDatabase(player.getUuid()); + SkyBlockPlayerProfiles profiles = userDatabase.getProfiles(); + + if (profiles == null) { + UUID profileId = UUID.randomUUID(); + profiles = new SkyBlockPlayerProfiles(player.getUuid()); + profiles.setCurrentlySelected(profileId); + profiles.addProfile(profileId); + userDatabase.saveProfiles(profiles); + return profiles; + } + + if (profiles.getCurrentlySelected() == null) { + UUID profileId = UUID.randomUUID(); + profiles.setCurrentlySelected(profileId); + profiles.addProfile(profileId); + userDatabase.saveProfiles(profiles); + } + + return profiles; + } + + private static void syncCoopValues(SkyBlockPlayer player, SkyBlockPlayerProfiles profiles, SkyBlockDataHandler handler) { + if (!handler.get(SkyBlockDataHandler.Data.IS_COOP, DatapointBoolean.class).getValue()) return; + + CoopDatabase.Coop coop = CoopDatabase.getFromMember(player.getUuid()); + if (coop == null) return; + if (coop.members().size() == 1) return; + + SkyBlockDataHandler sourceData; + if (SkyBlockGenericLoader.getLoadedPlayers().stream() + .anyMatch(player1 -> !player1.getUuid().equals(player.getUuid()) && coop.members().contains(player1.getUuid()))) { + SkyBlockPlayer otherCoopMember = SkyBlockGenericLoader.getLoadedPlayers().stream() + .filter(player1 -> !player1.getUuid().equals(player.getUuid()) && coop.members().contains(player1.getUuid())) + .findFirst() + .get(); + sourceData = otherCoopMember.getSkyblockDataHandler(); + } else { + UUID finalProfileId = profiles.getCurrentlySelected(); + sourceData = SkyBlockDataHandler.createFromProfileOnly( + new ProfilesDatabase(coop.memberProfiles().stream() + .filter(uuid -> !uuid.equals(finalProfileId)) + .findFirst() + .get().toString()).getDocument() + ); + } + + sourceData.getCoopValues().forEach((key, value) -> { + SkyBlockDatapoint targetDatapoint = (SkyBlockDatapoint) handler.getSkyBlockDatapoint(key); + targetDatapoint.setValueBypassCoop(value); + }); + } + + private static void scheduleRegionRefresh(SkyBlockPlayer player) { + MathUtility.delay(() -> { + SkyBlockRegion playerRegion = player.getRegion(); + if (playerRegion != null && player.isOnline()) { + HypixelEventHandler.callCustomEvent(new PlayerRegionChangeEvent( + player, + null, + playerRegion.getType() + )); + } + }, 50); + } + + private static void sendProfileIntro(SkyBlockPlayer player) { + Thread.startVirtualThread(() -> { + player.sendMessage(""); + player.showTitle(Title.title( + Component.text(TestingTexture.FULL_SCREEN_BLACK.toString()), + Component.empty(), + Title.Times.times(Duration.ZERO, Duration.ofMillis(300), Duration.ofSeconds(1)) + )); + + Rank rank = player.getRank(); + if (rank.isStaff()) { + CustomGroups.staffMembers.add(player); + } + + player.sendMessage("§7 "); + player.sendMessage("§aYou are playing on profile: §e" + player.getSkyblockDataHandler().get( + SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue()); + player.sendMessage("§8Profile ID: " + player.getProfiles().getCurrentlySelected()); + + UUID islandUuid = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class).getValue(); + if (!islandUuid.equals(player.getProfiles().getCurrentlySelected())) { + player.sendMessage("§8Island ID: " + islandUuid); + } + player.sendMessage(" "); + + player.health = player.getMaxHealth(); + player.sendPacket(new UpdateHealthPacket((player.health / player.getMaxHealth()) * 20, 20, 20)); + + MinecraftServer.getBossBarManager().removeAllBossBars(player); + MathUtility.delay(() -> { + if (!player.isOnline()) return; + player.getPetData().updatePetEntityImpl(player); + }, 20); + + TravelScrollIslands island = TravelScrollIslands.getFromType(HypixelConst.getTypeLoader().getType()); + if (island != null) { + List visitedIslands = player.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.VISITED_ISLANDS, DatapointStringList.class) + .getValue(); + if (!visitedIslands.contains(island.getInternalName())) { + visitedIslands.add(island.getInternalName()); + player.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.VISITED_ISLANDS, DatapointStringList.class) + .setValue(visitedIslands); + } + } + }); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycle.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycle.java new file mode 100644 index 000000000..fdbe2fc07 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycle.java @@ -0,0 +1,48 @@ +package net.swofty.type.skyblockgeneric.user.island; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import org.tinylog.Logger; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class IslandLifecycle { + private static final List steps = new CopyOnWriteArrayList<>(); + + public static void register(IslandLifecycleStep step) { + steps.add(step); + steps.sort(Comparator.comparing(IslandLifecycleStep::phase).thenComparingInt(IslandLifecycleStep::order)); + } + + public static void run(IslandLifecyclePhase phase, IslandLifecycleContext context) { + steps.stream() + .filter(step -> step.phase() == phase) + .forEach(step -> runStep(step, context)); + } + + private static void runStep(IslandLifecycleStep step, IslandLifecycleContext context) { + long started = System.currentTimeMillis(); + Logger.info("[{}] Starting island {} step {}", context.island().getIslandID(), step.phase(), step.getClass().getSimpleName()); + + try { + step.run(context); + Logger.info("[{}] Completed island {} step {} in {}ms", + context.island().getIslandID(), + step.phase(), + step.getClass().getSimpleName(), + System.currentTimeMillis() - started); + } catch (Throwable throwable) { + Logger.error(throwable, "[{}] Failed island {} step {} after {}ms", + context.island().getIslandID(), + step.phase(), + step.getClass().getSimpleName(), + System.currentTimeMillis() - started); + if (throwable instanceof RuntimeException runtimeException) throw runtimeException; + if (throwable instanceof Error error) throw error; + throw new RuntimeException(throwable); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycleContext.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycleContext.java new file mode 100644 index 000000000..10c063954 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycleContext.java @@ -0,0 +1,13 @@ +package net.swofty.type.skyblockgeneric.user.island; + +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.List; +import java.util.UUID; + +public record IslandLifecycleContext( + SkyBlockIsland island, + boolean coop, + List onlineMembers, + List memberProfiles) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecyclePhase.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecyclePhase.java new file mode 100644 index 000000000..fa3d8dc0d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecyclePhase.java @@ -0,0 +1,7 @@ +package net.swofty.type.skyblockgeneric.user.island; + +public enum IslandLifecyclePhase { + CREATE, + LOAD, + SAVE +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycleStep.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycleStep.java new file mode 100644 index 000000000..b36d5be52 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandLifecycleStep.java @@ -0,0 +1,11 @@ +package net.swofty.type.skyblockgeneric.user.island; + +public interface IslandLifecycleStep { + IslandLifecyclePhase phase(); + + default int order() { + return 0; + } + + void run(IslandLifecycleContext context); +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandMembers.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandMembers.java new file mode 100644 index 000000000..c65feabf1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandMembers.java @@ -0,0 +1,31 @@ +package net.swofty.type.skyblockgeneric.user.island; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; +import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.List; +import java.util.UUID; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class IslandMembers { + + public static List onlineMembers(UUID islandId, CoopDatabase.Coop coop) { + if (coop != null) { + return coop.getOnlineMembers(); + } + + try { + return List.of(SkyBlockGenericLoader.getPlayerFromProfileUUID(islandId)); + } catch (NullPointerException ignored) { + return List.of(); + } + } + + public static List memberProfiles(UUID islandId, CoopDatabase.Coop coop) { + return coop != null ? coop.memberProfiles() : List.of(islandId); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandWorldStorage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandWorldStorage.java new file mode 100644 index 000000000..a92ffbf0d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/IslandWorldStorage.java @@ -0,0 +1,56 @@ +package net.swofty.type.skyblockgeneric.user.island; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.hollowcube.polar.PolarLoader; +import net.hollowcube.polar.PolarReader; +import net.hollowcube.polar.PolarWorld; +import net.hollowcube.polar.PolarWriter; +import net.swofty.commons.CustomWorlds; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.skyblockgeneric.data.monogdb.IslandDatabase; +import org.bson.types.Binary; +import org.tinylog.Logger; + +import java.io.IOException; +import java.nio.file.Path; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class IslandWorldStorage { + private static final Path TEMPLATE_PATH = CustomWorlds.SKYBLOCK_ISLAND_TEMPLATE.getPath(); + + public static LoadedIslandWorld load(IslandDatabase database) { + if (!database.exists()) { + return new LoadedIslandWorld(templateWorld(), HypixelConst.getCurrentIslandVersion(), 0, true); + } + + int version = database.has("version") ? (int) database.get("version", Integer.class) : 0; + + if (version == 0) { + return new LoadedIslandWorld(templateWorld(), version, System.currentTimeMillis(), false); + } + + PolarWorld world = PolarReader.read(((Binary) database.get("data", Binary.class)).getData()); + long lastSaved = (long) database.get("lastSaved", Long.class); + return new LoadedIslandWorld(world, version, lastSaved, false); + } + + public static void save(IslandDatabase database, PolarWorld world, int version) { + database.insertOrUpdate("data", new Binary(PolarWriter.write(world))); + database.insertOrUpdate("lastSaved", System.currentTimeMillis()); + database.insertOrUpdate("version", version); + } + + private static PolarWorld templateWorld() { + try { + return new PolarLoader(TEMPLATE_PATH).world(); + } catch (IOException e) { + Logger.error("Failed to create island world", e); + throw new RuntimeException("Failed to create island world", e); + } + } + + public record LoadedIslandWorld(PolarWorld world, int version, long lastSaved, boolean firstCreated) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/SkyBlockIsland.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/SkyBlockIsland.java new file mode 100644 index 000000000..1b81a358e --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/island/SkyBlockIsland.java @@ -0,0 +1,175 @@ +package net.swofty.type.skyblockgeneric.user.island; + +import lombok.Getter; +import lombok.Setter; +import net.hollowcube.polar.PolarLoader; +import net.hollowcube.polar.PolarWorld; +import net.kyori.adventure.key.Key; +import net.minestom.server.MinecraftServer; +import net.minestom.server.instance.InstanceContainer; +import net.minestom.server.instance.SharedInstance; +import net.minestom.server.registry.RegistryKey; +import net.minestom.server.timer.ExecutionType; +import net.minestom.server.timer.Scheduler; +import net.minestom.server.timer.TaskSchedule; +import net.minestom.server.world.DimensionType; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.utility.MathUtility; +import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; +import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; +import net.swofty.type.skyblockgeneric.data.monogdb.IslandDatabase; +import net.swofty.type.skyblockgeneric.minion.IslandMinionData; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.JerryInformation; +import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +@Getter +public class SkyBlockIsland { + private static final Map loadedIslands = new HashMap<>(); + + private final IslandDatabase database; + private final CoopDatabase.Coop coop; + private final UUID islandID; + private Boolean created = false; + private SharedInstance islandInstance; + private PolarWorld world; + + @Setter + private JerryInformation jerryInformation = null; + @Setter + private IslandMinionData minionData = null; + @Setter + private long lastSaved = 0; + @Setter + private Integer islandVersion; + + public SkyBlockIsland(UUID islandID, UUID profileID) { + this.islandID = islandID; + this.database = new IslandDatabase(islandID.toString()); + this.coop = CoopDatabase.getFromMemberProfile(profileID); + + loadedIslands.put(islandID, this); + } + + public CompletableFuture getSharedInstance() { + CompletableFuture future = new CompletableFuture<>(); + + Thread.startVirtualThread(() -> { + try { + if (created) { + future.complete(islandInstance); + return; + } + + Logger.info("[{}] Starting island instance load", islandID); + + InstanceContainer temporaryInstance = createInstanceContainer(); + islandInstance = MinecraftServer.getInstanceManager().createSharedInstance(temporaryInstance); + + IslandWorldStorage.LoadedIslandWorld loadedWorld = IslandWorldStorage.load(database); + world = loadedWorld.world(); + islandVersion = loadedWorld.version(); + lastSaved = loadedWorld.lastSaved(); + IslandLifecycleContext context = lifecycleContext(); + + if (loadedWorld.firstCreated()) { + IslandLifecycle.run(IslandLifecyclePhase.CREATE, context); + } + + migrateIfNeeded(); + temporaryInstance.setChunkLoader(new PolarLoader(world)); + + this.created = true; + IslandLifecycle.run(IslandLifecyclePhase.LOAD, context); + + future.complete(islandInstance); + context.onlineMembers().forEach(HypixelPlayer::setReadyForEvents); + Logger.info("[{}] Completed island instance load", islandID); + } catch (Throwable throwable) { + Logger.error(throwable, "[{}] Failed island instance load", islandID); + future.completeExceptionally(throwable); + } + }); + + return future; + } + + public void runVacantCheck() { + if (islandInstance == null) return; + + if (islandInstance.getPlayers().isEmpty()) { + IslandLifecycle.run(IslandLifecyclePhase.SAVE, lifecycleContext()); + + save(); + this.created = false; + islandInstance.getChunks().forEach(chunk -> { + islandInstance.unloadChunk(chunk); + }); + this.islandInstance = null; + this.world = null; + } + } + + private void save() { + new PolarLoader(world).saveInstance(islandInstance); + IslandWorldStorage.save(database, world, islandVersion); + } + + private InstanceContainer createInstanceContainer() { + RegistryKey dimensionTypeKey = MinecraftServer.getDimensionTypeRegistry().getKey( + Key.key("skyblock:island") + ); + return MinecraftServer.getInstanceManager().createInstanceContainer(dimensionTypeKey); + } + + private IslandLifecycleContext lifecycleContext() { + List onlineMembers = IslandMembers.onlineMembers(islandID, coop); + List memberProfiles = IslandMembers.memberProfiles(islandID, coop); + return new IslandLifecycleContext(this, coop != null, onlineMembers, memberProfiles); + } + + private void migrateIfNeeded() { + int oldVersion = islandVersion; + if (islandVersion >= HypixelConst.getCurrentIslandVersion()) return; + + MathUtility.delay(() -> SkyBlockGenericLoader.getLoadedPlayers().stream() + .filter(player -> player.getSkyBlockIsland().getIslandID() == islandID) + .forEach(player -> player.getLogHandler().debug("Your island was migrated from version §c" + oldVersion + " §fto §a" + HypixelConst.getCurrentIslandVersion() + "§f!")), 20); + + islandVersion = HypixelConst.getCurrentIslandVersion(); + } + + public static boolean hasIsland(UUID islandID) { + return loadedIslands.containsKey(islandID); + } + + public static SkyBlockIsland getOrCreate(UUID islandID, UUID profileID) { + SkyBlockIsland existing = loadedIslands.get(islandID); + if (existing != null) return existing; + + return new SkyBlockIsland(islandID, profileID); + } + + public static @Nullable SkyBlockIsland getIsland(UUID islandID) { + if (!loadedIslands.containsKey(islandID)) return null; + return loadedIslands.get(islandID); + } + + public static void runVacantLoop(Scheduler scheduler) { + scheduler.submitTask(() -> { + SkyBlockGenericLoader.getLoadedPlayers().forEach(player -> { + if (player.isOnIsland()) + player.getSkyBlockIsland().runVacantCheck(); + }); + return TaskSchedule.tick(4); + }, ExecutionType.TICK_END); + } +} diff --git a/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/TypeSkyWarsConfiguratorLoader.java b/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/TypeSkyWarsConfiguratorLoader.java index eecd23562..fe9018e8d 100644 --- a/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/TypeSkyWarsConfiguratorLoader.java +++ b/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/TypeSkyWarsConfiguratorLoader.java @@ -10,7 +10,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.HypixelTypeLoader; import net.swofty.type.generic.command.HypixelCommand; @@ -116,7 +116,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerDataSpawn.java b/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerDataSpawn.java index e5fb5d63d..7df38b7be 100644 --- a/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerDataSpawn.java +++ b/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerDataSpawn.java @@ -3,13 +3,14 @@ import net.kyori.adventure.text.Component; import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; diff --git a/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerJoin.java b/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerJoin.java index 617f0801f..4f39ac8d3 100644 --- a/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerJoin.java +++ b/type.skywarsconfigurator/src/main/java/net/swofty/type/skywarsconfigurator/events/ActionPlayerJoin.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/TypeSkywarsGameLoader.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/TypeSkywarsGameLoader.java index 43d3a6950..ccc0cb7ec 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/TypeSkywarsGameLoader.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/TypeSkywarsGameLoader.java @@ -20,12 +20,11 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.GameHeartbeatProtocol; import net.swofty.commons.skywars.SkywarsGameType; import net.swofty.commons.skywars.map.SkywarsMapsConfig; import net.swofty.proxyapi.ProxyService; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.pvp.MinestomPvP; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; @@ -222,7 +221,7 @@ public void afterInitialize(MinecraftServer server) { commonsGames.add(commonsGame); } - var heartbeat = new GameHeartbeatProtocolObject.HeartbeatMessage( + var heartbeat = new GameHeartbeatProtocol.HeartbeatMessage( uuid, shortName, getType(), @@ -294,15 +293,15 @@ public List getNPCs() { @Override @SuppressWarnings("unchecked") - public List> getTypedServiceHandlers() { + public List> getServiceHandlers() { return (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.skywarsgame.redis.service", - TypedServiceHandler.class + RedisMessageHandler.class ).toList(); } @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionArrowStats.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionArrowStats.java index 4753ea9b5..7c0cf7ea6 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionArrowStats.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionArrowStats.java @@ -12,15 +12,16 @@ import net.swofty.type.generic.data.datapoints.DatapointSkywarsModeStats; import net.swofty.type.generic.data.handlers.SkywarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionArrowStats implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBowUse(PlayerUseItemEvent event) { if (!(event.getPlayer() instanceof SkywarsPlayer player)) return; if (event.getItemStack().material() != Material.BOW) return; @@ -33,7 +34,7 @@ public void onBowUse(PlayerUseItemEvent event) { recordArrowShot(player, game); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onArrowHit(EntityDamageEvent event) { if (!(event.getEntity() instanceof LivingEntity)) return; diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestClose.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestClose.java index ec3142296..7ac281251 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestClose.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestClose.java @@ -5,15 +5,16 @@ import net.minestom.server.inventory.AbstractInventory; import net.minestom.server.inventory.Inventory; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionChestClose implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onInventoryClose(InventoryCloseEvent event) { if (!(event.getPlayer() instanceof SkywarsPlayer player)) return; diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestOpen.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestOpen.java index a9c2560da..e3c100db1 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestOpen.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionChestOpen.java @@ -4,15 +4,16 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.instance.block.Block; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionChestOpen implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockInteract(PlayerBlockInteractEvent event) { if (!(event.getPlayer() instanceof SkywarsPlayer player)) return; diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionGameCustomItems.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionGameCustomItems.java index 9fd6e91a1..9c4834b54 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionGameCustomItems.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionGameCustomItems.java @@ -7,12 +7,13 @@ import net.swofty.type.skywarsgame.luckyblock.items.LuckyBlockItemHandler; import net.swofty.type.skywarsgame.user.SkywarsPlayer; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; public class ActionGameCustomItems implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemOnBlockEvent event) { TypeSkywarsGameLoader.getItemHandler().onItemUseOnBlock(event); @@ -21,7 +22,7 @@ public void run(PlayerUseItemOnBlockEvent event) { } } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerUseItemEvent event) { TypeSkywarsGameLoader.getItemHandler().onItemUse(event); @@ -30,7 +31,7 @@ public void run(PlayerUseItemEvent event) { } } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockPlaceEvent event) { TypeSkywarsGameLoader.getItemHandler().onBlockPlace(event); } diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockArrows.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockArrows.java index b9b2de98d..002ea94f8 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockArrows.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockArrows.java @@ -12,8 +12,9 @@ import net.minestom.server.potion.Potion; import net.minestom.server.potion.PotionEffect; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.luckyblock.items.LuckyBlockItemRegistry; import net.swofty.type.skywarsgame.luckyblock.items.weapons.ExplosiveBow; import net.swofty.type.skywarsgame.luckyblock.items.weapons.Invisibow; @@ -27,7 +28,7 @@ public class ActionLuckyBlockArrows implements HypixelEventClass { private static final Map arrowBowMap = new ConcurrentHashMap<>(); - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onArrowShoot(EntityShootEvent event) { if (!(event.getEntity() instanceof SkywarsPlayer player)) return; @@ -39,7 +40,7 @@ public void onArrowShoot(EntityShootEvent event) { } } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onArrowHitBlock(ProjectileCollideWithBlockEvent event) { Entity projectile = event.getEntity(); String bowId = arrowBowMap.remove(projectile.getUuid()); @@ -49,7 +50,7 @@ public void onArrowHitBlock(ProjectileCollideWithBlockEvent event) { handleArrowEffect(bowId, projectile, event.getCollisionPosition(), null); } - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onArrowHitEntity(ProjectileCollideWithEntityEvent event) { Entity projectile = event.getEntity(); String bowId = arrowBowMap.get(projectile.getUuid()); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockBreak.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockBreak.java index f34236a76..9b14c4d2a 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockBreak.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockBreak.java @@ -5,8 +5,9 @@ import net.minestom.server.instance.block.Block; import net.swofty.commons.skywars.SkywarsGameType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; @@ -14,7 +15,7 @@ import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionLuckyBlockBreak implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockBreak(PlayerBlockBreakEvent event) { if (!(event.getPlayer() instanceof SkywarsPlayer player)) return; diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockPlace.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockPlace.java index f7dc02cf7..936a76882 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockPlace.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionLuckyBlockPlace.java @@ -6,8 +6,9 @@ import net.minestom.server.item.Material; import net.swofty.commons.skywars.SkywarsGameType; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; @@ -16,7 +17,7 @@ import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionLuckyBlockPlace implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onBlockPlace(PlayerBlockPlaceEvent event) { if (!(event.getPlayer() instanceof SkywarsPlayer player)) return; diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobAttack.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobAttack.java index f1406c66f..4bbe3e9de 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobAttack.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobAttack.java @@ -7,8 +7,9 @@ import net.minestom.server.entity.damage.DamageType; import net.minestom.server.event.entity.EntityAttackEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; @@ -16,7 +17,7 @@ public class ActionMobAttack implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onMobAttack(EntityAttackEvent event) { Entity attacker = event.getEntity(); Entity target = event.getTarget(); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobKill.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobKill.java index 7d8762212..89b1d3075 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobKill.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionMobKill.java @@ -7,15 +7,16 @@ import net.swofty.type.generic.data.datapoints.DatapointSkywarsKitStats; import net.swofty.type.generic.data.handlers.SkywarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionMobKill implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onEntityDeath(EntityDeathEvent event) { Entity entity = event.getEntity(); if (entity instanceof Player) return; diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerChat.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerChat.java index 4309089a8..1df9dfabb 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerChat.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerChat.java @@ -9,8 +9,9 @@ import net.swofty.type.generic.data.datapoints.DatapointLong; import net.swofty.type.generic.data.handlers.SkywarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.categories.Rank; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; @@ -20,7 +21,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { final SkywarsPlayer player = (SkywarsPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerCombat.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerCombat.java index 284522537..9a5538a2d 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerCombat.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerCombat.java @@ -3,15 +3,16 @@ import net.minestom.server.entity.damage.DamageType; import net.minestom.server.event.entity.EntityDamageEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.game.SkywarsGameStatus; import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionPlayerCombat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.ALL, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void onDamage(EntityDamageEvent event) { if (!(event.getEntity() instanceof SkywarsPlayer victim)) return; diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerDisconnect.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerDisconnect.java index edcb1214f..ea3dc874b 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerDisconnect.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerDisconnect.java @@ -2,15 +2,16 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.SkywarsGameScoreboard; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import net.swofty.type.skywarsgame.user.SkywarsPlayer; public class ActionPlayerDisconnect implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void onDisconnect(PlayerDisconnectEvent event) { SkywarsPlayer player = (SkywarsPlayer) event.getPlayer(); SkywarsGame game = TypeSkywarsGameLoader.getPlayerGame(player); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerJoin.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerJoin.java index b2e72c737..00010ea34 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerJoin.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerJoin.java @@ -5,9 +5,10 @@ import net.swofty.commons.ServerType; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; -import net.swofty.type.generic.redis.service.TypedGameInformationHandler; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; +import net.swofty.type.generic.redis.service.GameInformationHandler; import net.swofty.type.generic.utility.MathUtility; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; @@ -16,7 +17,7 @@ import org.tinylog.Logger; public class ActionPlayerJoin implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void onJoin(AsyncPlayerConfigurationEvent event) { SkywarsPlayer player = (SkywarsPlayer) event.getPlayer(); Logger.info("Player " + player.getUsername() + " joined the server from origin server " + player.getOriginServer()); @@ -30,7 +31,7 @@ public void onJoin(AsyncPlayerConfigurationEvent event) { private void tryJoinGame(SkywarsPlayer player, boolean isRetry) { if (!player.isOnline()) return; - String assignedGameId = TypedGameInformationHandler.game.remove(player.getUuid()); + String assignedGameId = GameInformationHandler.game.remove(player.getUuid()); if (assignedGameId == null) { if (!isRetry) { Logger.info("No game assignment found for " + player.getUsername() + ", retrying in 1 second..."); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerNameColors.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerNameColors.java index 77aa51cfb..63284ecab 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerNameColors.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/events/ActionPlayerNameColors.java @@ -5,8 +5,9 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import net.minestom.server.network.packet.server.play.TeamsPacket; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.user.SkywarsPlayer; @@ -15,7 +16,7 @@ public class ActionPlayerNameColors implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = true, phase = EventPhase.GAMEPLAY) public void run(PlayerSpawnEvent event) { SkywarsPlayer player = (SkywarsPlayer) event.getPlayer(); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/gui/GUICageKitSelector.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/gui/GUICageKitSelector.java index 0905bf272..378dfd266 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/gui/GUICageKitSelector.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/gui/GUICageKitSelector.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Random; public class GUICageKitSelector extends HypixelInventoryGUI { private static final int[] KIT_SLOTS = { @@ -209,7 +208,7 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { return; } - SkywarsKit randomKit = ownedKits.get(new Random().nextInt(ownedKits.size())); + SkywarsKit randomKit = ownedKits.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(ownedKits.size())); currentUnlocks.selectKitForMode(mode, randomKit.getId()); player.sendMessage("§aRandomly selected the §e" + randomKit.getName() + " §akit!"); diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/item/impl/PlayAgainItem.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/item/impl/PlayAgainItem.java index f30012396..cc80c4ce9 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/item/impl/PlayAgainItem.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/item/impl/PlayAgainItem.java @@ -5,8 +5,8 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocolObject; -import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.ChooseGameProtocol; +import net.swofty.commons.protocol.objects.orchestrator.GetServerForMapProtocol; import net.swofty.proxyapi.ProxyService; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; @@ -35,8 +35,8 @@ public void onItemUse(PlayerUseItemEvent event) { String gameType = game.getGameType().name(); game.leave(player); - GetServerForMapProtocolObject.GetServerForMapMessage message = - new GetServerForMapProtocolObject.GetServerForMapMessage( + GetServerForMapProtocol.GetServerForMapMessage message = + new GetServerForMapProtocol.GetServerForMapMessage( ServerType.SKYWARS_GAME, null, gameType, @@ -44,10 +44,10 @@ public void onItemUse(PlayerUseItemEvent event) { ); PROXY_SERVICE.handleRequest(message).thenAccept(response -> { - if (response instanceof GetServerForMapProtocolObject.GetServerForMapResponse resp) { + if (response instanceof GetServerForMapProtocol.GetServerForMapResponse resp) { if (resp.server() != null) { - ChooseGameProtocolObject.ChooseGameMessage chooseMessage = - new ChooseGameProtocolObject.ChooseGameMessage( + ChooseGameProtocol.ChooseGameMessage chooseMessage = + new ChooseGameProtocol.ChooseGameMessage( player.getUuid(), resp.server(), resp.gameId() diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/manager/ChestManager.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/manager/ChestManager.java index 1e0b62776..cc7f6bfc0 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/manager/ChestManager.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/manager/ChestManager.java @@ -50,7 +50,7 @@ private void fillChest(Inventory chest, LootTier tier) { chest.clear(); List loot = ChestLootTable.generateLoot(tier, gameType.isInsane(), gameType); - Random random = new Random(); + java.util.concurrent.ThreadLocalRandom random = java.util.concurrent.ThreadLocalRandom.current(); Set usedSlots = new HashSet<>(); for (ItemStack item : loot) { @@ -61,8 +61,7 @@ private void fillChest(Inventory chest, LootTier tier) { attempts++; } while (usedSlots.contains(slot) && attempts < 50); - if (!usedSlots.contains(slot)) { - usedSlots.add(slot); + if (usedSlots.add(slot)) { chest.setItemStack(slot, item); } } diff --git a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/redis/service/TypedInstantiateGameHandler.java b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/redis/service/InstantiateGameHandler.java similarity index 88% rename from type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/redis/service/TypedInstantiateGameHandler.java rename to type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/redis/service/InstantiateGameHandler.java index 159c7d4a7..88a1ef8c5 100644 --- a/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/redis/service/TypedInstantiateGameHandler.java +++ b/type.skywarsgame/src/main/java/net/swofty/type/skywarsgame/redis/service/InstantiateGameHandler.java @@ -1,29 +1,30 @@ package net.swofty.type.skywarsgame.redis.service; -import net.swofty.commons.protocol.ServicePushProtocol; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol.Request; import net.swofty.commons.protocol.objects.game.InstantiateGamePushProtocol.Response; import net.swofty.commons.skywars.SkywarsGameType; import net.swofty.commons.skywars.map.SkywarsMapsConfig; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.skywarsgame.TypeSkywarsGameLoader; import net.swofty.type.skywarsgame.game.SkywarsGame; import java.util.List; import java.util.concurrent.ThreadLocalRandom; +import net.swofty.commons.redis.RedisMessageContext; -public class TypedInstantiateGameHandler implements TypedServiceHandler { +public class InstantiateGameHandler implements RedisMessageHandler { private static final InstantiateGamePushProtocol PROTOCOL = new InstantiateGamePushProtocol(); @Override - public ServicePushProtocol getProtocol() { + public RedisProtocol protocol() { return PROTOCOL; } @Override - public Response onMessage(Request request) { + public Response handle(Request request, RedisMessageContext context) { try { SkywarsGameType gameType = SkywarsGameType.from(request.gameType().toUpperCase()); if (gameType == null) { diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/TypeSkyWarsLobbyLoader.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/TypeSkyWarsLobbyLoader.java index 24141d03f..0a457f3ca 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/TypeSkyWarsLobbyLoader.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/TypeSkyWarsLobbyLoader.java @@ -7,8 +7,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; -import net.swofty.proxyapi.redis.TypedServiceHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.command.HypixelCommand; @@ -199,15 +198,15 @@ public List getNPCs() { @Override @SuppressWarnings("unchecked") - public List> getTypedServiceHandlers() { + public List> getServiceHandlers() { return (List) HypixelGenericLoader.loopThroughPackage( "net.swofty.type.skywarslobby.redis.service", - TypedServiceHandler.class + RedisMessageHandler.class ).toList(); } @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerChat.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerChat.java index b9e92be93..d34ac4a0b 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerChat.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerChat.java @@ -11,8 +11,9 @@ import net.swofty.type.generic.data.datapoints.DatapointLong; import net.swofty.type.generic.data.handlers.SkywarsDataHandler; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.party.PartyManager; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; @@ -22,7 +23,7 @@ public class ActionPlayerChat implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerChatEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); event.setCancelled(true); diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDataSpawn.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDataSpawn.java index 7be1b3c7c..726aa8e66 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDataSpawn.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDataSpawn.java @@ -6,14 +6,15 @@ import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.HypixelGenericLoader; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; public class ActionPlayerDataSpawn implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER_DATA, requireDataLoaded = false, isAsync = true, phase = EventPhase.POST_SPAWN) public void run(PlayerSpawnEvent event) { if (!event.isFirstSpawn()) return; if (!(HypixelConst.getTypeLoader().getType() == ServerType.SKYWARS_LOBBY)) return; diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDisconnect.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDisconnect.java index 6d88e4a17..fd8b7d799 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDisconnect.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerDisconnect.java @@ -2,14 +2,15 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skywarslobby.SkyWarsLobbyScoreboard; public class ActionPlayerDisconnect implements HypixelEventClass { - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.DISCONNECT) public void run(PlayerDisconnectEvent event) { HypixelPlayer player = (HypixelPlayer) event.getPlayer(); SkyWarsLobbyScoreboard.removeCache(player); diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerSpawn.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerSpawn.java index cf263d087..a16defcde 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerSpawn.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionPlayerSpawn.java @@ -4,8 +4,9 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.event.player.PlayerSpawnEvent; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skywarslobby.hologram.LeaderboardHologramManager; import net.swofty.type.skywarslobby.hologram.SoulWellHologramManager; @@ -14,7 +15,7 @@ public class ActionPlayerSpawn implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, isAsync = true, phase = EventPhase.SPAWN) public void run(PlayerSpawnEvent event) { final HypixelPlayer player = (HypixelPlayer) event.getPlayer(); player.setGameMode(GameMode.SURVIVAL); diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java index 55bc00b3e..f545b4813 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java @@ -4,8 +4,9 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.instance.block.Block; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skywarslobby.gui.GUISoulWell; @@ -14,7 +15,7 @@ public class ActionSoulWellInteract implements HypixelEventClass { private static final int SOUL_WELL_Y = 67; private static final int SOUL_WELL_Z = 0; - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerBlockInteractEvent event) { if (!(event.getPlayer() instanceof HypixelPlayer player)) { return; diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUIMapSelectionSkywars.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUIMapSelectionSkywars.java index 61a019e08..2af8bd477 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUIMapSelectionSkywars.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUIMapSelectionSkywars.java @@ -6,7 +6,7 @@ import net.minestom.server.item.Material; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocolObject; +import net.swofty.commons.protocol.objects.orchestrator.GetMapsProtocol; import net.swofty.commons.skywars.SkywarsGameType; import net.swofty.proxyapi.ProxyService; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; @@ -61,12 +61,12 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { private void loadMaps(HypixelPlayer player) { ProxyService orchestratorService = new ProxyService(ServiceType.ORCHESTRATOR); - GetMapsProtocolObject.GetMapsMessage message = - new GetMapsProtocolObject.GetMapsMessage(ServerType.SKYWARS_GAME, gameType.name()); + GetMapsProtocol.GetMapsMessage message = + new GetMapsProtocol.GetMapsMessage(ServerType.SKYWARS_GAME, gameType.name()); orchestratorService.handleRequest(message) .thenAccept(response -> { - if (response instanceof GetMapsProtocolObject.GetMapsResponse mapsResponse) { + if (response instanceof GetMapsProtocol.GetMapsResponse mapsResponse) { maps = mapsResponse.maps(); mapsLoaded = true; populateMaps(player); diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/kit/SkywarsKitRegistry.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/kit/SkywarsKitRegistry.java index 30d1d09a1..84eba5b0a 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/kit/SkywarsKitRegistry.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/kit/SkywarsKitRegistry.java @@ -3,7 +3,6 @@ import org.tinylog.Logger; import java.util.*; -import java.util.stream.Collectors; /** * Registry for all SkyWars kits. @@ -62,19 +61,17 @@ public static List getKitsForMode(String mode) { ensureInitialized(); return KITS.values().stream() .filter(kit -> kit.isAvailableFor(mode)) - .collect(Collectors.toList()); + .toList(); } /** * Get all kits sorted by rarity (lowest first) */ public static List getKitsSortedByRarity(String mode, boolean lowestFirst) { - List kits = getKitsForMode(mode); - kits.sort((a, b) -> { - int comparison = Integer.compare(a.getRarity().getSortOrder(), b.getRarity().getSortOrder()); - return lowestFirst ? comparison : -comparison; - }); - return kits; + Comparator byRarity = Comparator.comparingInt(k -> k.getRarity().getSortOrder()); + return getKitsForMode(mode).stream() + .sorted(lowestFirst ? byRarity : byRarity.reversed()) + .toList(); } /** @@ -84,7 +81,7 @@ public static List getDefaultKits() { ensureInitialized(); return KITS.values().stream() .filter(SkywarsKit::isDefault) - .collect(Collectors.toList()); + .toList(); } /** @@ -94,7 +91,7 @@ public static List getSoulWellKits() { ensureInitialized(); return KITS.values().stream() .filter(SkywarsKit::isSoulWellDrop) - .collect(Collectors.toList()); + .toList(); } /** @@ -106,7 +103,7 @@ public static List getUnownedSoulWellKits(Set ownedKitIds) { return KITS.values().stream() .filter(SkywarsKit::isSoulWellDrop) .filter(kit -> !ownedKitIds.contains(kit.getId())) - .collect(Collectors.toList()); + .toList(); } /** @@ -119,7 +116,7 @@ public static SkywarsKit getRandomSoulWellKit(Set ownedKitIds) { if (unownedKits.isEmpty()) { return null; } - return unownedKits.get(new Random().nextInt(unownedKits.size())); + return unownedKits.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(unownedKits.size())); } /** @@ -131,19 +128,13 @@ public static SkywarsKit getRandomSoulWellKit(Set ownedKitIds) { */ public static List getKitsSortedByRarity(String mode, boolean lowestFirst, boolean ownedFirst, Set ownedKitIds) { - List kits = getKitsForMode(mode); - kits.sort((a, b) -> { - if (ownedFirst) { - boolean aOwned = ownedKitIds.contains(a.getId()); - boolean bOwned = ownedKitIds.contains(b.getId()); - if (aOwned != bOwned) { - return aOwned ? -1 : 1; - } - } - int comparison = Integer.compare(a.getRarity().getSortOrder(), b.getRarity().getSortOrder()); - return lowestFirst ? comparison : -comparison; - }); - return kits; + Comparator byRarity = Comparator.comparingInt(k -> k.getRarity().getSortOrder()); + Comparator rarityComparator = lowestFirst ? byRarity : byRarity.reversed(); + Comparator comparator = ownedFirst + ? Comparator.comparing(k -> !ownedKitIds.contains(k.getId())) + .thenComparing(rarityComparator) + : rarityComparator; + return getKitsForMode(mode).stream().sorted(comparator).toList(); } /** @@ -153,7 +144,7 @@ public static List getKitsByRarity(SkywarsKitRarity rarity) { ensureInitialized(); return KITS.values().stream() .filter(kit -> kit.getRarity() == rarity) - .collect(Collectors.toList()); + .toList(); } /** diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/perk/SkywarsPerkRegistry.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/perk/SkywarsPerkRegistry.java index e3968ae4e..635da9b3f 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/perk/SkywarsPerkRegistry.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/perk/SkywarsPerkRegistry.java @@ -3,7 +3,6 @@ import org.tinylog.Logger; import java.util.*; -import java.util.stream.Collectors; /** * Registry for all SkyWars perks. @@ -62,19 +61,17 @@ public static List getPerksForMode(String mode) { ensureInitialized(); return PERKS.values().stream() .filter(perk -> perk.isAvailableFor(mode)) - .collect(Collectors.toList()); + .toList(); } /** * Get all perks sorted by rarity (lowest first) */ public static List getPerksSortedByRarity(String mode, boolean lowestFirst) { - List perks = getPerksForMode(mode); - perks.sort((a, b) -> { - int comparison = Integer.compare(a.getRarity().getSortOrder(), b.getRarity().getSortOrder()); - return lowestFirst ? comparison : -comparison; - }); - return perks; + Comparator byRarity = Comparator.comparingInt(p -> p.getRarity().getSortOrder()); + return getPerksForMode(mode).stream() + .sorted(lowestFirst ? byRarity : byRarity.reversed()) + .toList(); } /** @@ -84,7 +81,7 @@ public static List getSoulWellPerks() { ensureInitialized(); return PERKS.values().stream() .filter(SkywarsPerk::isSoulWellDrop) - .collect(Collectors.toList()); + .toList(); } /** @@ -96,7 +93,7 @@ public static List getUnownedSoulWellPerks(Set ownedPerkIds return PERKS.values().stream() .filter(SkywarsPerk::isSoulWellDrop) .filter(perk -> !ownedPerkIds.contains(perk.getId())) - .collect(Collectors.toList()); + .toList(); } /** @@ -109,7 +106,7 @@ public static SkywarsPerk getRandomSoulWellPerk(Set ownedPerkIds) { if (unownedPerks.isEmpty()) { return null; } - return unownedPerks.get(new Random().nextInt(unownedPerks.size())); + return unownedPerks.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(unownedPerks.size())); } /** @@ -119,7 +116,7 @@ public static List getPerksByRarity(SkywarsPerkRarity rarity) { ensureInitialized(); return PERKS.values().stream() .filter(perk -> perk.getRarity() == rarity) - .collect(Collectors.toList()); + .toList(); } /** @@ -137,7 +134,7 @@ public static List getGlobalPerks() { ensureInitialized(); return PERKS.values().stream() .filter(SkywarsPerk::isGlobal) - .collect(Collectors.toList()); + .toList(); } /** @@ -148,19 +145,17 @@ public static List getSelectablePerksForMode(String mode) { return PERKS.values().stream() .filter(perk -> perk.isAvailableFor(mode)) .filter(SkywarsPerk::isSelectable) - .collect(Collectors.toList()); + .toList(); } /** * Get selectable perks sorted by rarity */ public static List getSelectablePerksSortedByRarity(String mode, boolean lowestFirst) { - List perks = getSelectablePerksForMode(mode); - perks.sort((a, b) -> { - int comparison = Integer.compare(a.getRarity().getSortOrder(), b.getRarity().getSortOrder()); - return lowestFirst ? comparison : -comparison; - }); - return perks; + Comparator byRarity = Comparator.comparingInt(p -> p.getRarity().getSortOrder()); + return getSelectablePerksForMode(mode).stream() + .sorted(lowestFirst ? byRarity : byRarity.reversed()) + .toList(); } private static void ensureInitialized() { diff --git a/type.spidersden/src/main/java/net/swofty/type/spidersden/TypeSpidersDenLoader.java b/type.spidersden/src/main/java/net/swofty/type/spidersden/TypeSpidersDenLoader.java index a44b9e80a..13a4e8c5d 100644 --- a/type.spidersden/src/main/java/net/swofty/type/spidersden/TypeSpidersDenLoader.java +++ b/type.spidersden/src/main/java/net/swofty/type/spidersden/TypeSpidersDenLoader.java @@ -5,7 +5,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.HypixelEventClass; @@ -14,7 +14,7 @@ import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.tabmodules.AccountInformationModule; import net.swofty.type.skyblockgeneric.tabmodules.SkyBlockPlayersOnlineModule; -import net.swofty.type.spidersden.tab.SpidersDenServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; @@ -57,7 +57,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new SpidersDenServerModule(), + new AreaServerModule("tablist.server_info.area.spiders_den"), new AccountInformationModule() )); } @@ -87,7 +87,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.spidersden/src/main/java/net/swofty/type/spidersden/events/ActionPlayerJoin.java b/type.spidersden/src/main/java/net/swofty/type/spidersden/events/ActionPlayerJoin.java index 0625c8b5a..9a6158f7b 100644 --- a/type.spidersden/src/main/java/net/swofty/type/spidersden/events/ActionPlayerJoin.java +++ b/type.spidersden/src/main/java/net/swofty/type/spidersden/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.spidersden/src/main/java/net/swofty/type/spidersden/tab/SpidersDenServerModule.java b/type.spidersden/src/main/java/net/swofty/type/spidersden/tab/SpidersDenServerModule.java deleted file mode 100644 index 43bf6d32e..000000000 --- a/type.spidersden/src/main/java/net/swofty/type/spidersden/tab/SpidersDenServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.spidersden.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class SpidersDenServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.spiders_den", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.theend/src/main/java/net/swofty/type/theend/TypeTheEndLoader.java b/type.theend/src/main/java/net/swofty/type/theend/TypeTheEndLoader.java index a90a16ca2..353a48845 100644 --- a/type.theend/src/main/java/net/swofty/type/theend/TypeTheEndLoader.java +++ b/type.theend/src/main/java/net/swofty/type/theend/TypeTheEndLoader.java @@ -8,7 +8,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.HypixelEventClass; @@ -17,7 +17,7 @@ import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import net.swofty.type.skyblockgeneric.tabmodules.AccountInformationModule; import net.swofty.type.skyblockgeneric.tabmodules.SkyBlockPlayersOnlineModule; -import net.swofty.type.theend.tab.TheEndServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; @@ -58,7 +58,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new TheEndServerModule(), + new AreaServerModule("tablist.server_info.area.the_end"), new AccountInformationModule() )); } @@ -98,7 +98,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.theend/src/main/java/net/swofty/type/theend/events/ActionPlayerJoin.java b/type.theend/src/main/java/net/swofty/type/theend/events/ActionPlayerJoin.java index 94bc7729c..eeebc2469 100644 --- a/type.theend/src/main/java/net/swofty/type/theend/events/ActionPlayerJoin.java +++ b/type.theend/src/main/java/net/swofty/type/theend/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.theend/src/main/java/net/swofty/type/theend/tab/TheEndServerModule.java b/type.theend/src/main/java/net/swofty/type/theend/tab/TheEndServerModule.java deleted file mode 100644 index 4de1fd0bc..000000000 --- a/type.theend/src/main/java/net/swofty/type/theend/tab/TheEndServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.theend.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class TheEndServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.the_end", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/TypeTheFarmingIslandsLoader.java b/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/TypeTheFarmingIslandsLoader.java index 0b5d81507..ab782deba 100644 --- a/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/TypeTheFarmingIslandsLoader.java +++ b/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/TypeTheFarmingIslandsLoader.java @@ -5,7 +5,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.npc.HypixelNPC; @@ -15,7 +15,7 @@ import net.swofty.type.generic.tab.TablistModule; import net.swofty.type.skyblockgeneric.tabmodules.AccountInformationModule; import net.swofty.type.skyblockgeneric.tabmodules.SkyBlockPlayersOnlineModule; -import net.swofty.type.thefarmingislands.tab.TheFarmingIslandsServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; @@ -57,7 +57,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new TheFarmingIslandsServerModule(), + new AreaServerModule("tablist.server_info.area.the_farming_islands"), new AccountInformationModule() )); } @@ -87,7 +87,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/events/ActionPlayerJoin.java b/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/events/ActionPlayerJoin.java index 65f198896..6c16e36c3 100644 --- a/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/events/ActionPlayerJoin.java +++ b/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/tab/TheFarmingIslandsServerModule.java b/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/tab/TheFarmingIslandsServerModule.java deleted file mode 100644 index f535466f0..000000000 --- a/type.thefarmingislands/src/main/java/net/swofty/type/thefarmingislands/tab/TheFarmingIslandsServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.thefarmingislands.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class TheFarmingIslandsServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.the_farming_islands", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/TypeTheParkLoader.java b/type.thepark/src/main/java/net/swofty/type/thepark/TypeTheParkLoader.java index 4806ed56f..afc21d45b 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/TypeTheParkLoader.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/TypeTheParkLoader.java @@ -16,7 +16,7 @@ import net.swofty.commons.CustomWorlds; import net.swofty.commons.ServerType; import net.swofty.commons.ServiceType; -import net.swofty.proxyapi.redis.TypedProxyHandler; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.SkyBlockTypeLoader; import net.swofty.type.generic.entity.BlockDisplayEntity; @@ -35,7 +35,7 @@ import net.swofty.type.skyblockgeneric.tabmodules.AccountInformationModule; import net.swofty.type.skyblockgeneric.tabmodules.SkyBlockPlayersOnlineModule; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import net.swofty.type.thepark.tab.TheParkServerModule; +import net.swofty.type.generic.tab.AreaServerModule; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.tinylog.Logger; @@ -243,7 +243,7 @@ public List getModules() { return new ArrayList<>(List.of( new SkyBlockPlayersOnlineModule(1), new SkyBlockPlayersOnlineModule(2), - new TheParkServerModule(), + new AreaServerModule("tablist.server_info.area.the_park"), new AccountInformationModule() )); } @@ -273,7 +273,7 @@ public List getNPCs() { @Override - public List> getTypedProxyHandlers() { + public List> getProxyHandlers() { return List.of(); } diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionContinueParkMission.java b/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionContinueParkMission.java index 410abe2cc..b6a9c9948 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionContinueParkMission.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionContinueParkMission.java @@ -3,8 +3,9 @@ import net.minestom.server.entity.Entity; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.event.custom.PlayerRegionChangeEvent; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.missions.thepark.birchpark.MissionTravelToThePark; @@ -19,7 +20,7 @@ public class ActionContinueParkMission implements HypixelEventClass { - @HypixelEvent(node = EventNodes.CUSTOM, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.CUSTOM, requireDataLoaded = false, phase = EventPhase.GAMEPLAY) public void run(PlayerRegionChangeEvent event) { if (event.getTo() == null) return; diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionPlayerJoin.java b/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionPlayerJoin.java index 32737e368..918d5f66c 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionPlayerJoin.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/events/ActionPlayerJoin.java @@ -4,14 +4,15 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; -import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.event.phase.EventPhase; +import net.swofty.type.generic.event.phase.PhasedEvent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class ActionPlayerJoin implements HypixelEventClass { @SneakyThrows - @HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = false) + @PhasedEvent(node = EventNodes.PLAYER, requireDataLoaded = false, phase = EventPhase.CONNECT) public void run(AsyncPlayerConfigurationEvent event) { final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/tab/TheParkServerModule.java b/type.thepark/src/main/java/net/swofty/type/thepark/tab/TheParkServerModule.java deleted file mode 100644 index e35b8fdb8..000000000 --- a/type.thepark/src/main/java/net/swofty/type/thepark/tab/TheParkServerModule.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.swofty.type.thepark.tab; - -import net.kyori.adventure.text.Component; -import net.swofty.type.generic.HypixelConst; -import net.swofty.type.generic.i18n.I18n; -import net.swofty.type.generic.tab.TablistModule; -import net.swofty.type.generic.tab.TablistSkinRegistry; -import net.swofty.type.generic.user.HypixelPlayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class TheParkServerModule extends TablistModule { - @Override - public List getEntries(HypixelPlayer player) { - Locale l = player.getLocale(); - ArrayList entries = new ArrayList<>(List.of( - new TablistEntry(getCentered(I18n.string("tablist.module.server_info", l)), TablistSkinRegistry.CYAN) - )); - - entries.add(new TablistEntry(I18n.string("tablist.server_info.area.the_park", l), TablistSkinRegistry.GRAY)); - entries.add(new TablistEntry(I18n.string("tablist.server_info.server_label", l, Component.text(HypixelConst.getServerName())), TablistSkinRegistry.GRAY)); - - fillRestWithGray(entries); - - return entries; - } -} diff --git a/velocity.extension/build.gradle.kts b/velocity.extension/build.gradle.kts index ec2f68c65..12f86b178 100644 --- a/velocity.extension/build.gradle.kts +++ b/velocity.extension/build.gradle.kts @@ -4,7 +4,7 @@ plugins { java application `maven-publish` - id("com.gradleup.shadow") version "9.3.2" + id("com.gradleup.shadow") version "9.4.1" id("org.jetbrains.gradle.plugin.idea-ext") version "1.4.1" } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/SkyBlockVelocity.java b/velocity.extension/src/main/java/net/swofty/velocity/SkyBlockVelocity.java index 1c321ed7f..0e7b6dd30 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/SkyBlockVelocity.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/SkyBlockVelocity.java @@ -39,16 +39,18 @@ import net.swofty.commons.ServiceType; import net.swofty.commons.config.ConfigProvider; import net.swofty.commons.config.Settings; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.*; -import net.swofty.commons.protocol.objects.punishment.GetActivePunishmentProtocolObject; +import net.swofty.commons.protocol.objects.punishment.GetActivePunishmentProtocol; +import net.swofty.commons.redis.RedisClient; +import net.swofty.commons.redis.RedisEndpoint; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.commons.punishment.ActivePunishment; import net.swofty.commons.punishment.PunishmentMessages; import net.swofty.commons.punishment.PunishmentReason; import net.swofty.commons.punishment.PunishmentTag; import net.swofty.commons.punishment.PunishmentType; import net.swofty.proxyapi.ProxyService; -import net.swofty.proxyapi.redis.ServerOutboundMessage; import net.swofty.redisapi.api.RedisAPI; import net.swofty.velocity.command.LimboCommand; import net.swofty.velocity.command.LobbyCommand; @@ -66,9 +68,7 @@ import net.swofty.velocity.gamemanager.TransferHandler; import net.swofty.velocity.packet.PlayerChannelHandler; import net.swofty.velocity.presence.PresencePublisher; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; -import net.swofty.velocity.redis.RedisMessage; +import net.swofty.velocity.redis.RedisHandlerRegistry; import net.swofty.velocity.redis.listeners.ListenerStaffChat; import net.swofty.velocity.testflow.TestFlowManager; import net.swofty.velocity.viaversion.injector.SkyBlockViaInjector; @@ -225,25 +225,20 @@ public void onProxyInitialization(ProxyInitializeEvent event) { // Setup Redis RedisAPI.generateInstance(ConfigProvider.settings().getRedisUri()); RedisAPI.getInstance().setFilterId("proxy"); - loopThroughPackage("net.swofty.velocity.redis.listeners", RedisListener.class) - .forEach(listener -> { - RedisAPI.getInstance().registerChannel( - listener.getChannelName(), - (event2) -> { - listener.onMessage(event2.channel, event2.message); - }); - }); - ProtocolObject[] fromProxyProtocols = { + RedisClient.identify(RedisEndpoint.proxy()); + loopThroughPackage("net.swofty.velocity.redis.listeners", RedisMessageHandler.class) + .forEach(RedisHandlerRegistry::register); + RedisProtocol[] fromProxyProtocols = { new TeleportProtocol(), new PlayerSwitchedProtocol(), new DoesServerHaveIslandProtocol(), new RefreshCoopDataProtocol(), new RunEventProtocol(), new PingServerProtocol(), new GivePlayersOriginTypeProtocol(), new BroadcastStaffChatProtocol() }; - for (ProtocolObject protocol : fromProxyProtocols) { - RedisMessage.registerProxyToServer(protocol); + for (RedisProtocol protocol : fromProxyProtocols) { + RedisClient.registerResponseProtocol(protocol); } - loopThroughPackage("net.swofty.commons.protocol.objects", ProtocolObject.class) - .forEach(ServerOutboundMessage::registerFromProtocolObject); + loopThroughPackage("net.swofty.commons.protocol.objects", RedisProtocol.class) + .forEach(RedisClient::registerResponseProtocol); RedisAPI.getInstance().startListeners(); // Setup GameManager @@ -255,14 +250,14 @@ private boolean checkPunished(Player player) { ProxyService service = new ProxyService(ServiceType.PUNISHMENT); CompletableFuture banFuture = service.handleRequest( - new GetActivePunishmentProtocolObject.GetActivePunishmentMessage(player.getUniqueId(), PunishmentType.BAN.name())); + new GetActivePunishmentProtocol.GetActivePunishmentMessage(player.getUniqueId(), PunishmentType.BAN.name())); CompletableFuture muteFuture = service.handleRequest( - new GetActivePunishmentProtocolObject.GetActivePunishmentMessage(player.getUniqueId(), PunishmentType.MUTE.name())); + new GetActivePunishmentProtocol.GetActivePunishmentMessage(player.getUniqueId(), PunishmentType.MUTE.name())); CompletableFuture.allOf(banFuture, muteFuture).orTimeout(3, TimeUnit.SECONDS).join(); Object banResult = banFuture.join(); - if (banResult instanceof GetActivePunishmentProtocolObject.GetActivePunishmentResponse( + if (banResult instanceof GetActivePunishmentProtocol.GetActivePunishmentResponse( boolean found1, String type1, String id, PunishmentReason reason1, long at, List tags1, boolean success1, String error1 ) && found1) { @@ -273,7 +268,7 @@ private boolean checkPunished(Player player) { } Object muteResult = muteFuture.join(); - if (muteResult instanceof GetActivePunishmentProtocolObject.GetActivePunishmentResponse( + if (muteResult instanceof GetActivePunishmentProtocol.GetActivePunishmentResponse( boolean found, String type, String banId, PunishmentReason reason, long expiresAt, List tags, boolean success, String error ) && found) { @@ -359,7 +354,7 @@ public EventTask onPlayerJoin(PlayerChooseInitialServerEvent event) { return; } - List configurations = BalanceConfigurations.configurations.get(ServerType.BEDWARS_LOBBY); + List configurations = BalanceConfigurations.CONFIGURATIONS.get(ServerType.BEDWARS_LOBBY); GameManager.GameServer toSendTo = gameServers.getFirst(); for (BalanceConfiguration configuration : configurations) { @@ -403,18 +398,9 @@ public void onServerCrash(KickedFromServerEvent event) { CompletableFuture.delayedExecutor(GameManager.SLEEP_TIME + 300, TimeUnit.MILLISECONDS) .execute(() -> { - // Determine if the registeredServer disconnect was due to a crash - // if it was, then we send the player back to another registeredServer - // of that type, otherwise we disconnect them for the same - // reason as the original - - /*boolean isOnline = GameManager.getFromRegisteredServer(originalServer) != null; - if (isOnline) { - transferHandler.forceRemoveFromLimbo(); - event.getPlayer().disconnect(reason); - return; - }*/ - + // Determine if the registeredServer disconnect was due to a crash — + // if it was, send the player to another server of that type; + // otherwise disconnect them with the original reason. try { ServerType serverTypeToTry = serverType; if (!GameManager.hasType(serverTypeToTry) || !GameManager.isAnyEmpty(serverTypeToTry)) { diff --git a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/BalanceConfigurations.java b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/BalanceConfigurations.java index ada937516..a7813c198 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/BalanceConfigurations.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/BalanceConfigurations.java @@ -1,148 +1,103 @@ package net.swofty.velocity.gamemanager; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import com.velocitypowered.api.proxy.Player; import net.swofty.commons.ServerType; import net.swofty.velocity.gamemanager.impl.IslandCheck; import net.swofty.velocity.gamemanager.impl.LowestPlayerCount; import net.swofty.velocity.testflow.TestFlowManager; import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; -import java.util.HashMap; import java.util.List; import java.util.Map; -public class BalanceConfigurations { - public static HashMap> configurations = new HashMap<>(Map.ofEntries( - Map.entry(ServerType.SKYBLOCK_ISLAND, List.of( - new IslandCheck(), - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_HUB, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_DUNGEON_HUB, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_THE_FARMING_ISLANDS, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_SPIDERS_DEN, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_THE_END, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_CRIMSON_ISLE, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_GOLD_MINE, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_DEEP_CAVERNS, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_DWARVEN_MINES, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_THE_PARK, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_GALATEA, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_BACKWATER_BAYOU, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYBLOCK_JERRYS_WORKSHOP, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.PROTOTYPE_LOBBY, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.BEDWARS_LOBBY, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.BEDWARS_GAME, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYWARS_LOBBY, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYWARS_GAME, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.MURDER_MYSTERY_LOBBY, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.MURDER_MYSTERY_GAME, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.SKYWARS_CONFIGURATOR, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.BEDWARS_CONFIGURATOR, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.MURDER_MYSTERY_CONFIGURATOR, List.of( - new LowestPlayerCount() - )), - Map.entry(ServerType.RAVENGARD_LOBBY, List.of( - new LowestPlayerCount() - )) - )); - - public static @Nullable GameManager.GameServer getServerFor(Player player, ServerType type) { - if (TestFlowManager.isPlayerInTestFlow(player.getUsername())) { - player.sendPlainMessage("§eYou are currently in a network-isolated test flow, load balancing will be restricted to test flow servers!"); - player.sendPlainMessage("§8Executing test flow " + TestFlowManager.getTestFlowForPlayer(player.getUsername()).getName() + "..."); - } +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class BalanceConfigurations { - try { - for (BalanceConfiguration configuration : configurations.get(type)) { - List serversToConsider = GameManager.getFromType(type); - if (TestFlowManager.isPlayerInTestFlow(player.getUsername())) { - serversToConsider.removeIf(server -> { - boolean remove = server.maxPlayers() <= server.registeredServer().getPlayersConnected().size(); + // Shared singletons — the strategies are stateless, so there's no reason to + // hold 25+ separate instances when one per kind suffices. + private static final BalanceConfiguration ISLAND_CHECK = new IslandCheck(); + private static final BalanceConfiguration LOWEST_PLAYER_COUNT = new LowestPlayerCount(); + private static final List DEFAULT_CHAIN = List.of(LOWEST_PLAYER_COUNT); - if (!TestFlowManager.isServerInTestFlow(server.internalID())) { - remove = true; - } + public static final Map> CONFIGURATIONS = Map.ofEntries( + Map.entry(ServerType.SKYBLOCK_ISLAND, List.of(ISLAND_CHECK, LOWEST_PLAYER_COUNT)), + Map.entry(ServerType.SKYBLOCK_HUB, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_DUNGEON_HUB, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_THE_FARMING_ISLANDS, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_SPIDERS_DEN, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_THE_END, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_CRIMSON_ISLE, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_GOLD_MINE, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_DEEP_CAVERNS, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_DWARVEN_MINES, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_THE_PARK, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_GALATEA, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_BACKWATER_BAYOU, DEFAULT_CHAIN), + Map.entry(ServerType.SKYBLOCK_JERRYS_WORKSHOP, DEFAULT_CHAIN), + Map.entry(ServerType.PROTOTYPE_LOBBY, DEFAULT_CHAIN), + Map.entry(ServerType.BEDWARS_LOBBY, DEFAULT_CHAIN), + Map.entry(ServerType.BEDWARS_GAME, DEFAULT_CHAIN), + Map.entry(ServerType.SKYWARS_LOBBY, DEFAULT_CHAIN), + Map.entry(ServerType.SKYWARS_GAME, DEFAULT_CHAIN), + Map.entry(ServerType.MURDER_MYSTERY_LOBBY, DEFAULT_CHAIN), + Map.entry(ServerType.MURDER_MYSTERY_GAME, DEFAULT_CHAIN), + Map.entry(ServerType.SKYWARS_CONFIGURATOR, DEFAULT_CHAIN), + Map.entry(ServerType.BEDWARS_CONFIGURATOR, DEFAULT_CHAIN), + Map.entry(ServerType.MURDER_MYSTERY_CONFIGURATOR, DEFAULT_CHAIN), + Map.entry(ServerType.RAVENGARD_LOBBY, DEFAULT_CHAIN) + ); - TestFlowManager.ProxyTestFlowInstance testFlowInstance = TestFlowManager.getFromServerUUID( - server.internalID() - ); + public static @Nullable GameManager.GameServer getServerFor(Player player, ServerType type) { + final boolean inTestFlow = TestFlowManager.isPlayerInTestFlow(player.getUsername()); + if (inTestFlow) { + player.sendPlainMessage("§eYou are currently in a network-isolated test flow, load balancing will be restricted to test flow servers!"); + player.sendPlainMessage("§8Executing test flow " + + TestFlowManager.getTestFlowForPlayer(player.getUsername()).getName() + "..."); + } - if (!testFlowInstance.hasPlayer(player.getUsername())) { - remove = true; - } + try { + for (BalanceConfiguration configuration : CONFIGURATIONS.get(type)) { + List serversToConsider = GameManager.getFromType(type); + if (inTestFlow) { + serversToConsider.removeIf(server -> !isEligibleForTestFlowPlayer(server, player)); + } else { + serversToConsider.removeIf(server -> !isEligibleForRegularPlayer(server)); + } - return remove; - }); - } else { - serversToConsider.removeIf(server -> { - boolean remove = server.maxPlayers() <= server.registeredServer().getPlayersConnected().size(); + GameManager.GameServer server = configuration.getServer(player, serversToConsider); + if (server != null) { + if (inTestFlow) { + player.sendPlainMessage("§8Done overriding the server manager for your test flow."); + } + return server; + } + } + return null; + } catch (Exception e) { + Logger.error(e, "Error in trying to balance type {} for player {}", + type.name(), player.getUsername()); + throw e; + } + } - if (TestFlowManager.isServerInTestFlow(server.internalID())) { - remove = true; - } + private static boolean hasCapacity(GameManager.GameServer server) { + return server.maxPlayers() > server.registeredServer().getPlayersConnected().size(); + } - return remove; - }); - } + private static boolean isEligibleForRegularPlayer(GameManager.GameServer server) { + return hasCapacity(server) && !TestFlowManager.isServerInTestFlow(server.internalID()); + } - GameManager.GameServer server = configuration.getServer(player, serversToConsider); + private static boolean isEligibleForTestFlowPlayer(GameManager.GameServer server, Player player) { + if (!hasCapacity(server)) return false; + if (!TestFlowManager.isServerInTestFlow(server.internalID())) return false; - if (server != null) { - if (TestFlowManager.isPlayerInTestFlow(player.getUsername())) { - player.sendPlainMessage("§8Done overriding the server manager for your test flow."); - } - return server; - } - } - return null; - } catch (Exception e) { - System.out.println("Error in trying to balance type " + type.name() + " for player " + player.getUsername()); - throw e; - } - } + TestFlowManager.ProxyTestFlowInstance instance = + TestFlowManager.getFromServerUUID(server.internalID()); + return instance != null && instance.hasPlayer(player.getUsername()); + } } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/GameManager.java b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/GameManager.java index 3a2b571e7..4e96bd4cb 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/GameManager.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/GameManager.java @@ -8,7 +8,7 @@ import net.swofty.commons.config.ConfigProvider; import net.swofty.commons.protocol.objects.proxy.from.PingServerProtocol; import net.swofty.velocity.SkyBlockVelocity; -import net.swofty.velocity.redis.RedisMessage; +import net.swofty.commons.redis.RedisClient; import net.swofty.velocity.testflow.TestFlowManager; import org.jetbrains.annotations.Nullable; @@ -33,7 +33,7 @@ public static GameServer addServer(ServerType type, UUID serverID, String host, String rootName = isLobby ? "L" : (maxPlayers <= 20 ? "mini" : "mega"); String shortenedRootName = isLobby ? "L" : (maxPlayers <= 20 ? "m" : "M"); - char letter = (char) (new Random().nextInt(26) + (isLobby ? 'a' : 'A')); + char letter = (char) (java.util.concurrent.ThreadLocalRandom.current().nextInt(26) + (isLobby ? 'a' : 'A')); String displayName = getNextAvailableDisplayName() + "" + letter; GameServer server = new GameServer( @@ -104,7 +104,7 @@ public static void loopServers(ProxyServer server) { AtomicBoolean pingSuccess = new AtomicBoolean(false); long startTime = System.currentTimeMillis(); - RedisMessage.sendMessageToServer(registeredServer.internalID(), + RedisClient.requestServer(registeredServer.internalID(), new PingServerProtocol(), new PingServerProtocol.Request() ).thenRun(() -> { pingSuccess.set(true); @@ -112,8 +112,12 @@ public static void loopServers(ProxyServer server) { server.getScheduler().buildTask(SkyBlockVelocity.getPlugin(), () -> { if (!pingSuccess.get()) { - System.out.println("Server " + givenServer.getServerInfo().getName() + " is offline! Removing from list..."); - System.out.println("Ping was sent at " + startTime + " and was not received at " + System.currentTimeMillis() + " (" + (System.currentTimeMillis() - startTime) + "ms)"); + org.tinylog.Logger.warn( + "Server {} is offline! Removing from list (ping sent at {}, deadline {}ms)", + givenServer.getServerInfo().getName(), + startTime, + System.currentTimeMillis() - startTime + ); servers.get(serverType).remove(registeredServer); TestFlowManager.handleServerDisconnect(registeredServer.internalID); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/TransferHandler.java b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/TransferHandler.java index 8592726a7..cd2947dda 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/TransferHandler.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/TransferHandler.java @@ -7,7 +7,7 @@ import net.swofty.commons.protocol.objects.proxy.from.GivePlayersOriginTypeProtocol; import net.swofty.commons.protocol.objects.proxy.from.PlayerSwitchedProtocol; import net.swofty.velocity.SkyBlockVelocity; -import net.swofty.velocity.redis.RedisMessage; +import net.swofty.commons.redis.RedisClient; import java.util.Map; import java.util.Set; @@ -66,7 +66,7 @@ public void previousServerIsFinished(RegisteredServer manualPick) { UUID serverUUID = UUID.fromString(manualPick.getServerInfo().getName()); UUID originServerUUID = UUID.fromString(originServer.getServerInfo().getName()); - RedisMessage.sendMessageToServer(serverUUID, + RedisClient.requestServer(serverUUID, new GivePlayersOriginTypeProtocol(), new GivePlayersOriginTypeProtocol.Request( player.getUniqueId().toString(), originServerType.name())); @@ -78,7 +78,7 @@ public void previousServerIsFinished(RegisteredServer manualPick) { player.sendMessage(Component.text("§7Sending to server " + manualPickAsGame.displayName() + "...")); player.createConnectionRequest(manualPick).connectWithIndication(); - RedisMessage.sendMessageToServer(originServerUUID, + RedisClient.requestServer(originServerUUID, new PlayerSwitchedProtocol(), new PlayerSwitchedProtocol.Request(player.getUniqueId().toString())); }).start(); @@ -112,7 +112,7 @@ public void previousServerIsFinished() { UUID sendingToServerUUID = server.internalID(); ServerType originServerType = GameManager.getTypeFromRegisteredServer(originServer); - RedisMessage.sendMessageToServer(sendingToServerUUID, + RedisClient.requestServer(sendingToServerUUID, new GivePlayersOriginTypeProtocol(), new GivePlayersOriginTypeProtocol.Request( player.getUniqueId().toString(), originServerType.name())); @@ -123,7 +123,7 @@ public void previousServerIsFinished() { player.sendMessage(Component.text("§7Sending to server " + server.displayName() + "...")); player.createConnectionRequest(server.registeredServer()).connectWithIndication(); - RedisMessage.sendMessageToServer(originServerUUID, + RedisClient.requestServer(originServerUUID, new PlayerSwitchedProtocol(), new PlayerSwitchedProtocol.Request(player.getUniqueId().toString())); }).start(); @@ -166,7 +166,7 @@ public CompletableFuture transferTo(RegisteredServer toTransferTo) { UUID serverUUID = UUID.fromString(toTransferTo.getServerInfo().getName()); if (originServer != null && originServerType != null) { - RedisMessage.sendMessageToServer(serverUUID, + RedisClient.requestServer(serverUUID, new GivePlayersOriginTypeProtocol(), new GivePlayersOriginTypeProtocol.Request( player.getUniqueId().toString(), originServerType.name())); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/IslandCheck.java b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/IslandCheck.java index cd6960154..82a5b0bd1 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/IslandCheck.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/IslandCheck.java @@ -7,7 +7,7 @@ import net.swofty.velocity.data.UserDatabase; import net.swofty.velocity.gamemanager.BalanceConfiguration; import net.swofty.velocity.gamemanager.GameManager; -import net.swofty.velocity.redis.RedisMessage; +import net.swofty.commons.redis.RedisClient; import org.bson.Document; import org.jetbrains.annotations.NotNull; @@ -49,7 +49,7 @@ private static AtomicReference getGameServerAtomicRefere ArrayList gameServers = entry.getValue(); gameServers.forEach(gameServer -> { - DoesServerHaveIslandProtocol.Response response = RedisMessage.sendMessageToServer( + DoesServerHaveIslandProtocol.Response response = RedisClient.requestServer( gameServer.internalID(), new DoesServerHaveIslandProtocol(), new DoesServerHaveIslandProtocol.Request(islandUUID.toString())).join(); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/LowestPlayerCount.java b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/LowestPlayerCount.java index 35a56e11c..17e4b5a92 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/LowestPlayerCount.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/gamemanager/impl/LowestPlayerCount.java @@ -4,17 +4,16 @@ import net.swofty.velocity.gamemanager.BalanceConfiguration; import net.swofty.velocity.gamemanager.GameManager; +import java.util.Comparator; import java.util.List; -public class LowestPlayerCount extends BalanceConfiguration { +public final class LowestPlayerCount extends BalanceConfiguration { + + private static final Comparator BY_PLAYER_COUNT = + Comparator.comparingInt(server -> server.registeredServer().getPlayersConnected().size()); @Override public GameManager.GameServer getServer(Player player, List servers) { - return servers.stream().min((server1, server2) -> { - int server1Players = server1.registeredServer().getPlayersConnected().size(); - int server2Players = server2.registeredServer().getPlayersConnected().size(); - - return Integer.compare(server1Players, server2Players); - }).orElse(null); + return servers.stream().min(BY_PLAYER_COUNT).orElse(null); } } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/packet/PlayerChannelHandler.java b/velocity.extension/src/main/java/net/swofty/velocity/packet/PlayerChannelHandler.java index e66912aab..2635b8ef8 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/packet/PlayerChannelHandler.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/packet/PlayerChannelHandler.java @@ -37,7 +37,6 @@ public void write(final ChannelHandlerContext ctx, final Object packet, final Ch && packet.getClass() != KnownPacksPacket.class && packet.getClass() != TagsUpdatePacket.class ) { - //System.out.println("Blocked packet " + packet.getClass().getSimpleName() + " from being sent to " + player.getUsername() + " because they are in limbo."); return; } if (respawn == null && packet.getClass() == RespawnPacket.class) { @@ -48,7 +47,12 @@ public void write(final ChannelHandlerContext ctx, final Object packet, final Ch write(ctx, respawn, ctx.newPromise()); } } - } catch (Exception ignored) {} + } catch (Exception e) { + // Limbo packet replay is best-effort: a malformed cached respawn + // shouldn't drop the player. Log at debug so it surfaces during + // diagnostic runs without spamming production logs. + org.tinylog.Logger.debug(e, "Failed to replay cached respawn during limbo transfer"); + } super.write(ctx, packet, promise); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/presence/PresencePublisher.java b/velocity.extension/src/main/java/net/swofty/velocity/presence/PresencePublisher.java index 6d8a8c9a3..75fc23bc6 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/presence/PresencePublisher.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/presence/PresencePublisher.java @@ -1,17 +1,19 @@ package net.swofty.velocity.presence; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; import net.swofty.commons.presence.PresenceInfo; -import net.swofty.commons.protocol.objects.presence.UpdatePresenceProtocolObject; -import net.swofty.proxyapi.redis.ServerOutboundMessage; +import net.swofty.commons.protocol.objects.presence.UpdatePresenceProtocol; +import net.swofty.commons.redis.RedisClient; import java.util.UUID; +@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class PresencePublisher { - private PresencePublisher() {} - public static void publish(Player player, boolean online, String serverType, UUID serverId) { PresenceInfo info = new PresenceInfo( player.getUniqueId(), @@ -21,9 +23,9 @@ public static void publish(Player player, boolean online, String serverType, UUI System.currentTimeMillis() ); - ServerOutboundMessage.sendMessageToAllServicesFireAndForget( - new UpdatePresenceProtocolObject(), - new UpdatePresenceProtocolObject.UpdatePresenceMessage(info) + RedisClient.publishAllServices( + new UpdatePresenceProtocol(), + new UpdatePresenceProtocol.UpdatePresenceMessage(info) ); } @@ -38,4 +40,3 @@ public static void publish(Player player, boolean online, RegisteredServer serve publish(player, online, serverType, serverId); } } - diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/ChannelListener.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/ChannelListener.java deleted file mode 100644 index c58fa472d..000000000 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/ChannelListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.swofty.velocity.redis; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface ChannelListener { -} diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisHandlerRegistry.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisHandlerRegistry.java new file mode 100644 index 000000000..b29787275 --- /dev/null +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisHandlerRegistry.java @@ -0,0 +1,35 @@ +package net.swofty.velocity.redis; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import net.swofty.commons.protocol.RedisProtocol; +import net.swofty.commons.redis.RedisChannels; +import net.swofty.commons.redis.RedisEndpoint; +import net.swofty.commons.redis.RedisMessageBus; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; + +import java.util.UUID; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RedisHandlerRegistry { + + public static void register(RedisMessageHandler handler) { + RedisProtocol protocol = handler.protocol(); + + RedisMessageBus.registerHandler( + RedisEndpoint.proxy(), + RedisChannels.protocol(protocol), + handler, + (envelope, channel) -> RedisMessageContext.between( + UUID.fromString(envelope.id()), + RedisEndpoint.server(envelope.from()), + RedisEndpoint.proxy(), + protocol.channel() + ), + envelope -> envelope.from(), + envelope -> RedisChannels.protocol(protocol) + ); + } +} diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisListener.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisListener.java deleted file mode 100644 index a382d498c..000000000 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisListener.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.swofty.velocity.redis; - -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.redis.RedisEnvelope; -import net.swofty.redisapi.api.ChannelRegistry; -import net.swofty.redisapi.api.RedisAPI; -import org.tinylog.Logger; - -import java.util.UUID; - -public abstract class RedisListener { - private final ProtocolObject protocol; - - public RedisListener() { - this.protocol = getProtocol(); - } - - public abstract ProtocolObject getProtocol(); - public abstract R receivedMessage(T message, UUID serverUUID); - - public String getChannelName() { - return protocol.channel(); - } - - public void onMessage(String channel, String message) { - String messageWithoutFilter = message.substring(message.indexOf(";") + 1); - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - UUID uuid = UUID.fromString(envelope.id()); - UUID filterID = UUID.fromString(envelope.from()); - - T typedMessage = protocol.translateFromString(envelope.payload()); - - Thread.startVirtualThread(() -> { - R response; - try { - response = receivedMessage(typedMessage, filterID); - } catch (Exception e) { - System.out.println("Error on channel " + channel + " with message " + envelope.payload()); - Logger.error(e, "Error in Redis listener"); - return; - } - - String serializedResponse = protocol.translateReturnToString(response); - - RedisAPI.getInstance().publishMessage( - filterID.toString(), - ChannelRegistry.getFromName(channel), - new RedisEnvelope(envelope.id(), "proxy", serializedResponse).serialize()); - }); - } -} diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisMessage.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisMessage.java deleted file mode 100644 index fd8089765..000000000 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/RedisMessage.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.swofty.velocity.redis; - -import net.swofty.commons.protocol.ProtocolObject; -import net.swofty.commons.redis.RedisEnvelope; -import net.swofty.redisapi.api.ChannelRegistry; -import net.swofty.redisapi.api.RedisAPI; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public class RedisMessage { - private static final Map> callbacks = new HashMap<>(); - - public static CompletableFuture sendMessageToServer(UUID server, - ProtocolObject protocol, - T message) { - UUID requestID = UUID.randomUUID(); - CompletableFuture rawFuture = new CompletableFuture<>(); - - callbacks.put(requestID, rawFuture); - - String serialized = protocol.translateToString(message); - RedisAPI.getInstance().publishMessage( - server.toString(), - ChannelRegistry.getFromName(protocol.channel()), - new RedisEnvelope(requestID.toString(), "proxy", serialized).serialize()); - - return rawFuture.thenApply(protocol::translateReturnFromString); - } - - public static void registerProxyToServer(ProtocolObject protocol) { - RedisAPI.getInstance().registerChannel(protocol.channel(), (event) -> { - String messageWithoutFilter = event.message.substring(event.message.indexOf(";") + 1); - RedisEnvelope envelope = RedisEnvelope.deserialize(messageWithoutFilter); - UUID request = UUID.fromString(envelope.id()); - String rawMessage = envelope.payload(); - - try { - callbacks.get(request).complete(rawMessage); - callbacks.remove(request); - } catch (Exception e) { - System.out.println("RedisMessage: Error while processing message"); - System.out.println("Channel: " + event.channel); - System.out.println("Message: " + event.message); - } - }); - } -} diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerCount.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerCount.java index 71dcdc996..a27bab6ab 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerCount.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerCount.java @@ -1,27 +1,26 @@ package net.swofty.velocity.redis.listeners; import net.swofty.commons.ServerType; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.PlayerCountProtocol; import net.swofty.velocity.gamemanager.GameManager; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.List; import java.util.UUID; -@ChannelListener -public class ListenerPlayerCount extends RedisListener< +public class ListenerPlayerCount implements RedisMessageHandler< PlayerCountProtocol.Request, PlayerCountProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new PlayerCountProtocol(); } @Override - public PlayerCountProtocol.Response receivedMessage(PlayerCountProtocol.Request message, UUID serverUUID) { + public PlayerCountProtocol.Response handle(PlayerCountProtocol.Request message, RedisMessageContext context) { switch (message.lookupType()) { case ALL -> { int count = GameManager.getServers().values().stream() diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerHandler.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerHandler.java index 4d9c5fcaf..4098e209c 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerHandler.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerHandler.java @@ -7,7 +7,7 @@ import net.swofty.commons.ServerType; import net.swofty.commons.StringUtility; import net.swofty.commons.UnderstandableProxyServer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.GivePlayersOriginTypeProtocol; import net.swofty.commons.protocol.objects.proxy.from.RefreshCoopDataProtocol; import net.swofty.commons.protocol.objects.proxy.from.RunEventProtocol; @@ -17,28 +17,27 @@ import net.swofty.velocity.gamemanager.GameManager; import net.swofty.velocity.gamemanager.TransferHandler; import net.swofty.velocity.presence.PresencePublisher; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; -import net.swofty.velocity.redis.RedisMessage; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisClient; import java.util.Map; import java.util.Optional; import java.util.UUID; -@ChannelListener -public class ListenerPlayerHandler extends RedisListener< +public class ListenerPlayerHandler implements RedisMessageHandler< PlayerHandlerProtocol.Request, PlayerHandlerProtocol.Response> { private static final PlayerHandlerProtocol.Response EMPTY = new PlayerHandlerProtocol.Response(Map.of(), true, null); @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new PlayerHandlerProtocol(); } @Override - public PlayerHandlerProtocol.Response receivedMessage(PlayerHandlerProtocol.Request message, UUID serverUUID) { + public PlayerHandlerProtocol.Response handle(PlayerHandlerProtocol.Request message, RedisMessageContext context) { UUID uuid = UUID.fromString(message.uuid()); PlayerHandlerProtocol.Action action = message.action(); Map data = message.data() != null ? message.data() : Map.of(); @@ -126,7 +125,7 @@ public PlayerHandlerProtocol.Response receivedMessage(PlayerHandlerProtocol.Requ Number z = (Number) data.get("z"); Number yaw = (Number) data.get("yaw"); Number pitch = (Number) data.get("pitch"); - RedisMessage.sendMessageToServer(server, + RedisClient.requestServer(server, new TeleportProtocol(), new TeleportProtocol.Request(uuid.toString(), x.doubleValue(), y.doubleValue(), z.doubleValue(), @@ -137,7 +136,7 @@ public PlayerHandlerProtocol.Response receivedMessage(PlayerHandlerProtocol.Requ return EMPTY; } UUID server = UUID.fromString(potentialServer.get().getServer().getServerInfo().getName()); - RedisMessage.sendMessageToServer(server, + RedisClient.requestServer(server, new RunEventProtocol(), new RunEventProtocol.Request(uuid.toString(), (String) data.get("event"), @@ -148,7 +147,7 @@ public PlayerHandlerProtocol.Response receivedMessage(PlayerHandlerProtocol.Requ return EMPTY; } UUID server = UUID.fromString(potentialServer.get().getServer().getServerInfo().getName()); - RedisMessage.sendMessageToServer(server, + RedisClient.requestServer(server, new RefreshCoopDataProtocol(), new RefreshCoopDataProtocol.Request(uuid.toString(), (String) data.get("datapoint"))).join(); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerPunished.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerPunished.java index 7a6dad533..1049648ee 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerPunished.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerPlayerPunished.java @@ -3,7 +3,7 @@ import com.google.gson.Gson; import io.sentry.Sentry; import net.kyori.adventure.text.Component; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.PunishPlayerProtocol; import net.swofty.commons.punishment.PunishmentReason; import net.swofty.commons.punishment.PunishmentTag; @@ -13,25 +13,24 @@ import net.swofty.commons.punishment.template.BanType; import net.swofty.commons.punishment.template.MuteType; import net.swofty.velocity.SkyBlockVelocity; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import org.tinylog.Logger; import java.util.List; import java.util.UUID; -@ChannelListener -public class ListenerPlayerPunished extends RedisListener< +public class ListenerPlayerPunished implements RedisMessageHandler< PunishPlayerProtocol.Request, PunishPlayerProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new PunishPlayerProtocol(); } @Override - public PunishPlayerProtocol.Response receivedMessage(PunishPlayerProtocol.Request message, UUID serverUUID) { + public PunishPlayerProtocol.Response handle(PunishPlayerProtocol.Request message, RedisMessageContext context) { UUID target = UUID.fromString(message.target()); String type = message.type(); String id = message.id(); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerProxyOnline.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerProxyOnline.java index 319f20892..35c132aee 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerProxyOnline.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerProxyOnline.java @@ -1,26 +1,25 @@ package net.swofty.velocity.redis.listeners; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.ProxyIsOnlineProtocol; import net.swofty.velocity.gamemanager.GameManager; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.UUID; -@ChannelListener -public class ListenerProxyOnline extends RedisListener< +public class ListenerProxyOnline implements RedisMessageHandler< ProxyIsOnlineProtocol.Request, ProxyIsOnlineProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new ProxyIsOnlineProtocol(); } @Override - public ProxyIsOnlineProtocol.Response receivedMessage(ProxyIsOnlineProtocol.Request message, UUID serverUUID) { - if (GameManager.getFromUUID(serverUUID) == null) { + public ProxyIsOnlineProtocol.Response handle(ProxyIsOnlineProtocol.Request message, RedisMessageContext context) { + if (GameManager.getFromUUID(UUID.fromString(context.origin().id())) == null) { return new ProxyIsOnlineProtocol.Response(false, true, null); } return new ProxyIsOnlineProtocol.Response(true, true, null); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerRegisterTestFlow.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerRegisterTestFlow.java index b41dbde2a..efe2c2ba0 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerRegisterTestFlow.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerRegisterTestFlow.java @@ -1,29 +1,29 @@ package net.swofty.velocity.redis.listeners; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.RegisterTestFlowProtocol; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.velocity.testflow.TestFlowManager; import org.json.JSONObject; +import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; -@ChannelListener -public class ListenerRegisterTestFlow extends RedisListener< +public class ListenerRegisterTestFlow implements RedisMessageHandler< RegisterTestFlowProtocol.Request, RegisterTestFlowProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new RegisterTestFlowProtocol(); } @Override - public RegisterTestFlowProtocol.Response receivedMessage(RegisterTestFlowProtocol.Request message, UUID serverUUID) { + public RegisterTestFlowProtocol.Response handle(RegisterTestFlowProtocol.Request message, RedisMessageContext context) { try { String testFlowName = message.testFlowName(); String handler = message.handler(); @@ -37,12 +37,12 @@ public RegisterTestFlowProtocol.Response receivedMessage(RegisterTestFlowProtoco TestFlowManager.registerTestFlow(testFlowName, handler, players, serverConfigs); - System.out.println("Registered test flow '" + testFlowName + "' from server " + serverUUID); + Logger.info("Registered test flow '{}' from server {}", testFlowName, UUID.fromString(context.origin().id())); return new RegisterTestFlowProtocol.Response(true, "Test flow registered successfully", null); } catch (Exception e) { - System.out.println("Failed to register test flow from server " + serverUUID); + Logger.error(e, "Failed to register test flow from server {}", UUID.fromString(context.origin().id())); return new RegisterTestFlowProtocol.Response(false, null, e.getMessage()); } } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerFinishedWithPlayer.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerFinishedWithPlayer.java index fbd03e942..d850d46d6 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerFinishedWithPlayer.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerFinishedWithPlayer.java @@ -1,28 +1,27 @@ package net.swofty.velocity.redis.listeners; import com.velocitypowered.api.proxy.Player; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.FinishedWithPlayerProtocol; import net.swofty.velocity.SkyBlockVelocity; import net.swofty.velocity.gamemanager.TransferHandler; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.Optional; import java.util.UUID; -@ChannelListener -public class ListenerServerFinishedWithPlayer extends RedisListener< +public class ListenerServerFinishedWithPlayer implements RedisMessageHandler< FinishedWithPlayerProtocol.Request, FinishedWithPlayerProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new FinishedWithPlayerProtocol(); } @Override - public FinishedWithPlayerProtocol.Response receivedMessage(FinishedWithPlayerProtocol.Request message, UUID serverUUID) { + public FinishedWithPlayerProtocol.Response handle(FinishedWithPlayerProtocol.Request message, RedisMessageContext context) { UUID playerUUID = UUID.fromString(message.uuid()); Optional potentialPlayer = SkyBlockVelocity.getServer().getPlayer(playerUUID); diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerInitialized.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerInitialized.java index 12950bce2..e4c94c06c 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerInitialized.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerInitialized.java @@ -2,26 +2,25 @@ import net.swofty.commons.ServerType; import net.swofty.commons.config.ConfigProvider; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.RegisterServerProtocol; import net.swofty.velocity.gamemanager.GameManager; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.UUID; -@ChannelListener -public class ListenerServerInitialized extends RedisListener< +public class ListenerServerInitialized implements RedisMessageHandler< RegisterServerProtocol.Request, RegisterServerProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new RegisterServerProtocol(); } @Override - public RegisterServerProtocol.Response receivedMessage(RegisterServerProtocol.Request message, UUID serverUUID) { + public RegisterServerProtocol.Response handle(RegisterServerProtocol.Request message, RedisMessageContext context) { ServerType type = ServerType.valueOf(message.type()); int port = message.port() != null ? message.port() : -1; @@ -31,7 +30,7 @@ public RegisterServerProtocol.Response receivedMessage(RegisterServerProtocol.Re int maxPlayers = message.maxPlayers(); - GameManager.GameServer server = GameManager.addServer(type, serverUUID, host, port, maxPlayers); + GameManager.GameServer server = GameManager.addServer(type, UUID.fromString(context.origin().id()), host, port, maxPlayers); return new RegisterServerProtocol.Response( server.registeredServer().getServerInfo().getAddress().getHostString(), server.registeredServer().getServerInfo().getAddress().getPort(), diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerName.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerName.java index 1a9afbdbf..d42685f78 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerName.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerName.java @@ -1,26 +1,25 @@ package net.swofty.velocity.redis.listeners; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.RequestServerNameProtocol; import net.swofty.velocity.gamemanager.GameManager; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import java.util.UUID; -@ChannelListener -public class ListenerServerName extends RedisListener< +public class ListenerServerName implements RedisMessageHandler< RequestServerNameProtocol.Request, RequestServerNameProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new RequestServerNameProtocol(); } @Override - public RequestServerNameProtocol.Response receivedMessage(RequestServerNameProtocol.Request message, UUID serverUUID) { - GameManager.GameServer server = GameManager.getFromUUID(serverUUID); + public RequestServerNameProtocol.Response handle(RequestServerNameProtocol.Request message, RedisMessageContext context) { + GameManager.GameServer server = GameManager.getFromUUID(UUID.fromString(context.origin().id())); return new RequestServerNameProtocol.Response(server.displayName(), server.shortDisplayName(), true, null); } } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServersInformation.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServersInformation.java index ffd3323bb..3806f4314 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServersInformation.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServersInformation.java @@ -3,30 +3,29 @@ import com.velocitypowered.api.proxy.Player; import net.swofty.commons.ServerType; import net.swofty.commons.UnderstandableProxyServer; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.RequestServersProtocol; import net.swofty.velocity.SkyBlockVelocity; import net.swofty.velocity.gamemanager.GameManager; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.velocity.testflow.TestFlowManager; import java.util.*; -@ChannelListener -public class ListenerServersInformation extends RedisListener< +public class ListenerServersInformation implements RedisMessageHandler< RequestServersProtocol.Request, RequestServersProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new RequestServersProtocol(); } @Override - public RequestServersProtocol.Response receivedMessage(RequestServersProtocol.Request message, UUID serverUUID) { + public RequestServersProtocol.Response handle(RequestServersProtocol.Request message, RedisMessageContext context) { String requestType = message.requestType(); - boolean isInTestFlow = TestFlowManager.isServerInTestFlow(serverUUID); + boolean isInTestFlow = TestFlowManager.isServerInTestFlow(UUID.fromString(context.origin().id())); switch (requestType) { case "ALL" -> { diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerStaffChat.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerStaffChat.java index 4f66465e5..27c6ef8ec 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerStaffChat.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerStaffChat.java @@ -1,27 +1,26 @@ package net.swofty.velocity.redis.listeners; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.from.BroadcastStaffChatProtocol; import net.swofty.commons.protocol.objects.proxy.to.StaffChatProtocol; import net.swofty.velocity.gamemanager.GameManager; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; -import net.swofty.velocity.redis.RedisMessage; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; +import net.swofty.commons.redis.RedisClient; import java.util.UUID; -@ChannelListener -public class ListenerStaffChat extends RedisListener< +public class ListenerStaffChat implements RedisMessageHandler< StaffChatProtocol.Request, StaffChatProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new StaffChatProtocol(); } @Override - public StaffChatProtocol.Response receivedMessage(StaffChatProtocol.Request message, UUID serverUUID) { + public StaffChatProtocol.Response handle(StaffChatProtocol.Request message, RedisMessageContext context) { broadcastToAllServers(new BroadcastStaffChatProtocol.Request( message.type(), message.formattedMessage(), message.uuid())); return new StaffChatProtocol.Response(); @@ -30,7 +29,7 @@ public StaffChatProtocol.Response receivedMessage(StaffChatProtocol.Request mess public static void broadcastToAllServers(BroadcastStaffChatProtocol.Request message) { GameManager.getServers().forEach((serverType, serverList) -> { serverList.forEach(gameServer -> { - RedisMessage.sendMessageToServer( + RedisClient.requestServer( gameServer.internalID(), new BroadcastStaffChatProtocol(), message diff --git a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerTestFlowServerReady.java b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerTestFlowServerReady.java index 495f31186..e9cf5abef 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerTestFlowServerReady.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerTestFlowServerReady.java @@ -1,40 +1,40 @@ package net.swofty.velocity.redis.listeners; import net.swofty.commons.ServerType; -import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.RedisProtocol; import net.swofty.commons.protocol.objects.proxy.to.TestFlowServerReadyProtocol; -import net.swofty.velocity.redis.ChannelListener; -import net.swofty.velocity.redis.RedisListener; +import net.swofty.commons.redis.RedisMessageContext; +import net.swofty.commons.redis.RedisMessageHandler; import net.swofty.velocity.testflow.TestFlowManager; +import org.tinylog.Logger; import java.util.UUID; -@ChannelListener -public class ListenerTestFlowServerReady extends RedisListener< +public class ListenerTestFlowServerReady implements RedisMessageHandler< TestFlowServerReadyProtocol.Request, TestFlowServerReadyProtocol.Response> { @Override - public ProtocolObject getProtocol() { + public RedisProtocol protocol() { return new TestFlowServerReadyProtocol(); } @Override - public TestFlowServerReadyProtocol.Response receivedMessage(TestFlowServerReadyProtocol.Request message, UUID serverUUID) { + public TestFlowServerReadyProtocol.Response handle(TestFlowServerReadyProtocol.Request message, RedisMessageContext context) { try { String testFlowName = message.testFlowName(); ServerType serverType = ServerType.valueOf(message.serverType()); int serverIndex = message.serverIndex(); - TestFlowManager.markServerReady(testFlowName, serverType, serverIndex, serverUUID); + TestFlowManager.markServerReady(testFlowName, serverType, serverIndex, UUID.fromString(context.origin().id())); - System.out.println("Server " + serverType.name() + " #" + serverIndex + - " is ready for test flow '" + testFlowName + "' (UUID: " + serverUUID + ")"); + Logger.info("Server {} #{} is ready for test flow '{}' (UUID: {})", + serverType.name(), serverIndex, testFlowName, UUID.fromString(context.origin().id())); return new TestFlowServerReadyProtocol.Response(true, "Server ready status recorded", null); } catch (Exception e) { - System.out.println("Failed to process test flow server ready from server " + serverUUID); + Logger.error(e, "Failed to process test flow server ready from server {}", UUID.fromString(context.origin().id())); return new TestFlowServerReadyProtocol.Response(false, null, e.getMessage()); } } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/testflow/TestFlowManager.java b/velocity.extension/src/main/java/net/swofty/velocity/testflow/TestFlowManager.java index ccd9c2de2..184d2797d 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/testflow/TestFlowManager.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/testflow/TestFlowManager.java @@ -3,6 +3,7 @@ import lombok.Getter; import net.swofty.commons.ServerType; import net.swofty.velocity.gamemanager.GameManager; +import org.tinylog.Logger; import java.lang.reflect.Constructor; import java.util.ArrayList; @@ -26,17 +27,15 @@ public class TestFlowManager { */ public static void registerTestFlow(String name, String handler, List players, List serverConfigs) { if (activeTestFlows.containsKey(name)) { - System.out.println("[WARN] Test flow " + name + " is already registered, ignoring duplicate registration"); + Logger.warn("Test flow {} is already registered, ignoring duplicate registration", name); return; } ProxyTestFlowInstance instance = new ProxyTestFlowInstance(name, handler, players, serverConfigs); activeTestFlows.put(name, instance); - System.out.println("[INFO] Registered test flow: " + name); - System.out.println("[INFO] Handler: " + handler); - System.out.println("[INFO] Players: " + players); - System.out.println("[INFO] Expected servers: " + instance.getTotalExpectedServers()); + Logger.info("Registered test flow: {} (handler={}, players={}, expectedServers={})", + name, handler, players, instance.getTotalExpectedServers()); // Try to load and instantiate the handler loadTestFlowHandler(instance); @@ -48,17 +47,17 @@ public static void registerTestFlow(String name, String handler, List pl public static void markServerReady(String testFlowName, ServerType serverType, int serverIndex, UUID serverUUID) { ProxyTestFlowInstance instance = activeTestFlows.get(testFlowName); if (instance == null) { - System.out.println("[WARN] Received server ready notification for unknown test flow: " + testFlowName); + Logger.warn("Received server ready notification for unknown test flow: {}", testFlowName); return; } instance.markServerReady(serverType, serverIndex, serverUUID); - System.out.println("[INFO] Server " + serverType.name() + " #" + serverIndex + " is ready for test flow: " + testFlowName); + Logger.info("Server {} #{} is ready for test flow: {}", serverType.name(), serverIndex, testFlowName); // Only trigger "all servers ready" once when we actually reach the total count if (instance.areAllServersReady() && !instance.isAllServersReadyTriggered()) { instance.setAllServersReadyTriggered(true); - System.out.println("[INFO] All servers are ready for test flow: " + testFlowName); + Logger.info("All servers are ready for test flow: {}", testFlowName); if (instance.getHandler() != null) { instance.getHandler().onAllServersReady(instance); } @@ -72,17 +71,15 @@ public static void markServerReady(String testFlowName, ServerType serverType, i public static void handleServerDisconnect(UUID serverUUID) { activeTestFlows.values().forEach(instance -> { if (instance.getServerUUIDs().contains(serverUUID)) { - System.out.println("[INFO] Test flow server disconnected: " + serverUUID + " from test flow: " + instance.getName()); + Logger.info("Test flow server disconnected: {} from test flow: {}", serverUUID, instance.getName()); - // Remove the server from the ready servers list instance.removeServer(serverUUID); - // Check if any servers are still online for this test flow if (instance.hasAnyServersOnline()) { - System.out.println("[INFO] Test flow " + instance.getName() + " still has " + - instance.getOnlineServerCount() + " servers online"); + Logger.info("Test flow {} still has {} servers online", + instance.getName(), instance.getOnlineServerCount()); } else { - System.out.println("[WARN] All servers for test flow " + instance.getName() + " are offline, cleaning up..."); + Logger.warn("All servers for test flow {} are offline, cleaning up...", instance.getName()); cleanupTestFlow(instance.getName()); } } @@ -96,20 +93,18 @@ public static void handleServerDisconnect(UUID serverUUID) { private static void cleanupTestFlow(String testFlowName) { ProxyTestFlowInstance instance = activeTestFlows.get(testFlowName); if (instance != null) { - System.out.println("[INFO] Cleaning up test flow: " + testFlowName); + Logger.info("Cleaning up test flow: {}", testFlowName); - // Notify handler that test flow is ending if (instance.getHandler() != null) { try { instance.getHandler().onTestFlowEnd(instance); } catch (Exception e) { - System.out.println("[ERROR] Error in test flow handler onTestFlowEnd: " + e.getMessage()); + Logger.error(e, "Error in test flow handler onTestFlowEnd"); } } - // Remove from active test flows activeTestFlows.remove(testFlowName); - System.out.println("[INFO] Test flow " + testFlowName + " has been cleaned up and removed"); + Logger.info("Test flow {} has been cleaned up and removed", testFlowName); } } @@ -157,7 +152,7 @@ public static void unregisterTestFlow(String name) { ProxyTestFlowInstance instance = activeTestFlows.remove(name); if (instance != null && instance.getHandler() != null) { instance.getHandler().onTestFlowEnd(instance); - System.out.println("[INFO] Unregistered test flow: " + name); + Logger.info("Unregistered test flow: {}", name); } } @@ -202,32 +197,24 @@ private static void loadTestFlowHandler(ProxyTestFlowInstance instance) { ProxyTestFlowHandler handler = (ProxyTestFlowHandler) constructor.newInstance(); instance.setHandler(handler); handler.onTestFlowStart(instance); - System.out.println("[INFO] Successfully loaded test flow handler: " + handlerName); + Logger.info("Successfully loaded test flow handler: {}", handlerName); } else { - System.out.println("[ERROR] Handler " + handlerName + " does not extend ProxyTestFlowHandler"); + Logger.error("Handler {} does not extend ProxyTestFlowHandler", handlerName); } } catch (Exception e) { - System.out.println("[ERROR] Failed to load test flow handler: " + instance.getHandlerClassName() + " - " + e.getMessage()); + Logger.error(e, "Failed to load test flow handler: {}", instance.getHandlerClassName()); } } /** * Server configuration for test flows */ - @Getter - public static class ServerConfig { - private final ServerType serverType; - private final int count; - - public ServerConfig(ServerType serverType, int count) { - this.serverType = serverType; - this.count = count; - } - + public record ServerConfig(ServerType serverType, int count) { public static ServerConfig fromJson(org.json.JSONObject json) { - ServerType type = ServerType.valueOf(json.getString("type")); - int count = json.getInt("count"); - return new ServerConfig(type, count); + return new ServerConfig( + ServerType.valueOf(json.getString("type")), + json.getInt("count") + ); } } @@ -287,7 +274,7 @@ public boolean hasPlayer(String playerName) { public int getTotalExpectedServers() { return serverConfigs.stream() - .mapToInt(ServerConfig::getCount) + .mapToInt(ServerConfig::count) .sum(); } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/testflow/handlers/SendToHubTestFlowHandler.java b/velocity.extension/src/main/java/net/swofty/velocity/testflow/handlers/SendToHubTestFlowHandler.java index 8ec7559e3..3988cf4a7 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/testflow/handlers/SendToHubTestFlowHandler.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/testflow/handlers/SendToHubTestFlowHandler.java @@ -3,6 +3,7 @@ import net.swofty.velocity.SkyBlockVelocity; import net.swofty.velocity.testflow.ProxyTestFlowHandler; import net.swofty.velocity.testflow.TestFlowManager; +import org.tinylog.Logger; public class SendToHubTestFlowHandler extends ProxyTestFlowHandler { @@ -28,19 +29,20 @@ public void onPlayerLeave(String playerName, TestFlowManager.ProxyTestFlowInstan @Override public void onTestFlowEnd(TestFlowManager.ProxyTestFlowInstance instance) { - System.out.println("Example test flow ended: " + instance.getName()); + Logger.info("Example test flow ended: {}", instance.getName()); } @Override public void onPeriodicUpdate(TestFlowManager.ProxyTestFlowInstance instance) { if (instance.getUptime() % 300000 == 0) { - System.out.println("Test flow " + instance.getName() + " status update:"); - System.out.println(" Runtime: " + (instance.getUptime() / 1000) + " seconds"); - System.out.println(" Active servers: " + instance.getGameServers().size()); - System.out.println(" Online test players: " + - instance.getPlayers().stream() - .mapToLong(name -> SkyBlockVelocity.getServer().getPlayer(name).isPresent() ? 1 : 0) - .sum()); + long onlinePlayers = instance.getPlayers().stream() + .mapToLong(name -> SkyBlockVelocity.getServer().getPlayer(name).isPresent() ? 1 : 0) + .sum(); + Logger.info("Test flow {} status — runtime: {}s, active servers: {}, online test players: {}", + instance.getName(), + instance.getUptime() / 1000, + instance.getGameServers().size(), + onlinePlayers); } } } \ No newline at end of file diff --git a/velocity.extension/src/main/java/net/swofty/velocity/viaversion/injector/SkyBlockViaInjector.java b/velocity.extension/src/main/java/net/swofty/velocity/viaversion/injector/SkyBlockViaInjector.java index c171274c7..c3f19eb9b 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/viaversion/injector/SkyBlockViaInjector.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/viaversion/injector/SkyBlockViaInjector.java @@ -10,6 +10,7 @@ import net.swofty.velocity.SkyBlockVelocity; import net.swofty.velocity.packet.PlayerChannelInitializer; import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -22,7 +23,7 @@ public class SkyBlockViaInjector implements ViaInjector { try { return Class.forName("com.velocitypowered.proxy.config.VelocityConfiguration").getMethod("getPlayerInfoForwardingMode"); } catch (NoSuchMethodException | ClassNotFoundException e) { - System.out.println("Failed to get getPlayerInfoForwardingMode method from Velocity"); + Logger.warn(e, "Failed to get getPlayerInfoForwardingMode method from Velocity"); return null; } } diff --git a/velocity.extension/src/main/java/net/swofty/velocity/viaversion/provider/SkyBlockVersionProvider.java b/velocity.extension/src/main/java/net/swofty/velocity/viaversion/provider/SkyBlockVersionProvider.java index c0cfa65c2..bdd644ea5 100644 --- a/velocity.extension/src/main/java/net/swofty/velocity/viaversion/provider/SkyBlockVersionProvider.java +++ b/velocity.extension/src/main/java/net/swofty/velocity/viaversion/provider/SkyBlockVersionProvider.java @@ -10,6 +10,7 @@ import net.swofty.velocity.SkyBlockVelocity; import net.swofty.velocity.viaversion.injector.SkyBlockViaInjector; import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; public class SkyBlockVersionProvider implements VersionProvider { private static final Method GET_ASSOCIATION = getAssociationMethod(); @@ -18,7 +19,7 @@ public class SkyBlockVersionProvider implements VersionProvider { try { return Class.forName("com.velocitypowered.proxy.connection.MinecraftConnection").getMethod("getAssociation"); } catch (NoSuchMethodException | ClassNotFoundException e) { - System.out.println("Failed to get association method from Velocity"); + Logger.warn(e, "Failed to get association method from Velocity"); return null; } } @@ -61,7 +62,7 @@ private ProtocolVersion getFrontProtocol(UserConnection user) throws Exception { } } - System.out.println("Panic, no protocol id found for " + playerVersion); + Logger.warn("No registered protocol id found for {}, falling back to player version", playerVersion); return playerVersion; } } diff --git a/website/package-lock.json b/website/package-lock.json index 36f61b2bc..d485ab882 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -12,7 +12,7 @@ }, "devDependencies": { "vitepress": "^1.5.0", - "vue": "^3.5.31" + "vue": "^3.5.34" } }, "node_modules/@algolia/abtesting": { @@ -294,9 +294,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "dev": true, "license": "MIT", "dependencies": { @@ -1314,57 +1314,57 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.31.tgz", - "integrity": "sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.34.tgz", + "integrity": "sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/shared": "3.5.31", + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.34", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.31.tgz", - "integrity": "sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.34.tgz", + "integrity": "sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-core": "3.5.34", + "@vue/shared": "3.5.34" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.31.tgz", - "integrity": "sha512-M8wpPgR9UJ8MiRGjppvx9uWJfLV7A/T+/rL8s/y3QG3u0c2/YZgff3d6SuimKRIhcYnWg5fTfDMlz2E6seUW8Q==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.34.tgz", + "integrity": "sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/compiler-core": "3.5.31", - "@vue/compiler-dom": "3.5.31", - "@vue/compiler-ssr": "3.5.31", - "@vue/shared": "3.5.31", + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.34", + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.14", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.31.tgz", - "integrity": "sha512-h0xIMxrt/LHOvJKMri+vdYT92BrK3HFLtDqq9Pr/lVVfE4IyKZKvWf0vJFW10Yr6nX02OR4MkJwI0c1HDa1hog==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.34.tgz", + "integrity": "sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-dom": "3.5.34", + "@vue/shared": "3.5.34" } }, "node_modules/@vue/devtools-api": { @@ -1404,57 +1404,57 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.31.tgz", - "integrity": "sha512-DtKXxk9E/KuVvt8VxWu+6Luc9I9ETNcqR1T1oW1gf02nXaZ1kuAx58oVu7uX9XxJR0iJCro6fqBLw9oSBELo5g==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.34.tgz", + "integrity": "sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.31" + "@vue/shared": "3.5.34" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.31.tgz", - "integrity": "sha512-AZPmIHXEAyhpkmN7aWlqjSfYynmkWlluDNPHMCZKFHH+lLtxP/30UJmoVhXmbDoP1Ng0jG0fyY2zCj1PnSSA6Q==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.34.tgz", + "integrity": "sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/reactivity": "3.5.34", + "@vue/shared": "3.5.34" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.31.tgz", - "integrity": "sha512-xQJsNRmGPeDCJq/u813tyonNgWBFjzfVkBwDREdEWndBnGdHLHgkwNBQxLtg4zDrzKTEcnikUy1UUNecb3lJ6g==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.34.tgz", + "integrity": "sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/runtime-core": "3.5.31", - "@vue/shared": "3.5.31", + "@vue/reactivity": "3.5.34", + "@vue/runtime-core": "3.5.34", + "@vue/shared": "3.5.34", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.31.tgz", - "integrity": "sha512-GJuwRvMcdZX/CriUnyIIOGkx3rMV3H6sOu0JhdKbduaeCji6zb60iOGMY7tFoN24NfsUYoFBhshZtGxGpxO4iA==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.34.tgz", + "integrity": "sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34" }, "peerDependencies": { - "vue": "3.5.31" + "vue": "3.5.34" } }, "node_modules/@vue/shared": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.31.tgz", - "integrity": "sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.34.tgz", + "integrity": "sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==", "dev": true, "license": "MIT" }, @@ -2050,9 +2050,9 @@ "license": "ISC" }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "dev": true, "funding": [ { @@ -2487,17 +2487,17 @@ } }, "node_modules/vue": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", - "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.34.tgz", + "integrity": "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.31", - "@vue/compiler-sfc": "3.5.31", - "@vue/runtime-dom": "3.5.31", - "@vue/server-renderer": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-sfc": "3.5.34", + "@vue/runtime-dom": "3.5.34", + "@vue/server-renderer": "3.5.34", + "@vue/shared": "3.5.34" }, "peerDependencies": { "typescript": "*" diff --git a/website/package.json b/website/package.json index f939cac11..a911e1cf8 100644 --- a/website/package.json +++ b/website/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "vitepress": "^1.5.0", - "vue": "^3.5.31" + "vue": "^3.5.34" }, "dependencies": { "markdown-it-container": "^4.0.0"