diff --git a/plugin/src/main/java/wand555/github/io/challenges/ChallengeManager.java b/plugin/src/main/java/wand555/github/io/challenges/ChallengeManager.java index e69b23e..384756c 100644 --- a/plugin/src/main/java/wand555/github/io/challenges/ChallengeManager.java +++ b/plugin/src/main/java/wand555/github/io/challenges/ChallengeManager.java @@ -13,6 +13,7 @@ public class ChallengeManager { + private @NotNull Challenges plugin; private @NotNull List rules; private @NotNull List goals; @@ -20,8 +21,8 @@ public class ChallengeManager { private GameState gameState; - public ChallengeManager() { - + public ChallengeManager(@NotNull Challenges plugin) { + this.plugin = plugin; } public void start() { @@ -32,6 +33,7 @@ public void start() { throw new RuntimeException("No goals specified!"); } gameState = GameState.RUNNING; + Challenges.getPlugin(Challenges.class).getLogger().info("starting"); } diff --git a/plugin/src/main/java/wand555/github/io/challenges/Challenges.java b/plugin/src/main/java/wand555/github/io/challenges/Challenges.java index 3985b02..8f36058 100644 --- a/plugin/src/main/java/wand555/github/io/challenges/Challenges.java +++ b/plugin/src/main/java/wand555/github/io/challenges/Challenges.java @@ -42,6 +42,7 @@ public void onEnable() { * #8846f2 Only [Challenges] * #c9526c Only [Punishment] * #ffc54d Only [Rules] + * #3abeaa Only [Goals] * * #fceaff default text * #64baaa highlight in text @@ -49,27 +50,6 @@ public void onEnable() { if(!getDataFolder().exists()) { boolean created = getDataFolder().mkdir(); } - - - - // Plugin startup logic - getCommand("test").setExecutor(this); - getCommand("load").setExecutor(this); - - Expansion.Builder builder = Expansion.builder("challenges"); - builder.globalPlaceholder("player", (argumentQueue, context) -> { - String playerName = argumentQueue.popOr("argument missing").value(); - return Tag.selfClosingInserting(Component.text(playerName)); - }); - builder.audiencePlaceholder("player2", (audience, queue, ctx) -> { - return Tag.selfClosingInserting(Component.text(((Player) audience).getName())); - }); - - Expansion expansion = builder.build(); - if(!expansion.registered()) { - expansion.register(); - } - } @Override @@ -80,12 +60,14 @@ public void onDisable() { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if(command.getName().equalsIgnoreCase("load")) { + File file = new File(getDataFolder(), "data.json"); if(!file.exists()) { } try { ChallengeManager challengeManager = FileManager.readFromFile(file, this); + challengeManager.start(); } catch (LoadValidationException e) { throw new RuntimeException(e); } @@ -119,10 +101,10 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command sender.sendMessage("ABC"); try { - ChallengeManager challengeManager = new ChallengeManager(); + ChallengeManager challengeManager = new ChallengeManager(this); JsonNode schemaRoot = new ObjectMapper().readTree(Challenges.class.getResource("/test-output-schema.json")); - MobGoal mobGoal = new MobGoal(new Context(this, new ResourceBundleContext(bundle, null), schemaRoot, challengeManager), new HashMap<>(Map.of(EntityType.PIG, new Collect(2)))); + MobGoal mobGoal = new MobGoal(new Context(this, new ResourceBundleContext(bundle, null, null), schemaRoot, challengeManager), new HashMap<>(Map.of(EntityType.PIG, new Collect(2)))); Player player = (Player) sender; mobGoal.openCollectedInv(player); } catch (IOException e) { diff --git a/plugin/src/main/java/wand555/github/io/challenges/ComponentInterpolator.java b/plugin/src/main/java/wand555/github/io/challenges/ComponentInterpolator.java index 66fcea7..1ea89cb 100644 --- a/plugin/src/main/java/wand555/github/io/challenges/ComponentInterpolator.java +++ b/plugin/src/main/java/wand555/github/io/challenges/ComponentInterpolator.java @@ -5,6 +5,9 @@ import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import wand555.github.io.challenges.utils.ResourceBundleHelper; import javax.validation.constraints.NotNull; import java.util.*; @@ -12,17 +15,20 @@ public class ComponentInterpolator { + public static Component interpolate(@NotNull Challenges plugin, @NotNull ResourceBundle bundle, @NotNull String key) { + return interpolate(plugin, bundle, key, Map.of()); + } @NotNull public static Component interpolate(@NotNull Challenges plugin, @NotNull ResourceBundle bundle, @NotNull String key, @NotNull Map placeholders) { Objects.requireNonNull(bundle); Objects.requireNonNull(key); Objects.requireNonNull(placeholders); - String rawText = getFromBundle(plugin, bundle, key); + String rawText = ResourceBundleHelper.getFromBundle(plugin, bundle, key); - String prefixColor = getFromBundle(plugin, bundle, "chat.color.prefix"); - String defaultColor = getFromBundle(plugin, bundle, "chat.color.default"); - String highlightColor = getFromBundle(plugin, bundle, "chat.color.highlight"); + String prefixColor = ResourceBundleHelper.getFromBundle(plugin, bundle, "chat.color.prefix"); + String defaultColor = ResourceBundleHelper.getFromBundle(plugin, bundle, "chat.color.default"); + String highlightColor = ResourceBundleHelper.getFromBundle(plugin, bundle, "chat.color.highlight"); TagResolver.Single[] mappedPlaceholders = mapPlaceHolders(placeholders, highlightColor); @@ -41,7 +47,7 @@ private static Component getBaseName(@NotNull Challenges plugin, @NotNull Resour return Component.empty(); } String baseName = split[0]; - String baseDisplayName = getFromBundle(plugin, bundle, String.format("%s.name", baseName)); + String baseDisplayName = ResourceBundleHelper.getFromBundle(plugin, bundle, String.format("%s.name", baseName)); return Component.text(String.format("[%s]: ", baseDisplayName), TextColor.fromHexString(prefixColor)); } @@ -54,20 +60,23 @@ private static TagResolver.Single[] mapPlaceHolders(@NotNull Map> Component translate(E enumToTranslate) { + String prefix = null; + if(enumToTranslate instanceof Material material) { + if(material.isBlock()) { + prefix = "block"; + } + else if (material.isItem()) { + prefix = "item"; + } + } + else if(enumToTranslate instanceof EntityType) { + prefix = "entity"; + } + if(prefix == null) { + throw new RuntimeException(String.format("Failed to map enum %s to translatable component!", enumToTranslate)); } - return ""; + return Component.translatable(String.format("%s.minecraft.%s", prefix, enumToTranslate.toString().toLowerCase())); } } diff --git a/plugin/src/main/java/wand555/github/io/challenges/Context.java b/plugin/src/main/java/wand555/github/io/challenges/Context.java index 8ca5ddf..ae38986 100644 --- a/plugin/src/main/java/wand555/github/io/challenges/Context.java +++ b/plugin/src/main/java/wand555/github/io/challenges/Context.java @@ -26,6 +26,11 @@ public Builder withRuleResourceBundle(ResourceBundle ruleResourceBundle) { return this; } + public Builder withGoalResourceBundle(ResourceBundle goalResourceBundle) { + resourceBundleContextBuilder.withGoalResourceBundle(goalResourceBundle); + return this; + } + public Builder withPunishmentResourceBundle(ResourceBundle punishmentResourceBundle) { resourceBundleContextBuilder.withPunishmentResourceBundle(punishmentResourceBundle); return this; diff --git a/plugin/src/main/java/wand555/github/io/challenges/FileManager.java b/plugin/src/main/java/wand555/github/io/challenges/FileManager.java index eb89e31..baf7389 100644 --- a/plugin/src/main/java/wand555/github/io/challenges/FileManager.java +++ b/plugin/src/main/java/wand555/github/io/challenges/FileManager.java @@ -61,9 +61,10 @@ public static ChallengeManager readFromFile(File file, Challenges plugin) throws Context context = new Context.Builder() .withPlugin(plugin) .withRuleResourceBundle(ResourceBundle.getBundle("rules", Locale.US, UTF8ResourceBundleControl.get())) + .withGoalResourceBundle(ResourceBundle.getBundle("goals", Locale.US, UTF8ResourceBundleControl.get())) .withPunishmentResourceBundle(ResourceBundle.getBundle("punishments", Locale.US, UTF8ResourceBundleControl.get())) .withSchemaRoot(schemaRoot) - .withChallengeManager(new ChallengeManager()) + .withChallengeManager(new ChallengeManager(plugin)) .build(); ModelMapper.map2ModelClasses(context, testOutputSchema); diff --git a/plugin/src/main/java/wand555/github/io/challenges/ResourceBundleContext.java b/plugin/src/main/java/wand555/github/io/challenges/ResourceBundleContext.java index e5fafad..0d7fb5d 100644 --- a/plugin/src/main/java/wand555/github/io/challenges/ResourceBundleContext.java +++ b/plugin/src/main/java/wand555/github/io/challenges/ResourceBundleContext.java @@ -4,10 +4,10 @@ import java.util.ResourceBundle; -public record ResourceBundleContext(ResourceBundle ruleResourceBundle, ResourceBundle punishmentResourceBundle) { +public record ResourceBundleContext(ResourceBundle ruleResourceBundle, ResourceBundle goalResourceBundle, ResourceBundle punishmentResourceBundle) { public static final class Builder { - private ResourceBundle ruleResourceBundle, punishmentResourceBundle; + private ResourceBundle ruleResourceBundle, goalResourceBundle, punishmentResourceBundle; public Builder() {} @@ -16,13 +16,18 @@ public Builder withRuleResourceBundle(ResourceBundle ruleResourceBundle) { return this; } + public Builder withGoalResourceBundle(ResourceBundle goalResourceBundle) { + this.goalResourceBundle = goalResourceBundle; + return this; + } + public Builder withPunishmentResourceBundle(ResourceBundle punishmentResourceBundle) { this.punishmentResourceBundle = punishmentResourceBundle; return this; } public ResourceBundleContext build() { - return new ResourceBundleContext(ruleResourceBundle, punishmentResourceBundle); + return new ResourceBundleContext(ruleResourceBundle, goalResourceBundle, punishmentResourceBundle); } } diff --git a/plugin/src/main/java/wand555/github/io/challenges/exceptions/MissingSoundException.java b/plugin/src/main/java/wand555/github/io/challenges/exceptions/MissingSoundException.java new file mode 100644 index 0000000..db237d1 --- /dev/null +++ b/plugin/src/main/java/wand555/github/io/challenges/exceptions/MissingSoundException.java @@ -0,0 +1,4 @@ +package wand555.github.io.challenges.exceptions; + +public class MissingSoundException extends Exception { +} diff --git a/plugin/src/main/java/wand555/github/io/challenges/goals/MobGoal.java b/plugin/src/main/java/wand555/github/io/challenges/goals/MobGoal.java index 9540e35..746b19f 100644 --- a/plugin/src/main/java/wand555/github/io/challenges/goals/MobGoal.java +++ b/plugin/src/main/java/wand555/github/io/challenges/goals/MobGoal.java @@ -1,5 +1,6 @@ package wand555.github.io.challenges.goals; +import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -7,6 +8,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDeathEvent; import wand555.github.io.challenges.Challenges; +import wand555.github.io.challenges.ComponentInterpolator; import wand555.github.io.challenges.Context; import wand555.github.io.challenges.Storable; import wand555.github.io.challenges.generated.CollectableEntryConfig; @@ -14,6 +16,7 @@ import wand555.github.io.challenges.generated.MobGoalConfig; import wand555.github.io.challenges.inventory.CollectedInventory; import wand555.github.io.challenges.inventory.CollectedItemStack; +import wand555.github.io.challenges.utils.ActionHelper; import java.util.Map; import java.util.logging.Level; @@ -31,10 +34,6 @@ public MobGoal(Context context, boolean complete, Map toKil super(context, complete); this.toKill = toKill; this.collectedInventory = new CollectedInventory(context.plugin()); - for(int i=0; i<100; i++) { - collectedInventory.addCollectedItemStack(new CollectedItemStack(Material.STONE, i+"", i)); - } - context.plugin().getServer().getPluginManager().registerEvents(this, context.plugin()); } @@ -49,7 +48,18 @@ public Map getToKill() { @Override public void onComplete() { setComplete(true); - // TODO: display messages + + Component toSend = ComponentInterpolator.interpolate( + context.plugin(), + context.resourceBundleContext().goalResourceBundle(), + "mobgoal.all.reached.message" + ); + ActionHelper.sendAndPlaySound( + context.plugin(), + toSend, + context.resourceBundleContext().goalResourceBundle(), + "mobgoal.all.reached.sound" + ); notifyManager(); } @@ -74,10 +84,44 @@ public void onMobDeath(EntityDeathEvent event) { } private void newEntityKilled(Player killer, EntityType killed) { - getToKill().computeIfPresent(killed, (entityType, collect) -> { + Collect updatedCollect = getToKill().computeIfPresent(killed, (entityType, collect) -> { collect.setCurrentAmount(collect.getCurrentAmount()+1); return collect; }); + Component toSend = null; + String soundInBundleKey = null; + if(updatedCollect.isComplete()) { + toSend = ComponentInterpolator.interpolate( + context.plugin(), + context.resourceBundleContext().goalResourceBundle(), + "mobgoal.single.reached.message", + Map.of( + "entity", ComponentInterpolator.translate(killed) + ) + ); + soundInBundleKey = "mobgoal.single.reached.sound"; + } + else { + toSend = ComponentInterpolator.interpolate( + context.plugin(), + context.resourceBundleContext().goalResourceBundle(), + "mobgoal.single.step.message", + Map.of( + "player", Component.text(killer.getName()), + "entity", ComponentInterpolator.translate(killed), + "amount", Component.text(updatedCollect.getCurrentAmount()), + "total_amount", Component.text(updatedCollect.getAmountNeeded()) + ) + ); + soundInBundleKey = "mobgoal.single.step.sound"; + } + ActionHelper.sendAndPlaySound( + context.plugin(), + toSend, + context.resourceBundleContext().goalResourceBundle(), + soundInBundleKey + ); + if(determineComplete()) { onComplete(); } @@ -89,6 +133,6 @@ private boolean determineComplete() { @Override public void addToGeneratedConfig(GoalsConfig config) { - + config.setMobGoal(toGeneratedJSONClass()); } } diff --git a/plugin/src/main/java/wand555/github/io/challenges/utils/ActionHelper.java b/plugin/src/main/java/wand555/github/io/challenges/utils/ActionHelper.java new file mode 100644 index 0000000..427a3c5 --- /dev/null +++ b/plugin/src/main/java/wand555/github/io/challenges/utils/ActionHelper.java @@ -0,0 +1,48 @@ +package wand555.github.io.challenges.utils; + +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import wand555.github.io.challenges.Challenges; +import wand555.github.io.challenges.exceptions.MissingSoundException; + +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.bukkit.Sound; + +import javax.validation.constraints.NotNull; + +public class ActionHelper { + + private static final Map ALL_SOUNDS = Stream.of(Sound.values()) + .collect(Collectors.toMap( + sound -> sound.getKey().getKey(), + Function.identity() + )); + + public static void sendAndPlaySound(@NotNull Challenges plugin, @NotNull Component componentToSend, @NotNull ResourceBundle resourceBundle, @NotNull String keyInBundle) { + String soundToPlayKey = ResourceBundleHelper.getFromBundle(plugin, resourceBundle, keyInBundle); + + plugin.getServer().broadcast(componentToSend); + try { + Sound soundToPlay = str2Sound(soundToPlayKey); + plugin.getServer().getOnlinePlayers().forEach(onlinePlayer -> { + onlinePlayer.playSound(onlinePlayer.getLocation(), soundToPlay, 1f,1f); + }); + } catch (MissingSoundException e) { + plugin.getLogger().warning("missing sound"); + } + } + + private static Sound str2Sound(String soundKey) throws MissingSoundException { + Sound sound = ALL_SOUNDS.get(soundKey); + if(sound == null) { + throw new MissingSoundException(); + } + return sound; + } +} diff --git a/plugin/src/main/java/wand555/github/io/challenges/utils/ResourceBundleHelper.java b/plugin/src/main/java/wand555/github/io/challenges/utils/ResourceBundleHelper.java new file mode 100644 index 0000000..53ffdd8 --- /dev/null +++ b/plugin/src/main/java/wand555/github/io/challenges/utils/ResourceBundleHelper.java @@ -0,0 +1,28 @@ +package wand555.github.io.challenges.utils; + +import wand555.github.io.challenges.Challenges; + +import javax.validation.constraints.NotNull; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.logging.Level; + +public class ResourceBundleHelper { + + public static String getFromBundle(@NotNull Challenges plugin, ResourceBundle bundle, String key) { + try { + return bundle.getString(key); + } catch (MissingResourceException e) { + // log to ingame + String msg = String.format("Key '%s' is not found in resource bundle '%s'.", key, bundle.getBaseBundleName()); + plugin.getServer().getLogger().warning(msg); + plugin.getServer().getLogger().log(Level.WARNING, msg, e); + } catch (ClassCastException e) { + // log to ingame + String msg = String.format("Key '%s' is not a valid string in resource bundle '%s'.", key, bundle.getBaseBundleName()); + plugin.getServer().getLogger().warning(msg); + plugin.getServer().getLogger().log(Level.WARNING, msg, e); + } + return ""; + } +} diff --git a/plugin/src/main/resources/goals.properties b/plugin/src/main/resources/goals.properties new file mode 100644 index 0000000..f8aa9f8 --- /dev/null +++ b/plugin/src/main/resources/goals.properties @@ -0,0 +1,11 @@ +chat.color.prefix=#008e6e +chat.color.default=#fceaff +chat.color.highlight=#3abeaa + +mobgoal.name= MobGoal +mobgoal.single.step.message= killed ! / reached! +mobgoal.single.step.sound= entity.experience_orb.pickup +mobgoal.single.reached.message= All successfully killed! +mobgoal.single.reached.sound= block.enchantment_table.use +mobgoal.all.reached.message= All entities have been successfully killed! This goal is complete! +mobgoal.all.reached.sound= ui.toast.challenge_complete \ No newline at end of file diff --git a/plugin/src/main/resources/goals_de.properties b/plugin/src/main/resources/goals_de.properties new file mode 100644 index 0000000..e69de29 diff --git a/plugin/src/main/resources/goals_en.properties b/plugin/src/main/resources/goals_en.properties new file mode 100644 index 0000000..e69de29 diff --git a/plugin/src/test/java/wand555/github/io/FileManagerTest.java b/plugin/src/test/java/wand555/github/io/FileManagerTest.java index 1b7d0dd..a8bef77 100644 --- a/plugin/src/test/java/wand555/github/io/FileManagerTest.java +++ b/plugin/src/test/java/wand555/github/io/FileManagerTest.java @@ -45,7 +45,7 @@ public void setUp() throws IOException { player = server.addPlayer(); bundle = ResourceBundle.getBundle("rules", Locale.US, UTF8ResourceBundleControl.get()); JsonNode schemaRoot = new ObjectMapper().readTree(new File("src/test/resources/challenges_schema.json")); - context = new Context(plugin, new ResourceBundleContext(bundle, null), schemaRoot, new ChallengeManager()); + context = new Context(plugin, new ResourceBundleContext(bundle, null, null), schemaRoot, new ChallengeManager(plugin)); mapper = new ModelMapper(context); diff --git a/plugin/src/test/java/wand555/github/io/challenges/rules/NoBlockBreakRuleTest.java b/plugin/src/test/java/wand555/github/io/challenges/rules/NoBlockBreakRuleTest.java index cc1f848..abfb671 100644 --- a/plugin/src/test/java/wand555/github/io/challenges/rules/NoBlockBreakRuleTest.java +++ b/plugin/src/test/java/wand555/github/io/challenges/rules/NoBlockBreakRuleTest.java @@ -66,7 +66,7 @@ public void setUp() { plugin = MockBukkit.load(Challenges.class); player = server.addPlayer("dummy"); toBeBroken = player.getWorld().getBlockAt(0, 0, 0); - context = new Context(plugin, resourceBundleContext, schemaRoot, new ChallengeManager()); + context = new Context(plugin, resourceBundleContext, schemaRoot, new ChallengeManager(plugin)); rule = spy(new NoBlockBreakRule(context, new NoBlockBreakRuleConfig(List.of(Material.STONE.toString()), null))); } diff --git a/plugin/src/test/java/wand555/github/io/goals/MobGoalTest.java b/plugin/src/test/java/wand555/github/io/goals/MobGoalTest.java index f9f16af..74dfd08 100644 --- a/plugin/src/test/java/wand555/github/io/goals/MobGoalTest.java +++ b/plugin/src/test/java/wand555/github/io/goals/MobGoalTest.java @@ -50,7 +50,7 @@ public void setUp() throws IOException { bundle = ResourceBundle.getBundle("rules", Locale.US, UTF8ResourceBundleControl.get()); JsonNode schemaRoot = new ObjectMapper().readTree(Challenges.class.getResource("/test-output-schema.json")); ChallengeManager manager = mock(ChallengeManager.class); - context = new Context(plugin, new ResourceBundleContext(bundle, null), schemaRoot, manager); //TODO load correct bundle + context = new Context(plugin, new ResourceBundleContext(bundle, null, null), schemaRoot, manager); //TODO load correct bundle mapper = new ModelMapper(context); diff --git a/plugin/src/test/java/wand555/github/io/punishments/HealthPunishmentTest.java b/plugin/src/test/java/wand555/github/io/punishments/HealthPunishmentTest.java index 903f90a..304ae31 100644 --- a/plugin/src/test/java/wand555/github/io/punishments/HealthPunishmentTest.java +++ b/plugin/src/test/java/wand555/github/io/punishments/HealthPunishmentTest.java @@ -53,7 +53,7 @@ public void setUp() throws IOException { server = MockBukkit.mock(); plugin = MockBukkit.load(Challenges.class); player = server.addPlayer(); - context = new Context(plugin, resourceBundleContext, schemaRoot, new ChallengeManager()); + context = new Context(plugin, resourceBundleContext, schemaRoot, new ChallengeManager(plugin)); } @AfterEach