From 78604b68414c280bb03065ea9176b72af33dc833 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sat, 30 Jul 2022 23:10:59 -0400 Subject: [PATCH 01/15] Create aggression levels and create declare war system --- .../java/io/icker/factions/FactionsMod.java | 1 + .../factions/api/persistents/Faction.java | 2 + .../api/persistents/Relationship.java | 4 ++ .../factions/command/DeclareCommand.java | 29 +++++++-- .../java/io/icker/factions/config/Config.java | 5 ++ .../io/icker/factions/config/WarConfig.java | 11 ++++ .../io/icker/factions/core/WarManager.java | 62 +++++++++++++++++++ .../java/io/icker/factions/util/Command.java | 19 +++++- 8 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 src/main/java/io/icker/factions/config/WarConfig.java create mode 100644 src/main/java/io/icker/factions/core/WarManager.java diff --git a/src/main/java/io/icker/factions/FactionsMod.java b/src/main/java/io/icker/factions/FactionsMod.java index fe654eab..03639904 100644 --- a/src/main/java/io/icker/factions/FactionsMod.java +++ b/src/main/java/io/icker/factions/FactionsMod.java @@ -39,6 +39,7 @@ public void onInitialize() { ServerManager.register(); SoundManager.register(); WorldManager.register(); + WarManager.register(); CommandRegistrationCallback.EVENT.register(FactionsMod::registerCommands); } diff --git a/src/main/java/io/icker/factions/api/persistents/Faction.java b/src/main/java/io/icker/factions/api/persistents/Faction.java index dac69b56..ea985d98 100644 --- a/src/main/java/io/icker/factions/api/persistents/Faction.java +++ b/src/main/java/io/icker/factions/api/persistents/Faction.java @@ -7,6 +7,7 @@ import io.icker.factions.database.Name; import net.minecraft.inventory.SimpleInventory; import net.minecraft.util.Formatting; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -68,6 +69,7 @@ public String getKey() { return id.toString(); } + @Nullable public static Faction get(UUID id) { return STORE.get(id); } diff --git a/src/main/java/io/icker/factions/api/persistents/Relationship.java b/src/main/java/io/icker/factions/api/persistents/Relationship.java index 25f808a7..8519d940 100644 --- a/src/main/java/io/icker/factions/api/persistents/Relationship.java +++ b/src/main/java/io/icker/factions/api/persistents/Relationship.java @@ -9,11 +9,15 @@ public enum Status { ALLY, NEUTRAL, ENEMY, + WARRING } @Field("Target") public UUID target; + @Field("Aggression") + public int aggression; + @Field("Status") public Status status; diff --git a/src/main/java/io/icker/factions/command/DeclareCommand.java b/src/main/java/io/icker/factions/command/DeclareCommand.java index 7f61942b..d59392f9 100644 --- a/src/main/java/io/icker/factions/command/DeclareCommand.java +++ b/src/main/java/io/icker/factions/command/DeclareCommand.java @@ -1,14 +1,12 @@ package io.icker.factions.command; -import java.util.Locale; - import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.tree.LiteralCommandNode; - import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.Relationship; +import io.icker.factions.core.WarManager; import io.icker.factions.util.Command; import io.icker.factions.util.Message; import net.minecraft.server.command.CommandManager; @@ -16,6 +14,8 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Formatting; +import java.util.Locale; + public class DeclareCommand implements Command { private int ally(CommandContext context) throws CommandSyntaxException { return updateRelationship(context, Relationship.Status.ALLY); @@ -29,6 +29,10 @@ private int enemy(CommandContext context) throws CommandSyn return updateRelationship(context, Relationship.Status.ENEMY); } + private int war(CommandContext context) throws CommandSyntaxException { + return updateRelationship(context, Relationship.Status.WARRING); + } + private int updateRelationship(CommandContext context, Relationship.Status status) throws CommandSyntaxException { String name = StringArgumentType.getString(context, "faction"); ServerCommandSource source = context.getSource(); @@ -53,12 +57,20 @@ private int updateRelationship(CommandContext context, Rela return 0; } + if (status == Relationship.Status.WARRING && !WarManager.eligibleForWar(sourceFaction, targetFaction)) { + new Message("You cannot currently go to war with that faction").fail().send(player, false); + return 0; + } + Relationship rel = new Relationship(targetFaction.getID(), status); Relationship rev = targetFaction.getRelationship(sourceFaction.getID()); sourceFaction.setRelationship(rel); + rel.aggression = 0; + Message msgStatus = rel.status == Relationship.Status.ALLY ? new Message("allies").format(Formatting.GREEN) - : rel.status == Relationship.Status.ENEMY ? new Message("enemies").format(Formatting.RED) + : rel.status == Relationship.Status.ENEMY ? new Message("enemies").format(Formatting.RED) + : rel.status == Relationship.Status.WARRING ? new Message("warring").format(Formatting.RED).format(Formatting.BOLD) : new Message("neutral"); if (rel.status == rev.status) { @@ -111,6 +123,15 @@ public LiteralCommandNode getNode() { .executes(this::enemy) ) ) + .then( + CommandManager.literal("warring") + .requires(Requires.multiple(Requires.hasPerms("factions.declare.warring", 0), WarManager::eligibleForWar)) + .then( + CommandManager.argument("faction", StringArgumentType.greedyString()) + .suggests(Suggests.eligibleForWar()) + .executes(this::war) + ) + ) .build(); } diff --git a/src/main/java/io/icker/factions/config/Config.java b/src/main/java/io/icker/factions/config/Config.java index 715b8f24..21dfc156 100644 --- a/src/main/java/io/icker/factions/config/Config.java +++ b/src/main/java/io/icker/factions/config/Config.java @@ -24,6 +24,7 @@ public static Config load() { .registerTypeAdapter(HomeConfig.class, new Deserializer<>(HomeConfig.class)) .registerTypeAdapter(PowerConfig.class, new Deserializer<>(PowerConfig.class)) .registerTypeAdapter(SafeConfig.class, new Deserializer<>(SafeConfig.class)) + .registerTypeAdapter(WarConfig.class, new Deserializer<>(WarConfig.class)) .create(); try { @@ -66,6 +67,10 @@ public static Config load() { @Nullable public HomeConfig HOME = new HomeConfig(); + @SerializedName("war") + @Nullable + public WarConfig WAR = new WarConfig(); + @SerializedName("display") public DisplayConfig DISPLAY = new DisplayConfig(); diff --git a/src/main/java/io/icker/factions/config/WarConfig.java b/src/main/java/io/icker/factions/config/WarConfig.java new file mode 100644 index 00000000..d7a28911 --- /dev/null +++ b/src/main/java/io/icker/factions/config/WarConfig.java @@ -0,0 +1,11 @@ +package io.icker.factions.config; + +import com.google.gson.annotations.SerializedName; + +public class WarConfig { + @SerializedName("attackAggression") + public int ATTACK_AGGRESSION = 50; + + @SerializedName("aggressionLevelForWar") + public int AGGRESSION_LEVEL = 100; +} diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java new file mode 100644 index 00000000..1f0415d1 --- /dev/null +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -0,0 +1,62 @@ +package io.icker.factions.core; + +import io.icker.factions.FactionsMod; +import io.icker.factions.api.events.PlayerEvents; +import io.icker.factions.api.persistents.Faction; +import io.icker.factions.api.persistents.Relationship; +import io.icker.factions.api.persistents.User; +import io.icker.factions.api.persistents.User.Rank; +import io.icker.factions.util.Message; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; + +public class WarManager { + public static void register() { + PlayerEvents.ON_KILLED_BY_PLAYER.register(WarManager::onKilled); + } + + private static void onKilled(ServerPlayerEntity player, DamageSource source) { + Faction attackingFaction = User.get(source.getSource().getUuid()).getFaction(); + Faction targetFaction = User.get(player.getUuid()).getFaction(); + + if (attackingFaction == null || targetFaction == null) return; + + Relationship rel = attackingFaction.getRelationship(targetFaction.getID()); + Relationship rev = attackingFaction.getReverse(rel); + + if (rel.status == Relationship.Status.ENEMY && rev.status == Relationship.Status.ENEMY && FactionsMod.CONFIG.WAR != null) { + rev.aggression += FactionsMod.CONFIG.WAR.ATTACK_AGGRESSION; + if (rev.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL) { + PlayerManager playerManager = player.getServer().getPlayerManager(); + targetFaction.getUsers() + .stream() + .filter(user -> (user.rank == Rank.LEADER || user.rank == Rank.OWNER) && playerManager.getPlayer(user.getID()) != null) + .forEach(user -> playerManager.sendCommandTree(playerManager.getPlayer(user.getID()))); + + new Message("Your faction is now eligible to go to war with %s", attackingFaction.getName()).hover("Click to go to war").click(String.format("/f declare warring %s", attackingFaction.getName())).send(targetFaction); + } + } + } + + public static boolean eligibleForWar(ServerCommandSource source) { + if (FactionsMod.CONFIG.WAR == null) return false; + + ServerPlayerEntity player = source.getPlayer(); + if (source.getPlayer() == null) return false; + + User user = User.get(player.getUuid()); + if (!user.isInFaction()) return false; + + Faction faction = user.getFaction(); + + return faction.getEnemiesWith().stream().anyMatch(rel -> rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL || faction.getReverse(rel).status == Relationship.Status.WARRING); + } + + public static boolean eligibleForWar(Faction source, Faction target) { + if (FactionsMod.CONFIG.WAR == null) return false; + FactionsMod.LOGGER.info(source.getName(), target.getName()); + return target.getRelationship(source.getID()).status == Relationship.Status.WARRING || source.getRelationship(target.getID()).aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL; + } +} diff --git a/src/main/java/io/icker/factions/util/Command.java b/src/main/java/io/icker/factions/util/Command.java index 53b2bb88..25530559 100644 --- a/src/main/java/io/icker/factions/util/Command.java +++ b/src/main/java/io/icker/factions/util/Command.java @@ -1,18 +1,18 @@ package io.icker.factions.util; -import java.util.function.Predicate; - import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.tree.LiteralCommandNode; - import io.icker.factions.FactionsMod; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.User; +import io.icker.factions.core.WarManager; import me.lucko.fabric.api.permissions.v0.Permissions; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import java.util.function.Predicate; + public interface Command { public LiteralCommandNode getNode(); @@ -86,6 +86,19 @@ public static SuggestionProvider allFactions(boolean includ ); } + public static SuggestionProvider eligibleForWar() { + return suggest(user -> { + Faction source = user.getFaction(); + FactionsMod.LOGGER.info(source.getName()); + return Faction.all() + .stream() + .filter(faction -> WarManager.eligibleForWar(source, faction)) + .map(Faction::getName) + .toArray(String[]::new); + } + ); + } + public static SuggestionProvider openFactions() { return suggest(user -> Faction.all() From d9a1fe6d94eb641a0b2d029523d59a68c7402259 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sat, 30 Jul 2022 23:41:06 -0400 Subject: [PATCH 02/15] Add separate war command --- .../java/io/icker/factions/FactionsMod.java | 1 + .../factions/command/DeclareCommand.java | 20 ----- .../io/icker/factions/command/WarCommand.java | 75 +++++++++++++++++++ .../io/icker/factions/core/WarManager.java | 2 +- 4 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 src/main/java/io/icker/factions/command/WarCommand.java diff --git a/src/main/java/io/icker/factions/FactionsMod.java b/src/main/java/io/icker/factions/FactionsMod.java index 03639904..3636284b 100644 --- a/src/main/java/io/icker/factions/FactionsMod.java +++ b/src/main/java/io/icker/factions/FactionsMod.java @@ -75,6 +75,7 @@ private static void registerCommands(CommandDispatcher disp new ModifyCommand(), new RankCommand(), new SafeCommand(), + new WarCommand(), }; for (Command command : commands) { diff --git a/src/main/java/io/icker/factions/command/DeclareCommand.java b/src/main/java/io/icker/factions/command/DeclareCommand.java index d59392f9..69ada561 100644 --- a/src/main/java/io/icker/factions/command/DeclareCommand.java +++ b/src/main/java/io/icker/factions/command/DeclareCommand.java @@ -6,7 +6,6 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.Relationship; -import io.icker.factions.core.WarManager; import io.icker.factions.util.Command; import io.icker.factions.util.Message; import net.minecraft.server.command.CommandManager; @@ -29,10 +28,6 @@ private int enemy(CommandContext context) throws CommandSyn return updateRelationship(context, Relationship.Status.ENEMY); } - private int war(CommandContext context) throws CommandSyntaxException { - return updateRelationship(context, Relationship.Status.WARRING); - } - private int updateRelationship(CommandContext context, Relationship.Status status) throws CommandSyntaxException { String name = StringArgumentType.getString(context, "faction"); ServerCommandSource source = context.getSource(); @@ -57,11 +52,6 @@ private int updateRelationship(CommandContext context, Rela return 0; } - if (status == Relationship.Status.WARRING && !WarManager.eligibleForWar(sourceFaction, targetFaction)) { - new Message("You cannot currently go to war with that faction").fail().send(player, false); - return 0; - } - Relationship rel = new Relationship(targetFaction.getID(), status); Relationship rev = targetFaction.getRelationship(sourceFaction.getID()); sourceFaction.setRelationship(rel); @@ -70,7 +60,6 @@ private int updateRelationship(CommandContext context, Rela Message msgStatus = rel.status == Relationship.Status.ALLY ? new Message("allies").format(Formatting.GREEN) : rel.status == Relationship.Status.ENEMY ? new Message("enemies").format(Formatting.RED) - : rel.status == Relationship.Status.WARRING ? new Message("warring").format(Formatting.RED).format(Formatting.BOLD) : new Message("neutral"); if (rel.status == rev.status) { @@ -123,15 +112,6 @@ public LiteralCommandNode getNode() { .executes(this::enemy) ) ) - .then( - CommandManager.literal("warring") - .requires(Requires.multiple(Requires.hasPerms("factions.declare.warring", 0), WarManager::eligibleForWar)) - .then( - CommandManager.argument("faction", StringArgumentType.greedyString()) - .suggests(Suggests.eligibleForWar()) - .executes(this::war) - ) - ) .build(); } diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java new file mode 100644 index 00000000..b8f45aba --- /dev/null +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -0,0 +1,75 @@ +package io.icker.factions.command; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.icker.factions.api.persistents.Faction; +import io.icker.factions.api.persistents.Relationship; +import io.icker.factions.core.WarManager; +import io.icker.factions.util.Command; +import io.icker.factions.util.Message; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; + +import static io.icker.factions.api.persistents.Relationship.Status.WARRING; + +public class WarCommand implements Command { + private int declare (CommandContext context) { + String name = StringArgumentType.getString(context, "faction"); + ServerCommandSource source = context.getSource(); + ServerPlayerEntity player = source.getPlayer(); + + Faction targetFaction = Faction.getByName(name); + + if (targetFaction == null) { + new Message("Cannot go to war with a nonexistent faction").fail().send(player, false); + return 0; + } + + Faction sourceFaction = Command.getUser(player).getFaction(); + + if (sourceFaction.equals(targetFaction)) { + new Message("Cannot declare war on yourself").fail().send(player, false); + return 0; + } + + if (sourceFaction.getRelationship(targetFaction.getID()).status == WARRING) { + new Message("You are already at war with that faction").fail().send(player, false); + return 0; + } + + if (!WarManager.eligibleForWar(sourceFaction, targetFaction)) { + new Message("You cannot currently go to war with that faction").fail().send(player, false); + return 0; + } + + Relationship rel = new Relationship(targetFaction.getID(), WARRING); + sourceFaction.setRelationship(rel); + + new Message("You have declared war on " + targetFaction.getName()).send(sourceFaction); + + new Message(sourceFaction.getName() + " have declared war on you") + .hover("Click to declare war back") + .click(String.format("/factions war declare %s", sourceFaction.getName())) + .send(targetFaction); + + return 1; + } + + @Override + public LiteralCommandNode getNode() { + return CommandManager + .literal("war") + .requires(Requires.isLeader()) + .then( + CommandManager.literal("declare") + .requires(WarManager::eligibleForWar) + .then( + CommandManager.argument("faction", StringArgumentType.greedyString()) + .suggests(Suggests.eligibleForWar()) + .executes(this::declare) + ) + ).build(); + } +} diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index 1f0415d1..77480a99 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -35,7 +35,7 @@ private static void onKilled(ServerPlayerEntity player, DamageSource source) { .filter(user -> (user.rank == Rank.LEADER || user.rank == Rank.OWNER) && playerManager.getPlayer(user.getID()) != null) .forEach(user -> playerManager.sendCommandTree(playerManager.getPlayer(user.getID()))); - new Message("Your faction is now eligible to go to war with %s", attackingFaction.getName()).hover("Click to go to war").click(String.format("/f declare warring %s", attackingFaction.getName())).send(targetFaction); + new Message("Your faction is now eligible to go to war with %s", attackingFaction.getName()).hover("Click to go to war").click(String.format("/f war declare %s", attackingFaction.getName())).send(targetFaction); } } } From cb55ea11a39f014e65e99d50881526ec4538a756 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 00:03:49 -0400 Subject: [PATCH 03/15] Add end war command --- .../factions/api/persistents/Faction.java | 4 ++ .../api/persistents/Relationship.java | 2 + .../factions/command/DeclareCommand.java | 5 ++ .../io/icker/factions/command/WarCommand.java | 66 +++++++++++++++++-- .../java/io/icker/factions/util/Command.java | 9 +++ 5 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/icker/factions/api/persistents/Faction.java b/src/main/java/io/icker/factions/api/persistents/Faction.java index ea985d98..8de57345 100644 --- a/src/main/java/io/icker/factions/api/persistents/Faction.java +++ b/src/main/java/io/icker/factions/api/persistents/Faction.java @@ -224,6 +224,10 @@ public List getEnemiesOf() { return relationships.stream().filter(rel -> getReverse(rel).status == Relationship.Status.ENEMY).toList(); } + public List getWars() { + return relationships.stream().filter(rel -> getReverse(rel).status == Relationship.Status.WARRING && rel.status == Relationship.Status.WARRING).toList(); + } + public void removeRelationship(UUID target) { relationships = new ArrayList<>(relationships.stream().filter(rel -> !rel.target.equals(target)).toList()); } diff --git a/src/main/java/io/icker/factions/api/persistents/Relationship.java b/src/main/java/io/icker/factions/api/persistents/Relationship.java index 8519d940..1a7ba853 100644 --- a/src/main/java/io/icker/factions/api/persistents/Relationship.java +++ b/src/main/java/io/icker/factions/api/persistents/Relationship.java @@ -21,6 +21,8 @@ public enum Status { @Field("Status") public Status status; + public boolean readyToEnd = false; + public Relationship(UUID target, Status status) { this.target = target; this.status = status; diff --git a/src/main/java/io/icker/factions/command/DeclareCommand.java b/src/main/java/io/icker/factions/command/DeclareCommand.java index 69ada561..f4d816eb 100644 --- a/src/main/java/io/icker/factions/command/DeclareCommand.java +++ b/src/main/java/io/icker/factions/command/DeclareCommand.java @@ -52,6 +52,11 @@ private int updateRelationship(CommandContext context, Rela return 0; } + if (sourceFaction.getRelationship(targetFaction.getID()).status == Relationship.Status.WARRING && targetFaction.getRelationship(sourceFaction.getID()).status == Relationship.Status.WARRING) { + new Message("Both factions must agree to end the war").fail().send(player, false); + return 0; + } + Relationship rel = new Relationship(targetFaction.getID(), status); Relationship rev = targetFaction.getRelationship(sourceFaction.getID()); sourceFaction.setRelationship(rel); diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java index b8f45aba..3d365010 100644 --- a/src/main/java/io/icker/factions/command/WarCommand.java +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -12,6 +12,7 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import static io.icker.factions.api.persistents.Relationship.Status.NEUTRAL; import static io.icker.factions.api.persistents.Relationship.Status.WARRING; public class WarCommand implements Command { @@ -57,19 +58,72 @@ private int declare (CommandContext context) { return 1; } + private int end (CommandContext context) { + String name = StringArgumentType.getString(context, "faction"); + ServerCommandSource source = context.getSource(); + ServerPlayerEntity player = source.getPlayer(); + + Faction targetFaction = Faction.getByName(name); + + if (targetFaction == null) { + new Message("Cannot end a war with a faction that does not exist").fail().send(player, false); + return 0; + } + + Faction sourceFaction = Command.getUser(player).getFaction(); + + if (sourceFaction.equals(targetFaction)) { + new Message("Cannot end a war with yourself").fail().send(player, false); + return 0; + } + + Relationship rel = sourceFaction.getRelationship(targetFaction.getID()); + Relationship rev = sourceFaction.getReverse(rel); + + if (rel.status != WARRING && rev.status != WARRING) { + new Message("You are not at war with that faction").fail().send(player, false); + return 0; + } + + if (!rev.readyToEnd) { + rel.readyToEnd = true; + new Message("%s must also agree to end the war (they have been asked if they want to end it)", targetFaction.getName()).send(player, false); + new Message("%s would like to end the war", sourceFaction.getName()).hover("Click to end the war").click(String.format("/f war end %s", sourceFaction.getName())).send(targetFaction); + return 0; + } + + rev.readyToEnd = false; + + rel.status = NEUTRAL; + rev.status = NEUTRAL; + + new Message("You are no longer at war with " + targetFaction.getName()).send(sourceFaction); + new Message(sourceFaction.getName() + " has ended the war").send(targetFaction); + return 1; + } + @Override public LiteralCommandNode getNode() { return CommandManager .literal("war") - .requires(Requires.isLeader()) + .requires(Requires.multiple(Requires.isLeader(), WarManager::eligibleForWar, Requires.require(user -> !user.getFaction().getWars().isEmpty()))) .then( CommandManager.literal("declare") .requires(WarManager::eligibleForWar) - .then( - CommandManager.argument("faction", StringArgumentType.greedyString()) - .suggests(Suggests.eligibleForWar()) - .executes(this::declare) - ) + .then( + CommandManager.argument("faction", StringArgumentType.greedyString()) + .suggests(Suggests.eligibleForWar()) + .executes(this::declare) + ) + ) + .then( + CommandManager.literal("end") + .requires(Requires.require(user -> !user.getFaction().getWars().isEmpty())) + .then( + CommandManager.argument("faction", StringArgumentType.greedyString()) + .suggests(Suggests.atWar()) + .executes(this::end) + ) ).build(); } } diff --git a/src/main/java/io/icker/factions/util/Command.java b/src/main/java/io/icker/factions/util/Command.java index 25530559..2e8c4b17 100644 --- a/src/main/java/io/icker/factions/util/Command.java +++ b/src/main/java/io/icker/factions/util/Command.java @@ -86,6 +86,15 @@ public static SuggestionProvider allFactions(boolean includ ); } + public static SuggestionProvider atWar() { + return suggest(user -> + user.getFaction().getWars() + .stream() + .map(rel -> Faction.get(rel.target).getName()) + .toArray(String[]::new) + ); + } + public static SuggestionProvider eligibleForWar() { return suggest(user -> { Faction source = user.getFaction(); From 7eabf5729be0936a4756a9d144cb9ed171e09ab3 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 12:14:18 -0400 Subject: [PATCH 04/15] Update command tree when necessary Add color to some commands/messages --- .../factions/api/persistents/Faction.java | 16 +++++++++++++ .../io/icker/factions/command/WarCommand.java | 23 ++++++++++++++++--- .../io/icker/factions/core/WarManager.java | 14 +++++------ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/icker/factions/api/persistents/Faction.java b/src/main/java/io/icker/factions/api/persistents/Faction.java index 8de57345..6cf1e5bc 100644 --- a/src/main/java/io/icker/factions/api/persistents/Faction.java +++ b/src/main/java/io/icker/factions/api/persistents/Faction.java @@ -6,10 +6,13 @@ import io.icker.factions.database.Field; import io.icker.factions.database.Name; import net.minecraft.inventory.SimpleInventory; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Formatting; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Predicate; @Name("Faction") public class Faction { @@ -171,6 +174,19 @@ public List getUsers() { return User.getByFaction(id); } + public void sendCommandTree(PlayerManager playerManager) { + sendCommandTree(playerManager, user -> true); + } + + public void sendCommandTree(PlayerManager playerManager, Predicate filter) { + getUsers().stream().filter(filter).forEach(user -> { + ServerPlayerEntity player = playerManager.getPlayer(user.getID()); + if (player != null) { + playerManager.sendCommandTree(player); + } + }); + } + public List getClaims() { return Claim.getByFaction(id); } diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java index 3d365010..5ef65550 100644 --- a/src/main/java/io/icker/factions/command/WarCommand.java +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -5,15 +5,19 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.Relationship; +import io.icker.factions.api.persistents.User; import io.icker.factions.core.WarManager; import io.icker.factions.util.Command; import io.icker.factions.util.Message; +import net.minecraft.server.PlayerManager; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import static io.icker.factions.api.persistents.Relationship.Status.NEUTRAL; import static io.icker.factions.api.persistents.Relationship.Status.WARRING; +import static net.minecraft.util.Formatting.RED; +import static net.minecraft.util.Formatting.RESET; public class WarCommand implements Command { private int declare (CommandContext context) { @@ -48,9 +52,12 @@ private int declare (CommandContext context) { Relationship rel = new Relationship(targetFaction.getID(), WARRING); sourceFaction.setRelationship(rel); - new Message("You have declared war on " + targetFaction.getName()).send(sourceFaction); + new Message("You have declared " + RED + "war" + RESET + " on " + targetFaction.getName()).send(sourceFaction); - new Message(sourceFaction.getName() + " have declared war on you") + PlayerManager playerManager = player.getServer().getPlayerManager(); + sourceFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + + new Message(sourceFaction.getName() + " have declared " + RED + "war" + RESET + " on you") .hover("Click to declare war back") .click(String.format("/factions war declare %s", sourceFaction.getName())) .send(targetFaction); @@ -87,6 +94,11 @@ private int end (CommandContext context) { if (!rev.readyToEnd) { rel.readyToEnd = true; + + PlayerManager playerManager = player.getServer().getPlayerManager(); + sourceFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + + new Message("%s must also agree to end the war (they have been asked if they want to end it)", targetFaction.getName()).send(player, false); new Message("%s would like to end the war", sourceFaction.getName()).hover("Click to end the war").click(String.format("/f war end %s", sourceFaction.getName())).send(targetFaction); return 0; @@ -99,6 +111,11 @@ private int end (CommandContext context) { new Message("You are no longer at war with " + targetFaction.getName()).send(sourceFaction); new Message(sourceFaction.getName() + " has ended the war").send(targetFaction); + + PlayerManager playerManager = player.getServer().getPlayerManager(); + sourceFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + targetFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + return 1; } @@ -106,7 +123,7 @@ private int end (CommandContext context) { public LiteralCommandNode getNode() { return CommandManager .literal("war") - .requires(Requires.multiple(Requires.isLeader(), WarManager::eligibleForWar, Requires.require(user -> !user.getFaction().getWars().isEmpty()))) + .requires(Requires.multiple(Requires.isLeader(), (source) -> WarManager.eligibleForWar(source) || Requires.require(user -> !user.getFaction().getWars().isEmpty()).test(source))) .then( CommandManager.literal("declare") .requires(WarManager::eligibleForWar) diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index 77480a99..e71a5198 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -12,6 +12,9 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import static net.minecraft.util.Formatting.RED; +import static net.minecraft.util.Formatting.RESET; + public class WarManager { public static void register() { PlayerEvents.ON_KILLED_BY_PLAYER.register(WarManager::onKilled); @@ -30,12 +33,10 @@ private static void onKilled(ServerPlayerEntity player, DamageSource source) { rev.aggression += FactionsMod.CONFIG.WAR.ATTACK_AGGRESSION; if (rev.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL) { PlayerManager playerManager = player.getServer().getPlayerManager(); - targetFaction.getUsers() - .stream() - .filter(user -> (user.rank == Rank.LEADER || user.rank == Rank.OWNER) && playerManager.getPlayer(user.getID()) != null) - .forEach(user -> playerManager.sendCommandTree(playerManager.getPlayer(user.getID()))); - new Message("Your faction is now eligible to go to war with %s", attackingFaction.getName()).hover("Click to go to war").click(String.format("/f war declare %s", attackingFaction.getName())).send(targetFaction); + targetFaction.sendCommandTree(playerManager, user -> (user.rank == Rank.LEADER || user.rank == Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + + new Message("Your faction is now eligible to go to " + RED + "war" + RESET + " with %s", attackingFaction.getName()).hover("Click to go to war").click(String.format("/f war declare %s", attackingFaction.getName())).send(targetFaction); } } } @@ -51,12 +52,11 @@ public static boolean eligibleForWar(ServerCommandSource source) { Faction faction = user.getFaction(); - return faction.getEnemiesWith().stream().anyMatch(rel -> rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL || faction.getReverse(rel).status == Relationship.Status.WARRING); + return faction.getEnemiesWith().stream().anyMatch(rel -> (rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL || faction.getReverse(rel).status == Relationship.Status.WARRING) && rel.status != Relationship.Status.WARRING); } public static boolean eligibleForWar(Faction source, Faction target) { if (FactionsMod.CONFIG.WAR == null) return false; - FactionsMod.LOGGER.info(source.getName(), target.getName()); return target.getRelationship(source.getID()).status == Relationship.Status.WARRING || source.getRelationship(target.getID()).aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL; } } From 2f3f3f7ba4c0c7b9c82209212d006c5965754c87 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 12:30:20 -0400 Subject: [PATCH 05/15] Update info command Disable claim protection during wars --- .../java/io/icker/factions/api/persistents/Faction.java | 2 +- src/main/java/io/icker/factions/command/InfoCommand.java | 8 ++++++++ .../java/io/icker/factions/core/InteractionManager.java | 7 ++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/icker/factions/api/persistents/Faction.java b/src/main/java/io/icker/factions/api/persistents/Faction.java index 6cf1e5bc..bbcb4338 100644 --- a/src/main/java/io/icker/factions/api/persistents/Faction.java +++ b/src/main/java/io/icker/factions/api/persistents/Faction.java @@ -241,7 +241,7 @@ public List getEnemiesOf() { } public List getWars() { - return relationships.stream().filter(rel -> getReverse(rel).status == Relationship.Status.WARRING && rel.status == Relationship.Status.WARRING).toList(); + return relationships.stream().filter(rel -> getReverse(rel).status == Relationship.Status.WARRING || rel.status == Relationship.Status.WARRING).toList(); } public void removeRelationship(UUID target) { diff --git a/src/main/java/io/icker/factions/command/InfoCommand.java b/src/main/java/io/icker/factions/command/InfoCommand.java index bf64b127..17126302 100644 --- a/src/main/java/io/icker/factions/command/InfoCommand.java +++ b/src/main/java/io/icker/factions/command/InfoCommand.java @@ -73,6 +73,11 @@ public static int info(ServerPlayerEntity player, Faction faction) { .map(fac -> fac.getColor() + fac.getName()) .collect(Collectors.joining(Formatting.GRAY + ", ")); + String atWarWith = Formatting.GRAY + faction.getWars().stream() + .map(rel -> Faction.get(rel.target)) + .map(fac -> fac.getColor() + fac.getName()) + .collect(Collectors.joining(Formatting.GRAY + ", ")); + int requiredPower = faction.getClaims().size() * FactionsMod.CONFIG.POWER.CLAIM_WEIGHT; int maxPower = users.size() * FactionsMod.CONFIG.POWER.MEMBER + FactionsMod.CONFIG.POWER.BASE; @@ -101,6 +106,9 @@ public static int info(ServerPlayerEntity player, Faction faction) { new Message(Formatting.RED + "Enemies (" + Formatting.WHITE + faction.getEnemiesWith().size() + Formatting.RED + "): ") .add(enemiesWith) .send(player, false); + new Message(Formatting.DARK_RED + "At War (" + Formatting.WHITE + faction.getWars().size() + Formatting.DARK_RED + "): ") + .add(atWarWith) + .send(player, false); return 1; } diff --git a/src/main/java/io/icker/factions/core/InteractionManager.java b/src/main/java/io/icker/factions/core/InteractionManager.java index eb83a36b..4cb26e79 100644 --- a/src/main/java/io/icker/factions/core/InteractionManager.java +++ b/src/main/java/io/icker/factions/core/InteractionManager.java @@ -4,6 +4,7 @@ import io.icker.factions.api.events.PlayerEvents; import io.icker.factions.api.persistents.Claim; import io.icker.factions.api.persistents.Faction; +import io.icker.factions.api.persistents.Relationship; import io.icker.factions.api.persistents.User; import io.icker.factions.mixin.BucketItemMixin; import io.icker.factions.mixin.ItemMixin; @@ -168,7 +169,11 @@ private static ActionResult checkPermissions(PlayerEntity player, BlockPos posit Faction userFaction = user.getFaction(); - if (claimFaction == userFaction && getRankLevel(claim.accessLevel) <= getRankLevel(user.rank)) { + if (claimFaction.equals(userFaction) && getRankLevel(claim.accessLevel) <= getRankLevel(user.rank)) { + return ActionResult.PASS; + } + + if (userFaction.getRelationship(claimFaction.getID()).status == Relationship.Status.WARRING) { return ActionResult.PASS; } From fee3d52a86b8f824a0908ab03949b0475b2dd25f Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 13:12:27 -0400 Subject: [PATCH 06/15] Add trespassing as a way to increase aggression --- .../api/events/RelationshipEvents.java | 12 ++++++ .../icker/factions/api/persistents/User.java | 3 ++ .../io/icker/factions/config/WarConfig.java | 6 +++ .../io/icker/factions/core/WarManager.java | 40 +++++++++++++++++++ .../mixin/ServerPlayerEntityMixin.java | 6 ++- 5 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/icker/factions/api/events/RelationshipEvents.java b/src/main/java/io/icker/factions/api/events/RelationshipEvents.java index 68928bd9..fd1999eb 100644 --- a/src/main/java/io/icker/factions/api/events/RelationshipEvents.java +++ b/src/main/java/io/icker/factions/api/events/RelationshipEvents.java @@ -3,6 +3,7 @@ import io.icker.factions.api.persistents.Relationship; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.network.ServerPlayerEntity; /** * All events related to relationships (UNIMPLEMENTED) @@ -26,6 +27,12 @@ public final class RelationshipEvents { } }); + public static final Event ON_TRESPASSING = EventFactory.createArrayBacked(OnTrespassing.class, callbacks -> (player) -> { + for (OnTrespassing callback : callbacks) { + callback.onTrespassing(player); + } + }); + @FunctionalInterface public interface NewDecleration { void onNewDecleration(Relationship relationship); @@ -40,4 +47,9 @@ public interface NewMutual { public interface EndMutual { void onEndMutual(Relationship relationship, Relationship.Status oldStatus); } + + @FunctionalInterface + public interface OnTrespassing { + void onTrespassing(ServerPlayerEntity player); + } } diff --git a/src/main/java/io/icker/factions/api/persistents/User.java b/src/main/java/io/icker/factions/api/persistents/User.java index 5e01185f..ca4b8a7e 100644 --- a/src/main/java/io/icker/factions/api/persistents/User.java +++ b/src/main/java/io/icker/factions/api/persistents/User.java @@ -57,6 +57,9 @@ public enum SoundMode { public boolean bypass = false; public String language = "en_us"; + public boolean isTrespassing = false; + public int startedTrespassing = 0; + private User spoof; public User(UUID id) { diff --git a/src/main/java/io/icker/factions/config/WarConfig.java b/src/main/java/io/icker/factions/config/WarConfig.java index d7a28911..3bfc19d1 100644 --- a/src/main/java/io/icker/factions/config/WarConfig.java +++ b/src/main/java/io/icker/factions/config/WarConfig.java @@ -8,4 +8,10 @@ public class WarConfig { @SerializedName("aggressionLevelForWar") public int AGGRESSION_LEVEL = 100; + + @SerializedName("trespassingTime") + public int TRESPASSING_TIME = 70; + + @SerializedName("trespassingAggression") + public int TRESPASSING_AGGRESSION = 7; } diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index e71a5198..f17f02cd 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -2,6 +2,8 @@ import io.icker.factions.FactionsMod; import io.icker.factions.api.events.PlayerEvents; +import io.icker.factions.api.events.RelationshipEvents; +import io.icker.factions.api.persistents.Claim; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.Relationship; import io.icker.factions.api.persistents.User; @@ -11,6 +13,7 @@ import net.minecraft.server.PlayerManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.math.ChunkPos; import static net.minecraft.util.Formatting.RED; import static net.minecraft.util.Formatting.RESET; @@ -18,6 +21,8 @@ public class WarManager { public static void register() { PlayerEvents.ON_KILLED_BY_PLAYER.register(WarManager::onKilled); + PlayerEvents.ON_MOVE.register(WarManager::onMove); + RelationshipEvents.ON_TRESPASSING.register(WarManager::onTrespassing); } private static void onKilled(ServerPlayerEntity player, DamageSource source) { @@ -41,6 +46,41 @@ private static void onKilled(ServerPlayerEntity player, DamageSource source) { } } + private static void onTrespassing(ServerPlayerEntity player) { + FactionsMod.LOGGER.info("trespassing"); + if (FactionsMod.CONFIG.WAR == null) return; + + User user = User.get(player.getUuid()); + + String dimension = player.world.getRegistryKey().getValue().toString(); + ChunkPos chunkPosition = player.getChunkPos(); + + Claim claim = Claim.get(chunkPosition.x, chunkPosition.z, dimension); + + claim.getFaction().getRelationship(user.getFaction().getID()).aggression += FactionsMod.CONFIG.WAR.TRESPASSING_AGGRESSION; + } + + private static void onMove(ServerPlayerEntity player) { + if (FactionsMod.CONFIG.WAR == null) return; + + User user = User.get(player.getUuid()); + + if (!user.isInFaction()) return; + + String dimension = player.world.getRegistryKey().getValue().toString(); + ChunkPos chunkPosition = player.getChunkPos(); + + Claim claim = Claim.get(chunkPosition.x, chunkPosition.z, dimension); + + if (claim == null) return; + + if (claim.getFaction().getRelationship(user.getFaction().getID()).status == Relationship.Status.ENEMY && !user.isTrespassing) { + user.startedTrespassing = player.age; + } + + user.isTrespassing = claim.getFaction().getRelationship(user.getFaction().getID()).status == Relationship.Status.ENEMY; + } + public static boolean eligibleForWar(ServerCommandSource source) { if (FactionsMod.CONFIG.WAR == null) return false; diff --git a/src/main/java/io/icker/factions/mixin/ServerPlayerEntityMixin.java b/src/main/java/io/icker/factions/mixin/ServerPlayerEntityMixin.java index 6c924c8d..b34da831 100644 --- a/src/main/java/io/icker/factions/mixin/ServerPlayerEntityMixin.java +++ b/src/main/java/io/icker/factions/mixin/ServerPlayerEntityMixin.java @@ -2,6 +2,7 @@ import io.icker.factions.FactionsMod; import io.icker.factions.api.events.PlayerEvents; +import io.icker.factions.api.events.RelationshipEvents; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.User; import io.icker.factions.util.Message; @@ -23,7 +24,6 @@ @Mixin(ServerPlayerEntity.class) public abstract class ServerPlayerEntityMixin extends LivingEntity { - protected ServerPlayerEntityMixin(EntityType entityType, World world) { super(entityType, world); } @@ -43,6 +43,10 @@ public void onDeath(DamageSource source, CallbackInfo info) { @Inject(at = @At("HEAD"), method = "tick") public void tick(CallbackInfo info) { + User user = User.get(((ServerPlayerEntity) (Object) this).getUuid()); + if (FactionsMod.CONFIG.WAR != null && user.isTrespassing && (age - user.startedTrespassing) % FactionsMod.CONFIG.WAR.TRESPASSING_TIME == 0) + RelationshipEvents.ON_TRESPASSING.invoker().onTrespassing((ServerPlayerEntity) (Object) this); + if (age % FactionsMod.CONFIG.POWER.POWER_TICKS.TICKS != 0 || age == 0) return; PlayerEvents.ON_POWER_TICK.invoker().onPowerTick((ServerPlayerEntity) (Object) this); } From 0972af268b2fad01e51002b6ef4ee292b7599f1e Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 13:25:47 -0400 Subject: [PATCH 07/15] Allow allies to go to war Remove some log statements --- src/main/java/io/icker/factions/core/WarManager.java | 11 ++++++++--- src/main/java/io/icker/factions/util/Command.java | 1 - 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index f17f02cd..1fe87a42 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -47,7 +47,6 @@ private static void onKilled(ServerPlayerEntity player, DamageSource source) { } private static void onTrespassing(ServerPlayerEntity player) { - FactionsMod.LOGGER.info("trespassing"); if (FactionsMod.CONFIG.WAR == null) return; User user = User.get(player.getUuid()); @@ -92,11 +91,17 @@ public static boolean eligibleForWar(ServerCommandSource source) { Faction faction = user.getFaction(); - return faction.getEnemiesWith().stream().anyMatch(rel -> (rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL || faction.getReverse(rel).status == Relationship.Status.WARRING) && rel.status != Relationship.Status.WARRING); + return + faction.getEnemiesWith().stream().anyMatch(rel -> (rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL || + faction.getReverse(rel).status == Relationship.Status.WARRING) && rel.status != Relationship.Status.WARRING) || + faction.getMutualAllies().stream().anyMatch(rel -> !Faction.get(rel.target).getWars().isEmpty()); } public static boolean eligibleForWar(Faction source, Faction target) { if (FactionsMod.CONFIG.WAR == null) return false; - return target.getRelationship(source.getID()).status == Relationship.Status.WARRING || source.getRelationship(target.getID()).aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL; + return + target.getRelationship(source.getID()).status == Relationship.Status.WARRING + || source.getRelationship(target.getID()).aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL + || source.getMutualAllies().stream().anyMatch(rel -> Faction.get(rel.target).getRelationship(target.getID()).status == Relationship.Status.WARRING); } } diff --git a/src/main/java/io/icker/factions/util/Command.java b/src/main/java/io/icker/factions/util/Command.java index 2e8c4b17..d159ac4e 100644 --- a/src/main/java/io/icker/factions/util/Command.java +++ b/src/main/java/io/icker/factions/util/Command.java @@ -98,7 +98,6 @@ public static SuggestionProvider atWar() { public static SuggestionProvider eligibleForWar() { return suggest(user -> { Faction source = user.getFaction(); - FactionsMod.LOGGER.info(source.getName()); return Faction.all() .stream() .filter(faction -> WarManager.eligibleForWar(source, faction)) From 34110a2bfbbec36556c0879be564437ef67c92a7 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 16:49:54 -0400 Subject: [PATCH 08/15] Add lives to war --- .../icker/factions/api/persistents/User.java | 3 ++ .../icker/factions/command/AdminCommand.java | 28 +++++++++++++++++++ .../io/icker/factions/command/WarCommand.java | 5 ++++ .../io/icker/factions/config/WarConfig.java | 3 ++ .../factions/core/InteractionManager.java | 2 ++ .../io/icker/factions/core/WarManager.java | 5 +++- 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/icker/factions/api/persistents/User.java b/src/main/java/io/icker/factions/api/persistents/User.java index ca4b8a7e..c6bf44e0 100644 --- a/src/main/java/io/icker/factions/api/persistents/User.java +++ b/src/main/java/io/icker/factions/api/persistents/User.java @@ -53,6 +53,9 @@ public enum SoundMode { @Field("Sounds") public SoundMode sounds = SoundMode.ALL; + @Field("Lives") + public int lives = -1; + public boolean autoclaim = false; public boolean bypass = false; public String language = "en_us"; diff --git a/src/main/java/io/icker/factions/command/AdminCommand.java b/src/main/java/io/icker/factions/command/AdminCommand.java index 0b5033a1..cb258cc4 100644 --- a/src/main/java/io/icker/factions/command/AdminCommand.java +++ b/src/main/java/io/icker/factions/command/AdminCommand.java @@ -77,6 +77,23 @@ private int power(CommandContext context) throws CommandSyn return 1; } + private int lives(CommandContext context) throws CommandSyntaxException { + ServerCommandSource source = context.getSource(); + ServerPlayerEntity player = source.getPlayer(); + + ServerPlayerEntity targetEntity = EntityArgumentType.getPlayer(context, "player"); + User target = User.get(targetEntity.getUuid()); + + int numLives = IntegerArgumentType.getInteger(context, "numLives"); + + target.lives = numLives; + + new Message("Set %s's lives to %d", targetEntity.getName().getString(), numLives).send(player, false); + new Message("Your lives have been set to %d by %s", numLives, player.getName().getString()).send(targetEntity, false); + + return 1; + } + private int spoof(CommandContext context) throws CommandSyntaxException { ServerCommandSource source = context.getSource(); ServerPlayerEntity player = source.getPlayer(); @@ -140,6 +157,17 @@ public LiteralCommandNode getNode() { ) .executes(this::clearSpoof) ) + .then( + CommandManager.literal("lives") + .requires(Requires.hasPerms("factions.admin.lives", FactionsMod.CONFIG.REQUIRED_BYPASS_LEVEL)) + .then( + CommandManager.argument("numLives", IntegerArgumentType.integer()) + .then( + CommandManager.argument("player", EntityArgumentType.player()) + .executes(this::lives) + ) + ) + ) .build(); } } diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java index 5ef65550..7968c35e 100644 --- a/src/main/java/io/icker/factions/command/WarCommand.java +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -3,6 +3,7 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.LiteralCommandNode; +import io.icker.factions.FactionsMod; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.Relationship; import io.icker.factions.api.persistents.User; @@ -21,6 +22,8 @@ public class WarCommand implements Command { private int declare (CommandContext context) { + if (FactionsMod.CONFIG.WAR == null) return 0; + String name = StringArgumentType.getString(context, "faction"); ServerCommandSource source = context.getSource(); ServerPlayerEntity player = source.getPlayer(); @@ -57,6 +60,8 @@ private int declare (CommandContext context) { PlayerManager playerManager = player.getServer().getPlayerManager(); sourceFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + sourceFaction.getUsers().forEach(user -> user.lives = FactionsMod.CONFIG.WAR.NUM_LIVES); + new Message(sourceFaction.getName() + " have declared " + RED + "war" + RESET + " on you") .hover("Click to declare war back") .click(String.format("/factions war declare %s", sourceFaction.getName())) diff --git a/src/main/java/io/icker/factions/config/WarConfig.java b/src/main/java/io/icker/factions/config/WarConfig.java index 3bfc19d1..0a8e080f 100644 --- a/src/main/java/io/icker/factions/config/WarConfig.java +++ b/src/main/java/io/icker/factions/config/WarConfig.java @@ -14,4 +14,7 @@ public class WarConfig { @SerializedName("trespassingAggression") public int TRESPASSING_AGGRESSION = 7; + + @SerializedName("numLives") + public int NUM_LIVES = 2; } diff --git a/src/main/java/io/icker/factions/core/InteractionManager.java b/src/main/java/io/icker/factions/core/InteractionManager.java index 4cb26e79..84d8182f 100644 --- a/src/main/java/io/icker/factions/core/InteractionManager.java +++ b/src/main/java/io/icker/factions/core/InteractionManager.java @@ -151,6 +151,8 @@ private static ActionResult checkPermissions(PlayerEntity player, BlockPos posit return ActionResult.PASS; } + if (user.lives == 0) return ActionResult.FAIL; + String dimension = world.getRegistryKey().getValue().toString(); ChunkPos chunkPosition = world.getChunk(position).getPos(); diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index 1fe87a42..3fbbaf75 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -27,7 +27,8 @@ public static void register() { private static void onKilled(ServerPlayerEntity player, DamageSource source) { Faction attackingFaction = User.get(source.getSource().getUuid()).getFaction(); - Faction targetFaction = User.get(player.getUuid()).getFaction(); + User killed = User.get(player.getUuid()); + Faction targetFaction = killed.getFaction(); if (attackingFaction == null || targetFaction == null) return; @@ -43,6 +44,8 @@ private static void onKilled(ServerPlayerEntity player, DamageSource source) { new Message("Your faction is now eligible to go to " + RED + "war" + RESET + " with %s", attackingFaction.getName()).hover("Click to go to war").click(String.format("/f war declare %s", attackingFaction.getName())).send(targetFaction); } + } else if (rel.status == Relationship.Status.WARRING) { + killed.lives--; } } From c71027986e303a4bda36bfa77f0b130a484ad268 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 16:50:19 -0400 Subject: [PATCH 09/15] Improve member command behind the scenes Include lives when hovering over name --- .../icker/factions/command/MemberCommand.java | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/src/main/java/io/icker/factions/command/MemberCommand.java b/src/main/java/io/icker/factions/command/MemberCommand.java index 78c0b508..c2b98377 100644 --- a/src/main/java/io/icker/factions/command/MemberCommand.java +++ b/src/main/java/io/icker/factions/command/MemberCommand.java @@ -16,10 +16,30 @@ import net.minecraft.util.UserCache; import net.minecraft.util.Util; +import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; +import java.util.stream.Collector; public class MemberCommand implements Command { + private static final Collector, Message> COLLECTOR = Collector.of( + ArrayList::new, + (result, user) -> result.add(getName(user)), + (result1, result2) -> { + result1.addAll(result2); + return result1; + }, + (result) -> { + Message message = new Message(""); + if (result.size() == 0) return message; + + result.subList(0, result.size()-1).forEach(message1 -> message.add(message1).add(", ")); + message.add(result.get(result.size()-1)); + return message; + } + ); + + private static UserCache cache; + private int self(CommandContext context) throws CommandSyntaxException { ServerCommandSource source = context.getSource(); ServerPlayerEntity player = source.getPlayer(); @@ -48,36 +68,32 @@ private int any(CommandContext context) throws CommandSynta return members(player, faction); } + private static Message getName(User user) { + return new Message(cache.getByUuid(user.getID()).orElse(new GameProfile(Util.NIL_UUID, "{Uncached Player}")).getName()).hover(String.format("Lives: %d", user.lives)); + } + public static int members(ServerPlayerEntity player, Faction faction) { List users = faction.getUsers(); - UserCache cache = player.getServer().getUserCache(); + cache = player.getServer().getUserCache(); long memberCount = users.stream().filter(u -> u.rank == User.Rank.MEMBER).count(); - String members = Formatting.WHITE + - users.stream() + Message members = users.stream() .filter(u -> u.rank == User.Rank.MEMBER) - .map(user -> cache.getByUuid(user.getID()).orElse(new GameProfile(Util.NIL_UUID, "{Uncached Player}")).getName()) - .collect(Collectors.joining(", ")); + .collect(COLLECTOR).format(Formatting.WHITE); long commanderCount = users.stream().filter(u -> u.rank == User.Rank.COMMANDER).count(); - String commanders = Formatting.WHITE + - users.stream() + Message commanders = users.stream() .filter(u -> u.rank == User.Rank.COMMANDER) - .map(user -> cache.getByUuid(user.getID()).orElse(new GameProfile(Util.NIL_UUID, "{Uncached Player}")).getName()) - .collect(Collectors.joining(", ")); + .collect(COLLECTOR).format(Formatting.WHITE); long leaderCount = users.stream().filter(u -> u.rank == User.Rank.LEADER).count(); - String leaders = Formatting.WHITE + - users.stream() + Message leaders = users.stream() .filter(u -> u.rank == User.Rank.LEADER) - .map(user -> cache.getByUuid(user.getID()).orElse(new GameProfile(Util.NIL_UUID, "{Uncached Player}")).getName()) - .collect(Collectors.joining(", ")); + .collect(COLLECTOR).format(Formatting.WHITE); - String owner = Formatting.WHITE + - users.stream() + Message owner = users.stream() .filter(u -> u.rank == User.Rank.OWNER) - .map(user -> cache.getByUuid(user.getID()).orElse(new GameProfile(Util.NIL_UUID, "{Uncached Player}")).getName()) - .collect(Collectors.joining(", ")); + .collect(COLLECTOR).format(Formatting.WHITE); // generate the --- int numDashes = 32 - faction.getName().length(); From c23e311e9ec5a1b92626a263e9c01d8b0f14b505 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 21:03:56 -0400 Subject: [PATCH 10/15] Create dedicated war persistent --- .../factions/api/persistents/Faction.java | 8 +- .../api/persistents/Relationship.java | 5 +- .../icker/factions/api/persistents/War.java | 142 ++++++++++++++++++ .../factions/command/DeclareCommand.java | 5 - .../icker/factions/command/InfoCommand.java | 10 +- .../io/icker/factions/command/WarCommand.java | 121 ++++++++++----- .../factions/core/InteractionManager.java | 5 +- .../io/icker/factions/core/ServerManager.java | 2 + .../io/icker/factions/core/WarManager.java | 34 ++--- .../java/io/icker/factions/util/Command.java | 21 ++- .../java/io/icker/factions/util/Message.java | 15 +- 11 files changed, 284 insertions(+), 84 deletions(-) create mode 100644 src/main/java/io/icker/factions/api/persistents/War.java diff --git a/src/main/java/io/icker/factions/api/persistents/Faction.java b/src/main/java/io/icker/factions/api/persistents/Faction.java index bbcb4338..4032e6a9 100644 --- a/src/main/java/io/icker/factions/api/persistents/Faction.java +++ b/src/main/java/io/icker/factions/api/persistents/Faction.java @@ -228,6 +228,10 @@ public boolean isMutualAllies(UUID target) { return rel.status == Relationship.Status.ALLY && getReverse(rel).status == Relationship.Status.ALLY; } + public boolean atWarWith(Faction target) { + return War.getByFactions(this, target) != null; + } + public List getMutualAllies() { return relationships.stream().filter(rel -> isMutualAllies(rel.target)).toList(); } @@ -240,8 +244,8 @@ public List getEnemiesOf() { return relationships.stream().filter(rel -> getReverse(rel).status == Relationship.Status.ENEMY).toList(); } - public List getWars() { - return relationships.stream().filter(rel -> getReverse(rel).status == Relationship.Status.WARRING || rel.status == Relationship.Status.WARRING).toList(); + public List getWars() { + return War.getByFaction(this); } public void removeRelationship(UUID target) { diff --git a/src/main/java/io/icker/factions/api/persistents/Relationship.java b/src/main/java/io/icker/factions/api/persistents/Relationship.java index 1a7ba853..54574c38 100644 --- a/src/main/java/io/icker/factions/api/persistents/Relationship.java +++ b/src/main/java/io/icker/factions/api/persistents/Relationship.java @@ -8,8 +8,7 @@ public class Relationship { public enum Status { ALLY, NEUTRAL, - ENEMY, - WARRING + ENEMY } @Field("Target") @@ -21,8 +20,6 @@ public enum Status { @Field("Status") public Status status; - public boolean readyToEnd = false; - public Relationship(UUID target, Status status) { this.target = target; this.status = status; diff --git a/src/main/java/io/icker/factions/api/persistents/War.java b/src/main/java/io/icker/factions/api/persistents/War.java new file mode 100644 index 00000000..7f6e3174 --- /dev/null +++ b/src/main/java/io/icker/factions/api/persistents/War.java @@ -0,0 +1,142 @@ +package io.icker.factions.api.persistents; + +import io.icker.factions.FactionsMod; +import io.icker.factions.database.Database; +import io.icker.factions.database.Field; +import io.icker.factions.database.Name; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.stream.Stream; + +@Name("War") +public class War { + private static final HashMap STORE = Database.load(War.class, War::getID); + + @Field("ID") + private UUID id; + + @Field("Source") + private UUID source; + + @Field("Target") + private UUID target; + + @Field("SourceTeam") + private ArrayList sourceTeam = new ArrayList<>(); + + @Field("TargetTeam") + private ArrayList targetTeam = new ArrayList<>(); + + @Field("Name") + private String name; + + public boolean sourceReadyToEnd = false; + public boolean targetReadyToEnd = false; + + public War(Faction source, Faction target) { + this.source = source.getID(); + this.target = target.getID(); + this.targetTeam.add(target.getID()); + this.sourceTeam.add(source.getID()); + this.id = UUID.randomUUID(); + name = String.format("The %s-%s war", source.getName(), target.getName()); + } + + public War() {} + + public String getKey() { + return id.toString(); + } + + public static War get(UUID id) { + return STORE.get(id); + } + + public static War getByFactions(Faction source, Faction target) { + UUID id = STORE + .keySet() + .stream() + .filter(warKey -> { + War war = get(warKey); + return (war.getSourceTeam().contains(source) && war.getTargetTeam().contains(target)) || (war.getSourceTeam().contains(target) && war.getTargetTeam().contains(source)); + }) + .findFirst() + .orElse(null); + + if (id == null) return null; + return War.get(id); + } + + public static List getByFaction(Faction source) { + return STORE + .keySet() + .stream() + .filter(warKey -> { + War war = get(warKey); + return war.getSourceTeam().contains(source) || war.getTargetTeam().contains(source); + }) + .map(War::get) + .toList(); + + } + + public static War getByName(String name) { + FactionsMod.LOGGER.info(all().size()); + return all().stream().filter(war -> war.getName().equals(name)).findFirst().orElse(null); + } + + public static List all() { + return STORE.keySet().stream().map(War::get).toList(); + } + + public static void add(War war) { + STORE.put(war.getID(), war); + } + + public UUID getID() { + return id; + } + + public void addSource(Faction source) { + this.sourceTeam.add(source.getID()); + } + + public List getSourceTeam() { + return sourceTeam.stream().map(Faction::get).toList(); + } + + public Faction getSource() { + return Faction.get(source); + } + + public void addTarget(Faction target) { + this.targetTeam.add(target.getID()); + } + + public List getTargetTeam() { + return targetTeam.stream().map(Faction::get).toList(); + } + + public Faction getTarget() { + return Faction.get(target); + } + + public String getName() { + return name; + } + + public List getFactions() { + return Stream.concat(getTargetTeam().stream(), getSourceTeam().stream()).toList(); + } + + public void end() { + STORE.remove(this.getID()); + } + + public static void save() { + Database.save(War.class, STORE.values().stream().toList()); + } +} diff --git a/src/main/java/io/icker/factions/command/DeclareCommand.java b/src/main/java/io/icker/factions/command/DeclareCommand.java index f4d816eb..69ada561 100644 --- a/src/main/java/io/icker/factions/command/DeclareCommand.java +++ b/src/main/java/io/icker/factions/command/DeclareCommand.java @@ -52,11 +52,6 @@ private int updateRelationship(CommandContext context, Rela return 0; } - if (sourceFaction.getRelationship(targetFaction.getID()).status == Relationship.Status.WARRING && targetFaction.getRelationship(sourceFaction.getID()).status == Relationship.Status.WARRING) { - new Message("Both factions must agree to end the war").fail().send(player, false); - return 0; - } - Relationship rel = new Relationship(targetFaction.getID(), status); Relationship rev = targetFaction.getRelationship(sourceFaction.getID()); sourceFaction.setRelationship(rel); diff --git a/src/main/java/io/icker/factions/command/InfoCommand.java b/src/main/java/io/icker/factions/command/InfoCommand.java index 17126302..644ff5ce 100644 --- a/src/main/java/io/icker/factions/command/InfoCommand.java +++ b/src/main/java/io/icker/factions/command/InfoCommand.java @@ -8,6 +8,7 @@ import io.icker.factions.FactionsMod; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.User; +import io.icker.factions.api.persistents.War; import io.icker.factions.util.Command; import io.icker.factions.util.Message; import net.minecraft.server.command.CommandManager; @@ -73,9 +74,8 @@ public static int info(ServerPlayerEntity player, Faction faction) { .map(fac -> fac.getColor() + fac.getName()) .collect(Collectors.joining(Formatting.GRAY + ", ")); - String atWarWith = Formatting.GRAY + faction.getWars().stream() - .map(rel -> Faction.get(rel.target)) - .map(fac -> fac.getColor() + fac.getName()) + String warsJoined = Formatting.GRAY + faction.getWars().stream() + .map(War::getName) .collect(Collectors.joining(Formatting.GRAY + ", ")); int requiredPower = faction.getClaims().size() * FactionsMod.CONFIG.POWER.CLAIM_WEIGHT; @@ -106,8 +106,8 @@ public static int info(ServerPlayerEntity player, Faction faction) { new Message(Formatting.RED + "Enemies (" + Formatting.WHITE + faction.getEnemiesWith().size() + Formatting.RED + "): ") .add(enemiesWith) .send(player, false); - new Message(Formatting.DARK_RED + "At War (" + Formatting.WHITE + faction.getWars().size() + Formatting.DARK_RED + "): ") - .add(atWarWith) + new Message(Formatting.DARK_RED + "Wars in (" + Formatting.WHITE + faction.getWars().size() + Formatting.DARK_RED + "): ") + .add(warsJoined) .send(player, false); return 1; diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java index 7968c35e..c1aafd95 100644 --- a/src/main/java/io/icker/factions/command/WarCommand.java +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -5,9 +5,8 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import io.icker.factions.FactionsMod; import io.icker.factions.api.persistents.Faction; -import io.icker.factions.api.persistents.Relationship; import io.icker.factions.api.persistents.User; -import io.icker.factions.core.WarManager; +import io.icker.factions.api.persistents.War; import io.icker.factions.util.Command; import io.icker.factions.util.Message; import net.minecraft.server.PlayerManager; @@ -15,8 +14,6 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import static io.icker.factions.api.persistents.Relationship.Status.NEUTRAL; -import static io.icker.factions.api.persistents.Relationship.Status.WARRING; import static net.minecraft.util.Formatting.RED; import static net.minecraft.util.Formatting.RESET; @@ -42,18 +39,12 @@ private int declare (CommandContext context) { return 0; } - if (sourceFaction.getRelationship(targetFaction.getID()).status == WARRING) { + if (War.getByFactions(sourceFaction, targetFaction) != null) { new Message("You are already at war with that faction").fail().send(player, false); return 0; } - if (!WarManager.eligibleForWar(sourceFaction, targetFaction)) { - new Message("You cannot currently go to war with that faction").fail().send(player, false); - return 0; - } - - Relationship rel = new Relationship(targetFaction.getID(), WARRING); - sourceFaction.setRelationship(rel); + War.add(new War(sourceFaction, targetFaction)); new Message("You have declared " + RED + "war" + RESET + " on " + targetFaction.getName()).send(sourceFaction); @@ -70,56 +61,98 @@ private int declare (CommandContext context) { return 1; } - private int end (CommandContext context) { - String name = StringArgumentType.getString(context, "faction"); + private int join (CommandContext context) { + if (FactionsMod.CONFIG.WAR == null) return 0; + String name = StringArgumentType.getString(context, "war"); ServerCommandSource source = context.getSource(); ServerPlayerEntity player = source.getPlayer(); - Faction targetFaction = Faction.getByName(name); + War war = War.getByName(name); + FactionsMod.LOGGER.info(war); + Faction faction = User.get(player.getUuid()).getFaction(); - if (targetFaction == null) { - new Message("Cannot end a war with a faction that does not exist").fail().send(player, false); + if (war == null) { + new Message("Couldn't find that war").fail().send(player, false); return 0; } - Faction sourceFaction = Command.getUser(player).getFaction(); + boolean alliesOnTarget = war.getTargetTeam().stream().anyMatch(faction1 -> faction.isMutualAllies(faction1.getID())); + boolean alliesOnSource = war.getSourceTeam().stream().anyMatch(faction1 -> faction.isMutualAllies(faction1.getID())); - if (sourceFaction.equals(targetFaction)) { - new Message("Cannot end a war with yourself").fail().send(player, false); + if (alliesOnSource && alliesOnTarget) { + new Message("Since you have allies on both sides you cannot take part in this war").fail().send(player, false); return 0; } - Relationship rel = sourceFaction.getRelationship(targetFaction.getID()); - Relationship rev = sourceFaction.getReverse(rel); + String teamName; - if (rel.status != WARRING && rev.status != WARRING) { - new Message("You are not at war with that faction").fail().send(player, false); + if (alliesOnTarget) { + war.addTarget(faction); + teamName = war.getTarget().getName(); + } else if (alliesOnSource) { + war.addSource(faction); + teamName = war.getSource().getName(); + } else { + new Message("You must be allied with someone in that war to join").fail().send(player, false); return 0; } - if (!rev.readyToEnd) { - rel.readyToEnd = true; + new Message("You have joined %s in the %s", teamName, war.getName()).send(faction); - PlayerManager playerManager = player.getServer().getPlayerManager(); - sourceFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + PlayerManager playerManager = player.getServer().getPlayerManager(); + faction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + + faction.getUsers().forEach(user -> user.lives = FactionsMod.CONFIG.WAR.NUM_LIVES); + + new Message("%s have joined the war", faction.getName()) + .send(war); + + return 1; + } + + private int end (CommandContext context) { + String name = StringArgumentType.getString(context, "war"); + ServerCommandSource source = context.getSource(); + ServerPlayerEntity player = source.getPlayer(); + + War war = War.getByName(name); + Faction faction = User.get(player.getUuid()).getFaction(); + + if (war == null) { + new Message("Could not find the war").fail().send(player, false); + return 0; + } + boolean isSource = war.getSource().equals(faction); - new Message("%s must also agree to end the war (they have been asked if they want to end it)", targetFaction.getName()).send(player, false); - new Message("%s would like to end the war", sourceFaction.getName()).hover("Click to end the war").click(String.format("/f war end %s", sourceFaction.getName())).send(targetFaction); + if (!isSource && !war.getTarget().equals(faction)) { + new Message("You cannot end the war").fail().send(player, false); return 0; } - rev.readyToEnd = false; + Faction other = isSource ? war.getTarget() : war.getSource(); + + if ((isSource && !war.targetReadyToEnd) || (!isSource && !war.sourceReadyToEnd)) { + if (isSource) war.sourceReadyToEnd = true; + else war.targetReadyToEnd = true; - rel.status = NEUTRAL; - rev.status = NEUTRAL; + PlayerManager playerManager = player.getServer().getPlayerManager(); + other.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); - new Message("You are no longer at war with " + targetFaction.getName()).send(sourceFaction); - new Message(sourceFaction.getName() + " has ended the war").send(targetFaction); + + new Message("%s must also agree to end the war (they have been asked if they want to end it)", other.getName()).send(player, false); + new Message("%s would like to end the war", faction.getName()).hover("Click to end the war").click(String.format("/f war end %s", war.getName())).send(other); + return 0; + } + + war.end(); + + new Message("You are no longer at war with " + other.getName()).send(faction); + new Message(faction.getName() + " has ended the war").send(other); PlayerManager playerManager = player.getServer().getPlayerManager(); - sourceFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); - targetFaction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + faction.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); + other.sendCommandTree(playerManager, user -> (user.rank == User.Rank.LEADER || user.rank == User.Rank.OWNER) && playerManager.getPlayer(user.getID()) != null); return 1; } @@ -128,21 +161,27 @@ private int end (CommandContext context) { public LiteralCommandNode getNode() { return CommandManager .literal("war") - .requires(Requires.multiple(Requires.isLeader(), (source) -> WarManager.eligibleForWar(source) || Requires.require(user -> !user.getFaction().getWars().isEmpty()).test(source))) + .requires(Requires.multiple(Requires.isLeader(), (source) -> FactionsMod.CONFIG.WAR != null)) .then( CommandManager.literal("declare") - .requires(WarManager::eligibleForWar) .then( CommandManager.argument("faction", StringArgumentType.greedyString()) .suggests(Suggests.eligibleForWar()) .executes(this::declare) ) ) + .then( + CommandManager.literal("join") + .then( + CommandManager.argument("war", StringArgumentType.greedyString()) + .suggests(Suggests.joinableWars()) + .executes(this::join) + ) + ) .then( CommandManager.literal("end") - .requires(Requires.require(user -> !user.getFaction().getWars().isEmpty())) .then( - CommandManager.argument("faction", StringArgumentType.greedyString()) + CommandManager.argument("war", StringArgumentType.greedyString()) .suggests(Suggests.atWar()) .executes(this::end) ) diff --git a/src/main/java/io/icker/factions/core/InteractionManager.java b/src/main/java/io/icker/factions/core/InteractionManager.java index 84d8182f..e8a16273 100644 --- a/src/main/java/io/icker/factions/core/InteractionManager.java +++ b/src/main/java/io/icker/factions/core/InteractionManager.java @@ -4,7 +4,6 @@ import io.icker.factions.api.events.PlayerEvents; import io.icker.factions.api.persistents.Claim; import io.icker.factions.api.persistents.Faction; -import io.icker.factions.api.persistents.Relationship; import io.icker.factions.api.persistents.User; import io.icker.factions.mixin.BucketItemMixin; import io.icker.factions.mixin.ItemMixin; @@ -151,7 +150,7 @@ private static ActionResult checkPermissions(PlayerEntity player, BlockPos posit return ActionResult.PASS; } - if (user.lives == 0) return ActionResult.FAIL; + if (user.lives <= 0) return ActionResult.FAIL; String dimension = world.getRegistryKey().getValue().toString(); ChunkPos chunkPosition = world.getChunk(position).getPos(); @@ -175,7 +174,7 @@ private static ActionResult checkPermissions(PlayerEntity player, BlockPos posit return ActionResult.PASS; } - if (userFaction.getRelationship(claimFaction.getID()).status == Relationship.Status.WARRING) { + if (userFaction.atWarWith(claimFaction)) { return ActionResult.PASS; } diff --git a/src/main/java/io/icker/factions/core/ServerManager.java b/src/main/java/io/icker/factions/core/ServerManager.java index 6b5fa080..095d078d 100644 --- a/src/main/java/io/icker/factions/core/ServerManager.java +++ b/src/main/java/io/icker/factions/core/ServerManager.java @@ -4,6 +4,7 @@ import io.icker.factions.api.persistents.Claim; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.User; +import io.icker.factions.api.persistents.War; import io.icker.factions.util.Message; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; @@ -21,6 +22,7 @@ private static void save(MinecraftServer server) { Claim.save(); Faction.save(); User.save(); + War.save(); } private static void playerJoin(ServerPlayNetworkHandler handler, PacketSender sender, MinecraftServer server) { diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index 3fbbaf75..27d28fe4 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -3,10 +3,7 @@ import io.icker.factions.FactionsMod; import io.icker.factions.api.events.PlayerEvents; import io.icker.factions.api.events.RelationshipEvents; -import io.icker.factions.api.persistents.Claim; -import io.icker.factions.api.persistents.Faction; -import io.icker.factions.api.persistents.Relationship; -import io.icker.factions.api.persistents.User; +import io.icker.factions.api.persistents.*; import io.icker.factions.api.persistents.User.Rank; import io.icker.factions.util.Message; import net.minecraft.entity.damage.DamageSource; @@ -35,7 +32,7 @@ private static void onKilled(ServerPlayerEntity player, DamageSource source) { Relationship rel = attackingFaction.getRelationship(targetFaction.getID()); Relationship rev = attackingFaction.getReverse(rel); - if (rel.status == Relationship.Status.ENEMY && rev.status == Relationship.Status.ENEMY && FactionsMod.CONFIG.WAR != null) { + if (rel.status == Relationship.Status.ENEMY && rev.status == Relationship.Status.ENEMY && FactionsMod.CONFIG.WAR != null && !targetFaction.atWarWith(attackingFaction)) { rev.aggression += FactionsMod.CONFIG.WAR.ATTACK_AGGRESSION; if (rev.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL) { PlayerManager playerManager = player.getServer().getPlayerManager(); @@ -44,7 +41,7 @@ private static void onKilled(ServerPlayerEntity player, DamageSource source) { new Message("Your faction is now eligible to go to " + RED + "war" + RESET + " with %s", attackingFaction.getName()).hover("Click to go to war").click(String.format("/f war declare %s", attackingFaction.getName())).send(targetFaction); } - } else if (rel.status == Relationship.Status.WARRING) { + } else if (War.getByFactions(attackingFaction, targetFaction) != null) { killed.lives--; } } @@ -83,28 +80,29 @@ private static void onMove(ServerPlayerEntity player) { user.isTrespassing = claim.getFaction().getRelationship(user.getFaction().getID()).status == Relationship.Status.ENEMY; } - public static boolean eligibleForWar(ServerCommandSource source) { + public static boolean eligibleToStartWar(ServerCommandSource source) { if (FactionsMod.CONFIG.WAR == null) return false; ServerPlayerEntity player = source.getPlayer(); if (source.getPlayer() == null) return false; User user = User.get(player.getUuid()); - if (!user.isInFaction()) return false; - Faction faction = user.getFaction(); + if (!user.isInFaction()) return false; - return - faction.getEnemiesWith().stream().anyMatch(rel -> (rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL || - faction.getReverse(rel).status == Relationship.Status.WARRING) && rel.status != Relationship.Status.WARRING) || - faction.getMutualAllies().stream().anyMatch(rel -> !Faction.get(rel.target).getWars().isEmpty()); + return user.getFaction().getEnemiesWith().stream().anyMatch(rel -> (rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL)); } - public static boolean eligibleForWar(Faction source, Faction target) { + public static boolean eligibleToJoinWar(ServerCommandSource source) { if (FactionsMod.CONFIG.WAR == null) return false; - return - target.getRelationship(source.getID()).status == Relationship.Status.WARRING - || source.getRelationship(target.getID()).aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL - || source.getMutualAllies().stream().anyMatch(rel -> Faction.get(rel.target).getRelationship(target.getID()).status == Relationship.Status.WARRING); + + ServerPlayerEntity player = source.getPlayer(); + if (source.getPlayer() == null) return false; + + User user = User.get(player.getUuid()); + + if (!user.isInFaction()) return false; + + return War.all().stream().anyMatch(war -> user.getFaction().getMutualAllies().stream().map(rel -> Faction.get(rel.target)).anyMatch(faction -> war.getSourceTeam().contains(faction) || war.getTargetTeam().contains(faction))); } } diff --git a/src/main/java/io/icker/factions/util/Command.java b/src/main/java/io/icker/factions/util/Command.java index d159ac4e..af9de628 100644 --- a/src/main/java/io/icker/factions/util/Command.java +++ b/src/main/java/io/icker/factions/util/Command.java @@ -5,7 +5,7 @@ import io.icker.factions.FactionsMod; import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.User; -import io.icker.factions.core.WarManager; +import io.icker.factions.api.persistents.War; import me.lucko.fabric.api.permissions.v0.Permissions; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.command.ServerCommandSource; @@ -90,7 +90,18 @@ public static SuggestionProvider atWar() { return suggest(user -> user.getFaction().getWars() .stream() - .map(rel -> Faction.get(rel.target).getName()) + .map(War::getName) + .toArray(String[]::new) + ); + } + + public static SuggestionProvider joinableWars() { + return suggest(user -> + user.getFaction().getMutualAllies() + .stream() + .map(rel -> Faction.get(rel.target)) + .filter(faction -> War.getByFaction(faction) != null) + .map(Faction::getName) .toArray(String[]::new) ); } @@ -98,10 +109,10 @@ public static SuggestionProvider atWar() { public static SuggestionProvider eligibleForWar() { return suggest(user -> { Faction source = user.getFaction(); - return Faction.all() + return source.getEnemiesWith() .stream() - .filter(faction -> WarManager.eligibleForWar(source, faction)) - .map(Faction::getName) + .filter(rel -> rel.aggression >= FactionsMod.CONFIG.WAR.AGGRESSION_LEVEL) + .map(rel -> Faction.get(rel.target).getName()) .toArray(String[]::new); } ); diff --git a/src/main/java/io/icker/factions/util/Message.java b/src/main/java/io/icker/factions/util/Message.java index cffc35cd..259b4c7a 100644 --- a/src/main/java/io/icker/factions/util/Message.java +++ b/src/main/java/io/icker/factions/util/Message.java @@ -2,6 +2,7 @@ import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.User; +import io.icker.factions.api.persistents.War; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.PlayerManager; import net.minecraft.server.network.ServerPlayerEntity; @@ -72,6 +73,14 @@ public Message send(Faction faction) { return this; } + public Message send(War war) { + Message message = this.prependMessage(new Message(war.getName()).format(Formatting.RED)); + for (Faction faction : war.getFactions()) { + message.sendToFactionChat(faction); + } + return this; + } + public void sendToGlobalChat() { for (ServerPlayerEntity player : manager.getPlayerList()) { User.ChatMode option = User.get(player.getUuid()).chat; @@ -87,8 +96,12 @@ public void sendToFactionChat(Faction faction) { } public Message prependFaction(Faction faction) { + return prependMessage(new Message(faction.getColor().toString() + Formatting.BOLD + faction.getName()).hover(faction.getDescription())); + } + + public Message prependMessage(Message message) { text = new Message("") - .add(new Message(faction.getColor().toString() + Formatting.BOLD + faction.getName()).hover(faction.getDescription())) + .add(message) .filler("ยป") .raw() .append(text); From 2136329150530f3ddd7cdb2456a4342c863319c1 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 21:10:23 -0400 Subject: [PATCH 11/15] Fix join command suggestions --- .../java/io/icker/factions/core/WarManager.java | 2 +- src/main/java/io/icker/factions/util/Command.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index 27d28fe4..dbf4786f 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -103,6 +103,6 @@ public static boolean eligibleToJoinWar(ServerCommandSource source) { if (!user.isInFaction()) return false; - return War.all().stream().anyMatch(war -> user.getFaction().getMutualAllies().stream().map(rel -> Faction.get(rel.target)).anyMatch(faction -> war.getSourceTeam().contains(faction) || war.getTargetTeam().contains(faction))); + return War.all().stream().anyMatch(war -> user.getFaction().getMutualAllies().stream().map(rel -> Faction.get(rel.target)).anyMatch(faction -> war.getSourceTeam().contains(faction) || war.getTargetTeam().contains(faction))); } } diff --git a/src/main/java/io/icker/factions/util/Command.java b/src/main/java/io/icker/factions/util/Command.java index af9de628..8042f909 100644 --- a/src/main/java/io/icker/factions/util/Command.java +++ b/src/main/java/io/icker/factions/util/Command.java @@ -96,13 +96,16 @@ public static SuggestionProvider atWar() { } public static SuggestionProvider joinableWars() { - return suggest(user -> + return suggest(user -> War.all() + .stream() + .filter(war -> user.getFaction().getMutualAllies() - .stream() - .map(rel -> Faction.get(rel.target)) - .filter(faction -> War.getByFaction(faction) != null) - .map(Faction::getName) - .toArray(String[]::new) + .stream() + .map(rel -> Faction.get(rel.target)) + .anyMatch(faction -> war.getSourceTeam().contains(faction) || war.getTargetTeam().contains(faction)) + ).map(War::getName) + .toArray(String[]::new) + ); } From 40cb3a82dea7f281aa9fae96ee3e855a38c9f5c4 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 21:11:01 -0400 Subject: [PATCH 12/15] Stop declaring war back message appearing --- src/main/java/io/icker/factions/command/WarCommand.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java index c1aafd95..daf07064 100644 --- a/src/main/java/io/icker/factions/command/WarCommand.java +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -54,8 +54,6 @@ private int declare (CommandContext context) { sourceFaction.getUsers().forEach(user -> user.lives = FactionsMod.CONFIG.WAR.NUM_LIVES); new Message(sourceFaction.getName() + " have declared " + RED + "war" + RESET + " on you") - .hover("Click to declare war back") - .click(String.format("/factions war declare %s", sourceFaction.getName())) .send(targetFaction); return 1; From 0b07995c02ad1f533b53019ba45b6e9079cbe31a Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 21:14:22 -0400 Subject: [PATCH 13/15] Fix lives --- .../io/icker/factions/api/persistents/User.java | 3 ++- .../io/icker/factions/api/persistents/War.java | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/icker/factions/api/persistents/User.java b/src/main/java/io/icker/factions/api/persistents/User.java index c6bf44e0..0a705e9f 100644 --- a/src/main/java/io/icker/factions/api/persistents/User.java +++ b/src/main/java/io/icker/factions/api/persistents/User.java @@ -1,5 +1,6 @@ package io.icker.factions.api.persistents; +import io.icker.factions.FactionsMod; import io.icker.factions.api.events.FactionEvents; import io.icker.factions.database.Database; import io.icker.factions.database.Field; @@ -54,7 +55,7 @@ public enum SoundMode { public SoundMode sounds = SoundMode.ALL; @Field("Lives") - public int lives = -1; + public int lives = FactionsMod.CONFIG.WAR != null ? FactionsMod.CONFIG.WAR.NUM_LIVES : 3; public boolean autoclaim = false; public boolean bypass = false; diff --git a/src/main/java/io/icker/factions/api/persistents/War.java b/src/main/java/io/icker/factions/api/persistents/War.java index 7f6e3174..73f93438 100644 --- a/src/main/java/io/icker/factions/api/persistents/War.java +++ b/src/main/java/io/icker/factions/api/persistents/War.java @@ -43,6 +43,12 @@ public War(Faction source, Faction target) { this.sourceTeam.add(source.getID()); this.id = UUID.randomUUID(); name = String.format("The %s-%s war", source.getName(), target.getName()); + + for (Faction faction : getFactions()) { + for (User user : faction.getUsers()) { + user.lives = FactionsMod.CONFIG.WAR.NUM_LIVES; + } + } } public War() {} @@ -101,6 +107,9 @@ public UUID getID() { } public void addSource(Faction source) { + for (User user : source.getUsers()) { + user.lives = FactionsMod.CONFIG.WAR.NUM_LIVES; + } this.sourceTeam.add(source.getID()); } @@ -113,6 +122,9 @@ public Faction getSource() { } public void addTarget(Faction target) { + for (User user : target.getUsers()) { + user.lives = FactionsMod.CONFIG.WAR.NUM_LIVES; + } this.targetTeam.add(target.getID()); } @@ -134,6 +146,11 @@ public List getFactions() { public void end() { STORE.remove(this.getID()); + for (Faction faction : getFactions()) { + for (User user : faction.getUsers()) { + user.lives = FactionsMod.CONFIG.WAR.NUM_LIVES; + } + } } public static void save() { From a66670f6c0a5e1ef3d46aced0751da6dc8b0f823 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 21:15:30 -0400 Subject: [PATCH 14/15] Rest aggression when a war starts --- src/main/java/io/icker/factions/command/WarCommand.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java index daf07064..abd7a997 100644 --- a/src/main/java/io/icker/factions/command/WarCommand.java +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -44,6 +44,9 @@ private int declare (CommandContext context) { return 0; } + targetFaction.getRelationship(sourceFaction.getID()).aggression = 0; + sourceFaction.getRelationship(targetFaction.getID()).aggression = 0; + War.add(new War(sourceFaction, targetFaction)); new Message("You have declared " + RED + "war" + RESET + " on " + targetFaction.getName()).send(sourceFaction); From ed1894790f9868edb265caabd32ddd00a12752f4 Mon Sep 17 00:00:00 2001 From: BlueZeeKing Date: Sun, 31 Jul 2022 21:20:20 -0400 Subject: [PATCH 15/15] Fix command requirements --- .../io/icker/factions/command/WarCommand.java | 6 +++++- .../java/io/icker/factions/core/WarManager.java | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/icker/factions/command/WarCommand.java b/src/main/java/io/icker/factions/command/WarCommand.java index abd7a997..415a85f4 100644 --- a/src/main/java/io/icker/factions/command/WarCommand.java +++ b/src/main/java/io/icker/factions/command/WarCommand.java @@ -7,6 +7,7 @@ import io.icker.factions.api.persistents.Faction; import io.icker.factions.api.persistents.User; import io.icker.factions.api.persistents.War; +import io.icker.factions.core.WarManager; import io.icker.factions.util.Command; import io.icker.factions.util.Message; import net.minecraft.server.PlayerManager; @@ -162,9 +163,10 @@ private int end (CommandContext context) { public LiteralCommandNode getNode() { return CommandManager .literal("war") - .requires(Requires.multiple(Requires.isLeader(), (source) -> FactionsMod.CONFIG.WAR != null)) + .requires(Requires.multiple(Requires.isLeader(), (source) -> FactionsMod.CONFIG.WAR != null, Requires.hasPerms("factions.war", 0))) .then( CommandManager.literal("declare") + .requires(Requires.multiple(WarManager::eligibleToStartWar, Requires.hasPerms("factions.war.declare", 0))) .then( CommandManager.argument("faction", StringArgumentType.greedyString()) .suggests(Suggests.eligibleForWar()) @@ -173,6 +175,7 @@ public LiteralCommandNode getNode() { ) .then( CommandManager.literal("join") + .requires(Requires.multiple(WarManager::eligibleToJoinWar, Requires.hasPerms("factions.war.join", 0))) .then( CommandManager.argument("war", StringArgumentType.greedyString()) .suggests(Suggests.joinableWars()) @@ -181,6 +184,7 @@ public LiteralCommandNode getNode() { ) .then( CommandManager.literal("end") + .requires(Requires.multiple(WarManager::eligibleToEndWar, Requires.hasPerms("factions.war.end", 0))) .then( CommandManager.argument("war", StringArgumentType.greedyString()) .suggests(Suggests.atWar()) diff --git a/src/main/java/io/icker/factions/core/WarManager.java b/src/main/java/io/icker/factions/core/WarManager.java index dbf4786f..4226288a 100644 --- a/src/main/java/io/icker/factions/core/WarManager.java +++ b/src/main/java/io/icker/factions/core/WarManager.java @@ -105,4 +105,19 @@ public static boolean eligibleToJoinWar(ServerCommandSource source) { return War.all().stream().anyMatch(war -> user.getFaction().getMutualAllies().stream().map(rel -> Faction.get(rel.target)).anyMatch(faction -> war.getSourceTeam().contains(faction) || war.getTargetTeam().contains(faction))); } + + public static boolean eligibleToEndWar(ServerCommandSource source) { + if (FactionsMod.CONFIG.WAR == null) return false; + + ServerPlayerEntity player = source.getPlayer(); + if (source.getPlayer() == null) return false; + + User user = User.get(player.getUuid()); + + if (!user.isInFaction()) return false; + + Faction faction = user.getFaction(); + + return faction.getWars().stream().anyMatch(war -> war.getSource().equals(faction) || war.getTarget().equals(faction)); + } }