diff --git a/README.md b/README.md index f7c98ea..875e803 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,21 @@ Cobblemon Challenge is an extremely simple plugin for Cobblemon that makes challenging your friends and rivals to flat-level Pokemon battles easier! This is a server-side plugin that only needs to be installed on the Server. -#### Commands - +#### Command Parameters ```/challenge ``` - Challenges specified player to a lvl 50 pokemon battle. They may accept or deny this challenge. -```/challenge level ``` - Challenges specified player to a lvl X battle where X can be 1-100. +```/challenge level ``` - Challenges specified player to a lvl `````` battle where `````` can be **1 min** & **100 max**. + +```/challenge levelRange ``` - Challenges specified player to a lvl where the Pokemon's levels are clamped between the ``````&`````` where ``````&`````` can be **1 min** & **100 max**. + +```/challenge handicap ``` - Challenges specified player to a battle where `````` (the challenger) & `````` (the challenged) Pokemon level is offset by the input level. ``````&`````` can be from **-99 min** & **99 max**. + +```/challenge showPreview ``` - Challenges specified player to a default battle with no preview of the rivals pokemon during starter selection. + +##### Notes About Command Parameters: +1. The order of parameter input must be ```username``` -> ```level/levelRange``` -> ```handicap``` -> ```showPreview```. +2. If the challenge property is optional & not specified in the command. The default values from the config file will be used. -Example: ```/challenge TurtleHoarder level 100``` challenges TurtleHoarder to a level 100 battle. #### Configurations There are numerous options that will allow you to customize the Challenge experience to your server's needs. These settings can be found in the Cobblemon Challenge config file: @@ -18,14 +26,49 @@ settings can be found in the Cobblemon Challenge config file: ```challengeDistanceRestriction``` - The value that determines if challenges are restricted by distance. Set to **false** if you would want no restrictions on distance. This value is set to **true** by default. -```maxChallengeDistance``` - If challengeDistanceRestriction is set to **true**, then this value defines the max distance +```maxChallengeDistance``` - If challengeDistanceRestriction is set to **true**, then this value defines the max distance that a challenge can be sent. This is set to 50 blocks by default. -```defaultChallengeLevel``` - The value that determines the level of a challenge if there is not level specified by the challenger. +```defaultChallengeLevel``` - The value that determines the level of a challenge if there is no level specified by the challenger. This is set to 50 by default for lvl 50 battles. +```defaultHandicap``` - The value that determines each player's final level of each Pokemon if a handicap is not specified by the challenger. +This is set to 0 by default. + +```defaultShowPreview``` - If defaultShowPreview is set to **true** both players will see which pokemon the opponent is bringing to battle. If defaultShowPreview is set to **false** both players parties will be hidden from their opponent. +(Note: Even when defaultShowPreview is true the player will never see the opponents chosen lead pokemon) +This is set to true by default. + ```challengeExpirationTime``` - The value that determines how long a challenge should be pending before it expires. This is set to 60000 milliseconds / 1 minute by default. -```challengeCooldownTime``` - The value that determines how long a player must wait before sending a consecutive request. This value is +```challengeCooldownTime``` - The value that determines how long a player must wait before sending a consecutive request. This value is set to 5000 milliseconds / 5 seconds by default, though players will need to wait until their existing challenge expires before sending another one. + +### All Possible Commands: + +```/challenge ``` + +```/challenge handicap ``` + +```/challenge showPreview ``` + +```/challenge handicap showPreview ``` + + +```/challenge level ``` + +```/challenge level handicap ``` + +```/challenge level showPreview ``` + +```/challenge level handicap showPreview ``` + + +```/challenge levelRange ``` + +```/challenge levelRange handicap ``` + +```/challenge levelRange showPreview ``` + +```/challenge levelRange handicap showPreview ``` \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0cec26b..ff51ebb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,18 +1,13 @@ plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' id 'maven-publish' - id 'org.jetbrains.kotlin.jvm' version "1.7.10" + id 'org.jetbrains.kotlin.jvm' version "2.0.0" } version = project.mod_version group = project.maven_group repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. maven {url = "https://maven.parchmentmc.org"} maven { url "https://cursemaven.com" @@ -46,6 +41,7 @@ dependencies { //modRuntimeOnly"curse.maven:cobblemon-687131:4468330" modImplementation"curse.maven:architectury-419699:4663010" + modImplementation("net.fabricmc:fabric-language-kotlin:1.11.0+kotlin.2.0.0") } base { diff --git a/gradle.properties b/gradle.properties index e78e6ff..e7ecc3d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.parallel=true # check these on https://fabricmc.net/develop minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 -loader_version=0.14.22 +loader_version=0.15.11 # Mod Properties mod_version = 1.1.7 @@ -14,5 +14,5 @@ maven_group = com.turtlehoarder.cobblemonchallenge archives_base_name = cobblemonchallenge # Dependencies -fabric_version=0.89.3+1.20.1 -cloth_config_version=11.1.106 \ No newline at end of file +fabric_version=0.92.2+1.20.1 +cloth_config_version=11.1.118 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index db9a6b8..a8382d7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/api/ChallengeRequest.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/api/ChallengeRequest.java new file mode 100644 index 0000000..f930b02 --- /dev/null +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/api/ChallengeRequest.java @@ -0,0 +1,17 @@ +package com.turtlehoarder.cobblemonchallenge.api; + +import net.minecraft.server.level.ServerPlayer; + +public record ChallengeRequest ( + String id, + ServerPlayer challengerPlayer, + ServerPlayer challengedPlayer, + int minLevel, + int maxLevel, + int handicapP1, + int handicapP2, + boolean preview, + long createdTime +) { + +} diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/api/LeadPokemonSelection.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/api/LeadPokemonSelection.java new file mode 100644 index 0000000..dc715a4 --- /dev/null +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/api/LeadPokemonSelection.java @@ -0,0 +1,10 @@ +package com.turtlehoarder.cobblemonchallenge.api; + +import com.turtlehoarder.cobblemonchallenge.gui.LeadPokemonSelectionSession; + +public record LeadPokemonSelection( + LeadPokemonSelectionSession selectionWrapper, + long createdTime +) { + +} diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/command/ChallengeCommand.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/command/ChallengeCommand.java index 2807409..a6b7a98 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/command/ChallengeCommand.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/command/ChallengeCommand.java @@ -1,17 +1,22 @@ package com.turtlehoarder.cobblemonchallenge.command; +import com.turtlehoarder.cobblemonchallenge.api.ChallengeRequest; +import com.turtlehoarder.cobblemonchallenge.api.LeadPokemonSelection; +import com.turtlehoarder.cobblemonchallenge.config.ChallengeConfig; +import com.turtlehoarder.cobblemonchallenge.gui.LeadPokemonSelectionSession; +import com.turtlehoarder.cobblemonchallenge.util.ChallengeUtil; + import com.cobblemon.mod.common.Cobblemon; import com.cobblemon.mod.common.battles.BattleRegistry; + +import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; -import com.turtlehoarder.cobblemonchallenge.config.ChallengeConfig; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; -import com.turtlehoarder.cobblemonchallenge.gui.LeadPokemonMenuProvider; -import com.turtlehoarder.cobblemonchallenge.util.ChallengeUtil; -import com.turtlehoarder.cobblemonchallenge.gui.LeadPokemonSelectionSession; + import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; @@ -28,12 +33,11 @@ public class ChallengeCommand { - public record ChallengeRequest(String id, ServerPlayer challengerPlayer, ServerPlayer challengedPlayer, int minLevel, int maxLevel, int handicapP1, int handicapP2, boolean preview, long createdTime) {} - public record LeadPokemonSelection(LeadPokemonSelectionSession selectionWrapper, long createdTime) {} private static final float MAX_DISTANCE = ChallengeConfig.MAX_CHALLENGE_DISTANCE; private static final boolean USE_DISTANCE_RESTRICTION = ChallengeConfig.CHALLENGE_DISTANCE_RESTRICTION; private static final int DEFAULT_LEVEL = ChallengeConfig.DEFAULT_CHALLENGE_LEVEL; private static final int DEFAULT_HANDICAP = ChallengeConfig.DEFAULT_HANDICAP; + private static final boolean DEFAULT_SHOW_PREVIEW = ChallengeConfig.DEFAULT_SHOW_PREVIEW; private static final int CHALLENGE_COOLDOWN = ChallengeConfig.CHALLENGE_COOLDOWN_MILLIS; public static HashMap CHALLENGE_REQUESTS = new HashMap<>(); public static final HashMap ACTIVE_SELECTIONS = new HashMap<>(); @@ -43,7 +47,7 @@ public static void register(CommandDispatcher dispatcher) { // Overview: // > always player name with level or min/maxLevel are mutually exclusive // > 12 command trees - // > further additions may need a UI implementation to refine/make more user friendly + // > further additions may need a UI implementation to refine/make more user-friendly // (default everything) // handicap @@ -63,19 +67,16 @@ public static void register(CommandDispatcher dispatcher) { // (default everything) LiteralArgumentBuilder defaultChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, DEFAULT_HANDICAP, DEFAULT_HANDICAP, true)) + .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, DEFAULT_HANDICAP, DEFAULT_HANDICAP, DEFAULT_SHOW_PREVIEW)) ); // handicap LiteralArgumentBuilder handicapChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .then(Commands.literal("handicapP1") - .then(Commands.argument("setP1HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("handicapP2") - .then(Commands.argument("setP2HandicapTo", IntegerArgumentType.integer(-99,99)) - .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, IntegerArgumentType.getInteger(c, "setP1HandicapTo"), IntegerArgumentType.getInteger(c, "setP2HandicapTo"), true)) - ) - + .then(Commands.literal("handicap") + .then(Commands.argument("self", IntegerArgumentType.integer(-99,99)) + .then(Commands.argument("rival", IntegerArgumentType.integer(-99,99)) + .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, IntegerArgumentType.getInteger(c, "self"), IntegerArgumentType.getInteger(c, "rival"), DEFAULT_SHOW_PREVIEW)) ) ) ) @@ -84,20 +85,22 @@ public static void register(CommandDispatcher dispatcher) { // no preview LiteralArgumentBuilder noPreviewChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .then(Commands.literal("nopreview") - .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, DEFAULT_HANDICAP, DEFAULT_HANDICAP, false)) + .then(Commands.literal("showPreview") + .then(Commands.argument("show",BoolArgumentType.bool()) + .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, DEFAULT_HANDICAP, DEFAULT_HANDICAP, BoolArgumentType.getBool(c, "show"))) + ) ) ); // handicap + no preview LiteralArgumentBuilder handicapNoPreviewChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .then(Commands.literal("handicapP1") - .then(Commands.argument("setP1HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("handicapP2") - .then(Commands.argument("setP2HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("nopreview") - .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, IntegerArgumentType.getInteger(c, "setP1HandicapTo"), IntegerArgumentType.getInteger(c, "setP2HandicapTo"), false)) + .then(Commands.literal("handicap") + .then(Commands.argument("self", IntegerArgumentType.integer(-99,99)) + .then(Commands.argument("rival", IntegerArgumentType.integer(-99,99)) + .then(Commands.literal("showPreview") + .then(Commands.argument("show",BoolArgumentType.bool()) + .executes(c -> challengePlayer(c, DEFAULT_LEVEL, DEFAULT_LEVEL, IntegerArgumentType.getInteger(c, "self"), IntegerArgumentType.getInteger(c, "rival"), BoolArgumentType.getBool(c, "show"))) ) ) ) @@ -110,7 +113,7 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("player", EntityArgument.player()) .then(Commands.literal("level") .then(Commands.argument("setLevelTo", IntegerArgumentType.integer(1,100)) - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, true)) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, DEFAULT_SHOW_PREVIEW)) ) ) @@ -121,16 +124,13 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("player", EntityArgument.player()) .then(Commands.literal("level") .then(Commands.argument("setLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("handicapP1") - .then(Commands.argument("setP1HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("handicapP2") - .then(Commands.argument("setP2HandicapTo", IntegerArgumentType.integer(-99,99)) - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setP1HandicapTo"), IntegerArgumentType.getInteger(c, "setP2HandicapTo"), true)) - ) + .then(Commands.literal("handicap") + .then(Commands.argument("self", IntegerArgumentType.integer(-99,99)) + .then(Commands.argument("rival", IntegerArgumentType.integer(-99,99)) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "self"), IntegerArgumentType.getInteger(c, "rival"), DEFAULT_SHOW_PREVIEW)) ) ) ) - ) ) ); @@ -140,10 +140,11 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("player", EntityArgument.player()) .then(Commands.literal("level") .then(Commands.argument("setLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("nopreview") - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, false)) + .then(Commands.literal("showPreview") + .then(Commands.argument("show",BoolArgumentType.bool()) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, BoolArgumentType.getBool(c, "show"))) + ) ) - ) ) ); @@ -153,18 +154,17 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("player", EntityArgument.player()) .then(Commands.literal("level") .then(Commands.argument("setLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("handicapP1") - .then(Commands.argument("setP1HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("handicapP2") - .then(Commands.argument("setP2HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("nopreview") - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setP1HandicapTo"), IntegerArgumentType.getInteger(c, "setP2HandicapTo"), false)) + .then(Commands.literal("handicap") + .then(Commands.argument("self", IntegerArgumentType.integer(-99,99)) + .then(Commands.argument("rival", IntegerArgumentType.integer(-99,99)) + .then(Commands.literal("showPreview") + .then(Commands.argument("show",BoolArgumentType.bool()) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "setLevelTo"), IntegerArgumentType.getInteger(c, "self"), IntegerArgumentType.getInteger(c, "rival"), BoolArgumentType.getBool(c, "show"))) ) ) ) ) ) - ) ) ); @@ -172,14 +172,11 @@ public static void register(CommandDispatcher dispatcher) { // min/max LiteralArgumentBuilder minMaxLevelChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .then(Commands.literal("minLevel") - .then(Commands.argument("setMinLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("maxLevel") - .then(Commands.argument("setMaxLevelTo", IntegerArgumentType.integer(1,100)) - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setMinLevelTo"), IntegerArgumentType.getInteger(c, "setMaxLevelTo"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, true)) - ) + .then(Commands.literal("levelRange") + .then(Commands.argument("minLevel", IntegerArgumentType.integer(1,100)) + .then(Commands.argument("maxLevel", IntegerArgumentType.integer(1,100)) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "minLevel"), IntegerArgumentType.getInteger(c, "maxLevel"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, DEFAULT_SHOW_PREVIEW)) ) - ) ) ); @@ -187,22 +184,17 @@ public static void register(CommandDispatcher dispatcher) { // min/max + handicap LiteralArgumentBuilder minMaxLevelHandicapChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .then(Commands.literal("minLevel") - .then(Commands.argument("setMinLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("maxLevel") - .then(Commands.argument("setMaxLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("handicapP1") - .then(Commands.argument("setP1HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("handicapP2") - .then(Commands.argument("setP2HandicapTo", IntegerArgumentType.integer(-99,99)) - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setMinLevelTo"), IntegerArgumentType.getInteger(c, "setMaxLevelTo"), IntegerArgumentType.getInteger(c, "setP1HandicapTo"), IntegerArgumentType.getInteger(c, "setP2HandicapTo"), true)) - ) - ) + .then(Commands.literal("levelRange") + .then(Commands.argument("minLevel", IntegerArgumentType.integer(1,100)) + .then(Commands.argument("maxLevel", IntegerArgumentType.integer(1,100)) + .then(Commands.literal("handicap") + .then(Commands.argument("self", IntegerArgumentType.integer(-99,99)) + .then(Commands.argument("rival", IntegerArgumentType.integer(-99,99)) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "minLevel"), IntegerArgumentType.getInteger(c, "maxLevel"), IntegerArgumentType.getInteger(c, "self"), IntegerArgumentType.getInteger(c, "rival"), DEFAULT_SHOW_PREVIEW)) ) ) ) ) - ) ) ); @@ -210,16 +202,15 @@ public static void register(CommandDispatcher dispatcher) { // min/max + no preview LiteralArgumentBuilder minMaxLevelNoPreviewChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .then(Commands.literal("minLevel") - .then(Commands.argument("setMinLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("maxLevel") - .then(Commands.argument("setMaxLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("nopreview") - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setMinLevelTo"), IntegerArgumentType.getInteger(c, "setMaxLevelTo"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, false)) + .then(Commands.literal("levelRange") + .then(Commands.argument("minLevel", IntegerArgumentType.integer(1,100)) + .then(Commands.argument("maxLevel", IntegerArgumentType.integer(1,100)) + .then(Commands.literal("showPreview") + .then(Commands.argument("show",BoolArgumentType.bool()) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "minLevel"), IntegerArgumentType.getInteger(c, "maxLevel"), DEFAULT_HANDICAP, DEFAULT_HANDICAP, BoolArgumentType.getBool(c, "show"))) ) ) ) - ) ) ); @@ -227,33 +218,30 @@ public static void register(CommandDispatcher dispatcher) { // min/max + handicap + no preview LiteralArgumentBuilder minMaxLevelHandicapNoPreviewChallengeProperties = Commands.literal("challenge") .then(Commands.argument("player", EntityArgument.player()) - .then(Commands.literal("minLevel") - .then(Commands.argument("setMinLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("maxLevel") - .then(Commands.argument("setMaxLevelTo", IntegerArgumentType.integer(1,100)) - .then(Commands.literal("handicapP1") - .then(Commands.argument("setP1HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("handicapP2") - .then(Commands.argument("setP2HandicapTo", IntegerArgumentType.integer(-99,99)) - .then(Commands.literal("nopreview") - .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "setMinLevelTo"), IntegerArgumentType.getInteger(c, "setMaxLevelTo"), IntegerArgumentType.getInteger(c, "setP1HandicapTo"), IntegerArgumentType.getInteger(c, "setP2HandicapTo"), false)) - ) + .then(Commands.literal("levelRange") + .then(Commands.argument("minLevel", IntegerArgumentType.integer(1,100)) + .then(Commands.argument("maxLevel", IntegerArgumentType.integer(1,100)) + .then(Commands.literal("handicap") + .then(Commands.argument("self", IntegerArgumentType.integer(-99,99)) + .then(Commands.argument("rival", IntegerArgumentType.integer(-99,99)) + .then(Commands.literal("showPreview") + .then(Commands.argument("show",BoolArgumentType.bool()) + .executes(c -> challengePlayer(c, IntegerArgumentType.getInteger(c, "minLevel"), IntegerArgumentType.getInteger(c, "maxLevel"), IntegerArgumentType.getInteger(c, "self"), IntegerArgumentType.getInteger(c, "rival"), BoolArgumentType.getBool(c, "show"))) ) ) ) ) ) ) - ) ) ); // Command called to accept challenges - LiteralArgumentBuilder acceptChallengeAndProperties = Commands.literal("acceptchallenge") + LiteralArgumentBuilder acceptChallengeAndProperties = Commands.literal("accept-challenge") .then(Commands.argument("id", StringArgumentType.string()).executes(c -> acceptChallenge(c, StringArgumentType.getString(c, "id")))); // Command called to deny challenges - LiteralArgumentBuilder rejectChallengeAndProperties = Commands.literal("rejectchallenge") + LiteralArgumentBuilder rejectChallengeAndProperties = Commands.literal("reject-challenge") .then(Commands.argument("id", StringArgumentType.string()).executes(c -> rejectChallenge(c, StringArgumentType.getString(c, "id")))); @@ -281,18 +269,23 @@ public static void register(CommandDispatcher dispatcher) { public static int challengePlayer(CommandContext c, int minLevel, int maxLevel, int handicapP1, int handicapP2, boolean preview) { try { ServerPlayer challengerPlayer = c.getSource().getPlayer(); - ServerPlayer challengedPlayer = c.getArgument("player", EntitySelector.class).findSinglePlayer(c.getSource()); + if (challengerPlayer == null){ + c.getSource().sendFailure(Component.literal("Cannot send challenge, because ChallengerPlayer is null!")); + return 0; + } - if (LAST_SENT_CHALLENGE.containsKey(challengerPlayer.getUUID())) { - if (System.currentTimeMillis() - LAST_SENT_CHALLENGE.get(challengerPlayer.getUUID()) < CHALLENGE_COOLDOWN) { + ServerPlayer challengedPlayer = c.getArgument("player", EntitySelector.class).findSinglePlayer(c.getSource()); + UUID challengerUUID = challengerPlayer.getUUID(); + if (LAST_SENT_CHALLENGE.containsKey(challengerUUID)) { + if (System.currentTimeMillis() - LAST_SENT_CHALLENGE.get(challengerUUID) < CHALLENGE_COOLDOWN) { c.getSource().sendFailure(Component.literal(String.format("You must wait at least %d second(s) before sending another challenge", (int)Math.ceil(CHALLENGE_COOLDOWN / 1000f)))); return 0; } } for (ChallengeRequest request : CHALLENGE_REQUESTS.values()) { - if (request.challengerPlayer.getUUID().equals(challengerPlayer.getUUID())) { - c.getSource().sendFailure(Component.literal(String.format("You already have a pending challenge to %s", request.challengedPlayer.getDisplayName().getString()))); + if (request.challengerPlayer().getUUID().equals(challengerUUID)) { + c.getSource().sendFailure(Component.literal(String.format("You already have a pending challenge to %s", request.challengedPlayer().getDisplayName().getString()))); return 0; } } @@ -302,19 +295,18 @@ public static int challengePlayer(CommandContext c, int minL c.getSource().sendFailure(Component.literal("Cannot send challenge while in-battle")); return 0; } - if (Cobblemon.INSTANCE.getStorage().getParty(challengerPlayer).occupied() == 0) { c.getSource().sendFailure(Component.literal("Cannot send challenge while you have no pokemon!")); return 0; } - float distance = challengedPlayer.distanceTo(challengerPlayer); if (USE_DISTANCE_RESTRICTION && (distance > MAX_DISTANCE || challengedPlayer.level() != challengerPlayer.level())) { - c.getSource().sendFailure(Component.literal(String.format("Target must be less than %d blocks away to initiate a challenge", (int)MAX_DISTANCE))); + c.getSource().sendFailure(Component.literal(String.format("Target must be less than %d blocks away to initiate a challenge", (int) MAX_DISTANCE))); return 0; } + if (challengerPlayer == challengedPlayer) { c.getSource().sendFailure(Component.literal("You may not challenge yourself")); return 0; @@ -327,18 +319,18 @@ public static int challengePlayer(CommandContext c, int minL } ChallengeRequest request = ChallengeUtil.createChallengeRequest(challengerPlayer, challengedPlayer, minLevel, maxLevel, handicapP1, handicapP2, preview); - CHALLENGE_REQUESTS.put(request.id, request); + CHALLENGE_REQUESTS.put(request.id(), request); String levelComponent = (minLevel == maxLevel) ? ChatFormatting.YELLOW + String.format("You have been challenged to a " + ChatFormatting.BOLD + "level %d Pokemon battle", maxLevel) : ChatFormatting.YELLOW + String.format("You have been challenged to a " + ChatFormatting.BOLD + "level %d - %d Pokemon battle", minLevel, maxLevel); String challengerComponent = ChatFormatting.YELLOW + " by " + challengerPlayer.getDisplayName().getString() + "!"; - String optionsComponent = request.preview() ? "" : ChatFormatting.RED + " [NoTeamPreview]"; - String handicapComponent = (handicapP1 == 0 && handicapP2 == 0) ? "" : ChatFormatting.BLUE + " [" + challengerPlayer.getDisplayName().getString() + " handicap of " + handicapP1 + "] [" + challengedPlayer.getDisplayName().getString() + " handicap of " + handicapP2 + "]"; + String optionsComponent = request.preview() ? "" : ChatFormatting.GOLD + " [NoTeamPreview]"; + String handicapComponent = (handicapP1 == 0 && handicapP2 == 0) ? "" : ChatFormatting.GREEN + " [" + challengerPlayer.getDisplayName().getString() + " handicap of " + handicapP1 + "] [" + challengedPlayer.getDisplayName().getString() + " handicap of " + handicapP2 + "]"; MutableComponent notificationComponent = Component.literal(levelComponent + challengerComponent + optionsComponent + handicapComponent); MutableComponent interactiveComponent = Component.literal("Click to accept or deny: "); - interactiveComponent.append(Component.literal(ChatFormatting.GREEN + "Battle!").setStyle(Style.EMPTY.withBold(true).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/acceptchallenge %s", request.id))))); + interactiveComponent.append(Component.literal(ChatFormatting.GREEN + "Battle!").setStyle(Style.EMPTY.withBold(true).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/accept-challenge %s", request.id()))))); interactiveComponent.append(Component.literal(" or ")); - interactiveComponent.append(Component.literal(ChatFormatting.RED + "Reject").setStyle(Style.EMPTY.withBold(true).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/rejectchallenge %s", request.id))))); + interactiveComponent.append(Component.literal(ChatFormatting.RED + "Reject").setStyle(Style.EMPTY.withBold(true).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/reject-challenge %s", request.id()))))); challengedPlayer.displayClientMessage(notificationComponent, false); challengedPlayer.displayClientMessage(interactiveComponent, false); challengerPlayer.displayClientMessage(Component.literal(ChatFormatting.YELLOW + String.format("Challenge has been sent to %s", challengedPlayer.getDisplayName().getString())), false); @@ -346,6 +338,7 @@ public static int challengePlayer(CommandContext c, int minL return Command.SINGLE_SUCCESS; } catch (Exception e) { c.getSource().sendFailure(Component.literal("An unexpected error has occurred: " + e.getMessage())); + //noinspection CallToPrintStackTrace e.printStackTrace(); return 0; } @@ -358,16 +351,17 @@ public static int rejectChallenge(CommandContext c, String c c.getSource().sendFailure(Component.literal("Challenge request is not valid")); return 0; } - CHALLENGE_REQUESTS.remove(request.id); - request.challengedPlayer.displayClientMessage(Component.literal(ChatFormatting.RED + "Challenge has been rejected"), false); + CHALLENGE_REQUESTS.remove(request.id()); + request.challengedPlayer().displayClientMessage(Component.literal(ChatFormatting.RED + "Challenge has been rejected"), false); - if (ChallengeUtil.isPlayerOnline(request.challengerPlayer)) { - request.challengerPlayer.displayClientMessage(Component.literal(ChatFormatting.RED + String.format("%s has rejected your challenge.", request.challengedPlayer.getDisplayName().getString())), false); + if (ChallengeUtil.isPlayerOnline(request.challengerPlayer())) { + request.challengerPlayer().displayClientMessage(Component.literal(ChatFormatting.RED + String.format("%s has rejected your challenge.", request.challengedPlayer().getDisplayName().getString())), false); } return Command.SINGLE_SUCCESS; } catch (Exception e) { c.getSource().sendFailure(Component.literal("An unexpected error has occurred: " + e.getMessage())); + //noinspection CallToPrintStackTrace e.printStackTrace(); return 0; } @@ -382,32 +376,32 @@ public static int acceptChallenge(CommandContext c, String c } BattleRegistry br = Cobblemon.INSTANCE.getBattleRegistry(); - if (br.getBattleByParticipatingPlayer(request.challengedPlayer) != null) { + if (br.getBattleByParticipatingPlayer(request.challengedPlayer()) != null) { c.getSource().sendFailure(Component.literal("Cannot accept challenge: you are already in a battle")); return 0; } - else if (br.getBattleByParticipatingPlayer(request.challengerPlayer) != null) { - c.getSource().sendFailure(Component.literal(String.format("Cannot accept challenge: %s is already in a battle", request.challengerPlayer.getDisplayName().getString()))); + else if (br.getBattleByParticipatingPlayer(request.challengerPlayer()) != null) { + c.getSource().sendFailure(Component.literal(String.format("Cannot accept challenge: %s is already in a battle", request.challengerPlayer().getDisplayName().getString()))); return 0; } - if (Cobblemon.INSTANCE.getStorage().getParty(request.challengedPlayer).occupied() == 0) { + if (Cobblemon.INSTANCE.getStorage().getParty(request.challengedPlayer()).occupied() == 0) { c.getSource().sendFailure(Component.literal("Cannot accept challenge: You have no pokemon!")); return 0; } - if (Cobblemon.INSTANCE.getStorage().getParty(request.challengerPlayer).occupied() == 0) { - c.getSource().sendFailure(Component.literal(String.format("Cannot accept challenge: %s has no pokemon... somehow!", request.challengerPlayer.getDisplayName().getString()))); + if (Cobblemon.INSTANCE.getStorage().getParty(request.challengerPlayer()).occupied() == 0) { + c.getSource().sendFailure(Component.literal(String.format("Cannot accept challenge: %s has no pokemon... somehow!", request.challengerPlayer().getDisplayName().getString()))); return 0; } - float distance = request.challengerPlayer.distanceTo(request.challengedPlayer); - if (USE_DISTANCE_RESTRICTION && (distance > MAX_DISTANCE || request.challengerPlayer.level() != request.challengedPlayer.level())) { + float distance = request.challengerPlayer().distanceTo(request.challengedPlayer()); + if (USE_DISTANCE_RESTRICTION && (distance > MAX_DISTANCE || request.challengerPlayer().level() != request.challengedPlayer().level())) { c.getSource().sendFailure(Component.literal(String.format("Target must be less than %d blocks away to accept a challenge", (int)MAX_DISTANCE))); return 0; } ChallengeRequest challengeRequestRemoved = CHALLENGE_REQUESTS.remove(challengeId); - ServerPlayer challengerPlayer = request.challengerPlayer; + ServerPlayer challengerPlayer = request.challengerPlayer(); if (!ChallengeUtil.isPlayerOnline(challengerPlayer)) { c.getSource().sendFailure(Component.literal(String.format("%s is no longer online", challengerPlayer.getDisplayName().getString()))); @@ -417,6 +411,7 @@ else if (br.getBattleByParticipatingPlayer(request.challengerPlayer) != null) { return Command.SINGLE_SUCCESS; } catch (Exception exc) { c.getSource().sendFailure(Component.literal("Unexpected exception when accepting challenge: " + exc.getMessage())); + //noinspection CallToPrintStackTrace exc.printStackTrace(); return 1; } diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfig.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfig.java index 62ba39a..03189c6 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfig.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfig.java @@ -10,6 +10,7 @@ public class ChallengeConfig { public static int MAX_CHALLENGE_DISTANCE; public static int DEFAULT_CHALLENGE_LEVEL; public static int DEFAULT_HANDICAP; + public static Boolean DEFAULT_SHOW_PREVIEW; public static int REQUEST_EXPIRATION_MILLIS; public static int CHALLENGE_COOLDOWN_MILLIS; @@ -25,6 +26,7 @@ private static void createConfigs() { configs.addKeyValuePair(new Pair<>("maxChallengeDistance", 50)); configs.addKeyValuePair(new Pair<>("defaultChallengeLevel", 50)); configs.addKeyValuePair(new Pair<>("defaultHandicap", 0)); + configs.addKeyValuePair(new Pair<>("defaultShowPreview", true)); configs.addKeyValuePair(new Pair<>("challengeExpirationTime", 60000)); configs.addKeyValuePair(new Pair<>("challengeCooldownTime", 5000)); } @@ -34,6 +36,7 @@ private static void assignConfigs() { CHALLENGE_DISTANCE_RESTRICTION = CONFIG.getOrDefault("challengeDistanceRestriction", true); DEFAULT_CHALLENGE_LEVEL = CONFIG.getOrDefault("defaultChallengeLevel", 50); DEFAULT_HANDICAP = CONFIG.getOrDefault("defaultHandicap", 0); + DEFAULT_SHOW_PREVIEW = CONFIG.getOrDefault("defaultShowPreview", true); MAX_CHALLENGE_DISTANCE = CONFIG.getOrDefault("maxChallengeDistance", 50); REQUEST_EXPIRATION_MILLIS = CONFIG.getOrDefault("challengeExpirationTime", 60000); } diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfigProvider.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfigProvider.java index cd45669..3ab78e3 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfigProvider.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/config/ChallengeConfigProvider.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; + public class ChallengeConfigProvider implements SimpleConfig.DefaultConfig { private String configContents = ""; diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/event/ChallengeEventHandler.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/event/ChallengeEventHandler.java index cf8db7e..7388151 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/event/ChallengeEventHandler.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/event/ChallengeEventHandler.java @@ -1,5 +1,17 @@ package com.turtlehoarder.cobblemonchallenge.event; +import com.turtlehoarder.cobblemonchallenge.CobblemonChallenge; +import com.turtlehoarder.cobblemonchallenge.api.ChallengeRequest; +import com.turtlehoarder.cobblemonchallenge.api.LeadPokemonSelection; +import com.turtlehoarder.cobblemonchallenge.api.storage.FakePokemonStore; +import com.turtlehoarder.cobblemonchallenge.api.storage.party.FakePartyPosition; +import com.turtlehoarder.cobblemonchallenge.api.storage.party.FakePlayerPartyStore; +import com.turtlehoarder.cobblemonchallenge.battle.ChallengeBattleBuilder; +import com.turtlehoarder.cobblemonchallenge.command.ChallengeCommand; +import com.turtlehoarder.cobblemonchallenge.config.ChallengeConfig; +import com.turtlehoarder.cobblemonchallenge.gui.LeadPokemonSelectionSession; +import com.turtlehoarder.cobblemonchallenge.util.ChallengeUtil; + import com.cobblemon.mod.common.Cobblemon; import com.cobblemon.mod.common.CobblemonNetwork; import com.cobblemon.mod.common.api.Priority; @@ -9,16 +21,7 @@ import com.cobblemon.mod.common.api.storage.*; import com.cobblemon.mod.common.entity.pokemon.PokemonEntity; import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket; -import com.turtlehoarder.cobblemonchallenge.CobblemonChallenge; -import com.turtlehoarder.cobblemonchallenge.battle.ChallengeBattleBuilder; -import com.turtlehoarder.cobblemonchallenge.command.ChallengeCommand; -import com.turtlehoarder.cobblemonchallenge.config.ChallengeConfig; -import com.turtlehoarder.cobblemonchallenge.gui.LeadPokemonSelectionSession; -import com.turtlehoarder.cobblemonchallenge.util.ChallengeUtil; -import com.turtlehoarder.cobblemonchallenge.util.FakeStore; -import com.turtlehoarder.cobblemonchallenge.util.FakeStorePosition; -import kotlin.Unit; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; @@ -30,6 +33,7 @@ import net.minecraft.world.entity.Entity; import java.util.*; +import kotlin.Unit; public class ChallengeEventHandler { @@ -37,26 +41,17 @@ public static void registerEvents() { registerPostVictoryEvent(); registerChallengeLootPrevention(); registerCobblemonSavePrevention(); - ServerEntityEvents.ENTITY_LOAD.register((entity, server) -> { - checkSpawn(entity); - }); - ServerPlayConnectionEvents.DISCONNECT.register((event, server) -> { - onPlayerLoggedOut(event.getPlayer()); - }); - - ServerLifecycleEvents.SERVER_STOPPING.register((server) -> { - onServerShutdown(); - }); - + ServerEntityEvents.ENTITY_LOAD.register((entity, server) -> checkSpawn(entity)); + ServerPlayConnectionEvents.DISCONNECT.register((event, server) -> onPlayerLoggedOut(event.getPlayer())); + ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onServerShutdown()); ServerTickEvents.END_SERVER_TICK.register(ChallengeEventHandler::onServerTick); - } /* Since this plugin uses cloned pokemon in its battles, there will be a *cloned* pokemon left behind after the battle is complete. These events ensure that these cloned entities are tracked and removed when a battle ends via Victory, disconnect, or server shutdown */ - public static boolean registerPostVictoryEvent() { + public static void registerPostVictoryEvent() { CobblemonEvents.BATTLE_VICTORY.subscribe(Priority.NORMAL, (battleVictoryEvent) -> { CobblemonChallenge.LOGGER.debug("Battle victory!"); UUID battleId = battleVictoryEvent.getBattle().getBattleId(); @@ -103,7 +98,6 @@ public static boolean registerPostVictoryEvent() { } return Unit.INSTANCE; }); - return true; } // Prevent Challenge-mons from being saved to the world to prevent odd scenarios where duplicates can be spawned and re-caught @@ -162,22 +156,15 @@ public static void checkSpawn(Entity entity) { CobblemonChallenge.LOGGER.debug(String.format("Entity Joined already in battle: %s | Battle id %s", entity.getDisplayName().getString(), pokemonEntity.getBattleId())); ChallengeBattleBuilder.clonedPokemonList.add(pokemonEntity); // Trick Cobblemon into thinking the clones are *not* wild pokemon. This will prevent duplicates being caught if something unexpected happens to the battle, like /stopbattle or a server crash - UUID foundplayerUUID = null; PokemonBattle pb = ChallengeUtil.getAssociatedBattle(pokemonEntity); if (pb != null) { - foundplayerUUID = ChallengeUtil.getOwnerUuidOfClonedPokemon(pb, pokemonEntity); - } - if (pb != null) { + UUID foundplayerUUID = ChallengeUtil.getOwnerUuidOfClonedPokemon(pb, pokemonEntity); UUID playerUUID = (foundplayerUUID != null ? foundplayerUUID : new UUID(0,0)); - FakeStore fakeStore = new FakeStore(playerUUID); - // World's worst casting. Don't do this at home. - PokemonStore fakePartyStore = (PokemonStore)(PokemonStore) fakeStore; - pokemonEntity.getPokemon().getStoreCoordinates().set(new StoreCoordinates<>(fakePartyStore, new FakeStorePosition())); + FakePlayerPartyStore fakePlayerStore = new FakePlayerPartyStore(playerUUID); + PokemonStore fakePokemonStore = new FakePokemonStore(fakePlayerStore,playerUUID); + pokemonEntity.getPokemon().getStoreCoordinates().set(new StoreCoordinates<>(fakePokemonStore, new FakePartyPosition())); pokemonEntity.getBusyLocks().add("Cloned_Pokemon"); // Busy lock prevents others from interacting with cloned pokemon } - - - } } } @@ -186,7 +173,7 @@ public static void onServerShutdown() { CobblemonChallenge.LOGGER.debug("Performing Server Shutdown tasks for Cobblemon Challenge"); if (!ChallengeBattleBuilder.clonedPokemonList.isEmpty()) { CobblemonChallenge.LOGGER.debug(String.format("Cloned pokemon (%d) from challenges detected. Removing all before server shuts down", ChallengeBattleBuilder.clonedPokemonList.size())); - ArrayList clonedPokemonCopyList = new ArrayList(ChallengeBattleBuilder.clonedPokemonList); // Create a copy since other list may be altered by despawn events + ArrayList clonedPokemonCopyList = new ArrayList<>(ChallengeBattleBuilder.clonedPokemonList); // Create a copy since other list may be altered by despawn events clonedPokemonCopyList.forEach(pokemonEntity -> pokemonEntity.remove(Entity.RemovalReason.DISCARDED)); clonedPokemonCopyList.clear(); } @@ -197,10 +184,10 @@ public static void onServerTick(MinecraftServer server) { int tickCount = server.getTickCount(); if (tickCount % 20 == 0) { long nowTime = System.currentTimeMillis(); - Iterator> requestIterator = ChallengeCommand.CHALLENGE_REQUESTS.entrySet().iterator(); + Iterator> requestIterator = ChallengeCommand.CHALLENGE_REQUESTS.entrySet().iterator(); while (requestIterator.hasNext()) { - Map.Entry requestMap = requestIterator.next(); - ChallengeCommand.ChallengeRequest request = requestMap.getValue(); + Map.Entry requestMap = requestIterator.next(); + ChallengeRequest request = requestMap.getValue(); if (request.createdTime() + ChallengeConfig.REQUEST_EXPIRATION_MILLIS < nowTime) { if (ChallengeUtil.isPlayerOnline(request.challengedPlayer())) { request.challengedPlayer().displayClientMessage(Component.literal(ChatFormatting.RED + String.format("Challenge from %s has expired", request.challengerPlayer().getDisplayName().getString())), false); @@ -211,7 +198,7 @@ public static void onServerTick(MinecraftServer server) { requestIterator.remove(); } } - Iterator> selectionIterator = ChallengeCommand.ACTIVE_SELECTIONS.entrySet().iterator(); + Iterator> selectionIterator = ChallengeCommand.ACTIVE_SELECTIONS.entrySet().iterator(); while (selectionIterator.hasNext()) { LeadPokemonSelectionSession selectionSession = selectionIterator.next().getValue().selectionWrapper(); selectionSession.doTick(); diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenu.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenu.java index 490a915..98d2d40 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenu.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenu.java @@ -6,6 +6,7 @@ import net.minecraft.world.inventory.ChestMenu; import net.minecraft.world.inventory.ClickType; import net.minecraft.world.inventory.MenuType; + import org.jetbrains.annotations.NotNull; public class LeadPokemonMenu extends ChestMenu { diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenuProvider.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenuProvider.java index faf1348..e3a58b9 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenuProvider.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonMenuProvider.java @@ -1,15 +1,16 @@ package com.turtlehoarder.cobblemonchallenge.gui; +import com.turtlehoarder.cobblemonchallenge.api.ChallengeRequest; +import com.turtlehoarder.cobblemonchallenge.battle.ChallengeFormat; +import com.turtlehoarder.cobblemonchallenge.util.ChallengeUtil; + import com.cobblemon.mod.common.Cobblemon; import com.cobblemon.mod.common.CobblemonItems; import com.cobblemon.mod.common.api.storage.party.PartyStore; import com.cobblemon.mod.common.battles.pokemon.BattlePokemon; import com.cobblemon.mod.common.item.PokemonItem; import com.cobblemon.mod.common.pokemon.Pokemon; -import com.turtlehoarder.cobblemonchallenge.CobblemonChallenge; -import com.turtlehoarder.cobblemonchallenge.battle.ChallengeFormat; -import com.turtlehoarder.cobblemonchallenge.command.ChallengeCommand; -import com.turtlehoarder.cobblemonchallenge.util.ChallengeUtil; + import net.minecraft.ChatFormatting; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; @@ -22,6 +23,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Blocks; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,9 +45,9 @@ private enum MenuState {WAITING_FOR_BOTH, WAITING_FOR_RIVAL, WAITING_FOR_PLAYER} private LeadPokemonMenu openedMenu; public List selectedSlots = new ArrayList(); - private ChallengeCommand.ChallengeRequest request; + private ChallengeRequest request; - public LeadPokemonMenuProvider(LeadPokemonSelectionSession wrapper, ServerPlayer selector, ServerPlayer rivalPlayer, ChallengeCommand.ChallengeRequest request) { + public LeadPokemonMenuProvider(LeadPokemonSelectionSession wrapper, ServerPlayer selector, ServerPlayer rivalPlayer, ChallengeRequest request) { this.selector = selector; this.rival = rivalPlayer; this.selectionSession = wrapper; diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonSelectionSession.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonSelectionSession.java index 59412df..326333e 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonSelectionSession.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/gui/LeadPokemonSelectionSession.java @@ -1,11 +1,13 @@ package com.turtlehoarder.cobblemonchallenge.gui; -import com.cobblemon.mod.common.battles.BattleFormat; import com.turtlehoarder.cobblemonchallenge.CobblemonChallenge; +import com.turtlehoarder.cobblemonchallenge.api.ChallengeRequest; import com.turtlehoarder.cobblemonchallenge.battle.ChallengeBattleBuilder; import com.turtlehoarder.cobblemonchallenge.battle.ChallengeBuilderException; -import com.turtlehoarder.cobblemonchallenge.command.ChallengeCommand; import com.turtlehoarder.cobblemonchallenge.util.ChallengeUtil; + +import com.cobblemon.mod.common.battles.BattleFormat; + import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; @@ -16,7 +18,7 @@ public class LeadPokemonSelectionSession { private final LeadPokemonMenuProvider challengerMenuProvider; private final LeadPokemonMenuProvider challengedMenuProvider; - private final ChallengeCommand.ChallengeRequest originRequest; + private final ChallengeRequest originRequest; private final UUID uuid; public long creationTime; private int pokemonToSelect = 1; @@ -28,7 +30,7 @@ public class LeadPokemonSelectionSession { public static int LEAD_TIMEOUT_MILLIS = 90000; - public LeadPokemonSelectionSession(UUID uuid, long creationTime, ChallengeCommand.ChallengeRequest request) { + public LeadPokemonSelectionSession(UUID uuid, long creationTime, ChallengeRequest request) { this.originRequest = request; this.uuid = uuid; this.creationTime = creationTime; diff --git a/src/main/java/com/turtlehoarder/cobblemonchallenge/util/ChallengeUtil.java b/src/main/java/com/turtlehoarder/cobblemonchallenge/util/ChallengeUtil.java index f193958..1fb8075 100644 --- a/src/main/java/com/turtlehoarder/cobblemonchallenge/util/ChallengeUtil.java +++ b/src/main/java/com/turtlehoarder/cobblemonchallenge/util/ChallengeUtil.java @@ -7,7 +7,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity; import com.cobblemon.mod.common.pokemon.Pokemon; import com.cobblemon.mod.common.util.LocalizationUtilsKt; -import com.turtlehoarder.cobblemonchallenge.CobblemonChallenge; +import com.turtlehoarder.cobblemonchallenge.api.ChallengeRequest; import com.turtlehoarder.cobblemonchallenge.battle.ChallengeBattleBuilder; import com.turtlehoarder.cobblemonchallenge.battle.ChallengeFormat; import com.turtlehoarder.cobblemonchallenge.command.ChallengeCommand; @@ -57,10 +57,9 @@ public static boolean isPlayerOnline(ServerPlayer player) { return player.getServer().getPlayerList().getPlayer(player.getUUID()) != null; } - public static ChallengeCommand.ChallengeRequest createChallengeRequest(ServerPlayer challengerPlayer, ServerPlayer challengedPlayer, int minLevel, int maxLevel, int handicapP1, int handicapP2, boolean preview) { + public static ChallengeRequest createChallengeRequest(ServerPlayer challengerPlayer, ServerPlayer challengedPlayer, int minLevel, int maxLevel, int handicapP1, int handicapP2, boolean preview) { String key = UUID.randomUUID().toString().replaceAll("-", ""); - ChallengeCommand.ChallengeRequest newRequest = new ChallengeCommand.ChallengeRequest(key, challengerPlayer, challengedPlayer, minLevel, maxLevel, handicapP1, handicapP2, preview, System.currentTimeMillis()); - return newRequest; + return new ChallengeRequest(key, challengerPlayer, challengedPlayer, minLevel, maxLevel, handicapP1, handicapP2, preview, System.currentTimeMillis()); } public static ItemLike getDisplayBlockForPokemon(Pokemon pokemon) { diff --git a/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/FakePokemonStore.kt b/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/FakePokemonStore.kt new file mode 100644 index 0000000..48523a4 --- /dev/null +++ b/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/FakePokemonStore.kt @@ -0,0 +1,100 @@ +package com.turtlehoarder.cobblemonchallenge.api.storage + +import com.turtlehoarder.cobblemonchallenge.api.storage.party.FakePlayerPartyStore + +import com.cobblemon.mod.common.api.reactive.Observable +import com.cobblemon.mod.common.api.storage.PokemonStore +import com.cobblemon.mod.common.api.storage.StoreCoordinates +import com.cobblemon.mod.common.api.storage.StorePosition +import com.cobblemon.mod.common.api.storage.factory.PokemonStoreFactory +import com.cobblemon.mod.common.pokemon.Pokemon +import com.google.gson.JsonObject +import net.minecraft.server.level.ServerPlayer +import net.minecraft.nbt.CompoundTag +import java.util.* + +class FakePokemonStore( + private val playerStore : FakePlayerPartyStore, + /** The UUID of the store. The exact uniqueness requirements depend on the method used for saving. */ + override val uuid: UUID = playerStore.playerUUID +): PokemonStore() { + + /** Gets the [Pokemon] at the given position. */ + override operator fun get(position: StorePosition): Pokemon?{ + return null + } + + /** Gets the first empty position that a [Pokemon] might be put. */ + override fun getFirstAvailablePosition(): StorePosition? { + return null + } + + /** Gets an iterable of all [ServerPlayer]s that should be notified of any changes to the Pokémon in this store. */ + override fun getObservingPlayers(): Iterable { + return emptyList() + } + + /** Sends the contents of this store to a player as if they've never seen it before. This initializes the store then sends each contained Pokémon. */ + override fun sendTo(player: ServerPlayer) { } + + /** + * Runs initialization logic for this store, knowing that it has just been constructed in a [PokemonStoreFactory]. + * + * The minimum of what this function should do is iterate over all the Pokémon in this store and set their store + * coordinates. + * + * If this does not get called, or it does not do its job properly, serious de-sync issues may follow. + */ + override fun initialize() { } + + override fun iterator(): Iterator { + TODO("Not yet implemented") + } + + /** + * Sets the given position with the given [Pokemon], which can be null. This is for internal use only because + * other, more public methods will additionally send updates to the client, and for logical reasons this means + * there must be an internal and external set method. + */ + override fun setAtPosition(position: StorePosition, pokemon: Pokemon?) { + + } + + /** Returns true if the given position is pointing to a legitimate location in this store. */ + override fun isValidPosition(position: StorePosition): Boolean { + return true + } + + override fun saveToNBT(nbt: CompoundTag): CompoundTag { + return CompoundTag() + } + + override fun loadFromNBT(nbt: CompoundTag): PokemonStore { + return this + } + + override fun saveToJSON(json: JsonObject): JsonObject { + return JsonObject() + } + + override fun loadFromJSON(json: JsonObject): PokemonStore { + return this + } + + override fun savePositionToNBT(position: StorePosition, nbt: CompoundTag) { + + } + + override fun loadPositionFromNBT(nbt: CompoundTag): StoreCoordinates { + TODO("Not yet implemented") + } + + /** + * Returns an [Observable] that emits Unit whenever there is a change to this store. This includes any save-worthy + * change to a [Pokemon] contained in the store. You can access an [Observable] in each [Pokemon] that emits Unit for + * each change, accessed by [Pokemon.getChangeObservable]. + */ + override fun getAnyChangeObservable(): Observable { + return Observable.just(Unit) // @Eric: I think this should work but... I'll defer to you lol ;) - David + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/party/FakePartyPosition.kt b/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/party/FakePartyPosition.kt new file mode 100644 index 0000000..b42e29e --- /dev/null +++ b/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/party/FakePartyPosition.kt @@ -0,0 +1,17 @@ +package com.turtlehoarder.cobblemonchallenge.api.storage.party + +import com.cobblemon.mod.common.api.storage.StorePosition +import com.cobblemon.mod.common.api.storage.party.PartyPosition +import com.cobblemon.mod.common.net.IntSize +import com.cobblemon.mod.common.util.readSizedInt +import com.cobblemon.mod.common.util.writeSizedInt +import net.minecraft.network.FriendlyByteBuf + +class FakePartyPosition(val slot: Int = 0) : StorePosition { + companion object { + fun FriendlyByteBuf.writePartyPosition(position: FakePartyPosition) { + writeSizedInt(IntSize.U_BYTE, position.slot) + } + fun FriendlyByteBuf.readPartyPosition() = FakePartyPosition(readSizedInt(IntSize.U_BYTE)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/party/FakePlayerPartyStore.kt b/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/party/FakePlayerPartyStore.kt new file mode 100644 index 0000000..b85397c --- /dev/null +++ b/src/main/kotlin/com/turtlehoarder/cobblemonchallenge/api/storage/party/FakePlayerPartyStore.kt @@ -0,0 +1,15 @@ +package com.turtlehoarder.cobblemonchallenge.api.storage.party + +import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore +import com.cobblemon.mod.common.pokemon.Pokemon +import java.util.* + +class FakePlayerPartyStore( + private val fakeUUID: UUID = UUID(0, 0) +) : PlayerPartyStore(fakeUUID, fakeUUID) { + + // override function to serve the same purpose as the previous FakeStore + override fun add(pokemon: Pokemon): Boolean { + return true + } +} \ No newline at end of file