diff --git a/src/main/java/xyz/nucleoid/plasmid/api/game/GameTexts.java b/src/main/java/xyz/nucleoid/plasmid/api/game/GameTexts.java index cd2e7813..84ebf563 100644 --- a/src/main/java/xyz/nucleoid/plasmid/api/game/GameTexts.java +++ b/src/main/java/xyz/nucleoid/plasmid/api/game/GameTexts.java @@ -156,6 +156,14 @@ public static MutableText inOtherGame() { public static MutableText notAllowed() { return Text.translatable("text.plasmid.join_result.not_allowed"); } + + public static MutableText spectatorsOnly() { + return Text.translatable("text.plasmid.join_result.spectators_only"); + } + + public static MutableText participantsOnly() { + return Text.translatable("text.plasmid.join_result.participants_only"); + } } public static final class Kick { diff --git a/src/main/java/xyz/nucleoid/plasmid/api/game/player/JoinOffer.java b/src/main/java/xyz/nucleoid/plasmid/api/game/player/JoinOffer.java index 96eee49f..b7ea118d 100644 --- a/src/main/java/xyz/nucleoid/plasmid/api/game/player/JoinOffer.java +++ b/src/main/java/xyz/nucleoid/plasmid/api/game/player/JoinOffer.java @@ -8,6 +8,7 @@ import java.util.Set; import java.util.UUID; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -83,4 +84,54 @@ default JoinOfferResult.Accept accept() { default JoinOfferResult pass() { return JoinOfferResult.PASS; } + + /** + * Returns an offer result that accepts this offer only if the intent is to spectate. + *

+ * This function does not do anything on its own, but its result must be returned within a + * {@link GamePlayerEvents#OFFER} listener. + * + * @return an "accept" offer result for spectators and "reject" offer result for participants + */ + default JoinOfferResult acceptSpectators() { + return this.acceptSpectatorsOrElse((x) -> x.reject(GameTexts.Join.spectatorsOnly())); + } + + /** + * Returns an offer result that accepts this offer only if the intent is to spectate. + * Others will be resolved in the orElse method. + *

+ * This function does not do anything on its own, but its result must be returned within a + * {@link GamePlayerEvents#OFFER} listener. + * + * @return an "accept" offer result for spectators and "reject" offer result for participants + */ + default JoinOfferResult acceptSpectatorsOrElse(Function function) { + return this.intent() == JoinIntent.SPECTATE ? this.accept() : function.apply(this); + } + + /** + * Returns an offer result that accepts this offer only if the intent is to participate / play. + *

+ * This function does not do anything on its own, but its result must be returned within a + * {@link GamePlayerEvents#OFFER} listener. + * + * @return an "accept" offer result for participants and "reject" offer result for spectators + */ + default JoinOfferResult acceptParticipants() { + return this.acceptParticipantsOrElse((x) -> x.reject(GameTexts.Join.participantsOnly())); + } + + /** + * Returns an offer result that accepts this offer only if the intent is to participate / play. + * Others will be resolved in the orElse method. + *

+ * This function does not do anything on its own, but its result must be returned within a + * {@link GamePlayerEvents#OFFER} listener. + * + * @return an "accept" offer result for spectators and "reject" offer result for participants + */ + default JoinOfferResult acceptParticipantsOrElse(Function function) { + return this.intent() == JoinIntent.PLAY ? this.accept() : function.apply(this); + } } diff --git a/src/main/java/xyz/nucleoid/plasmid/api/game/player/MutablePlayerSet.java b/src/main/java/xyz/nucleoid/plasmid/api/game/player/MutablePlayerSet.java index a0508d64..da6c5f28 100644 --- a/src/main/java/xyz/nucleoid/plasmid/api/game/player/MutablePlayerSet.java +++ b/src/main/java/xyz/nucleoid/plasmid/api/game/player/MutablePlayerSet.java @@ -4,20 +4,32 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import xyz.nucleoid.plasmid.api.game.GameSpace; import xyz.nucleoid.plasmid.api.util.PlayerRef; import java.util.Iterator; import java.util.Set; import java.util.UUID; +import java.util.function.Function; public final class MutablePlayerSet implements PlayerSet { - private final MinecraftServer server; + private final Function playerGetter; private final Set players = new ObjectOpenHashSet<>(); public MutablePlayerSet(MinecraftServer server) { - this.server = server; + this.playerGetter = server.getPlayerManager()::getPlayer; + } + + public MutablePlayerSet(ServerWorld world) { + this.playerGetter = (uuid) -> world.getPlayerByUuid(uuid) instanceof ServerPlayerEntity player ? player : null; + } + + public MutablePlayerSet(GameSpace gameSpace) { + this.playerGetter = gameSpace.getPlayers()::getEntity; } public void clear() { @@ -47,7 +59,7 @@ public boolean remove(UUID id) { @Nullable @Override public ServerPlayerEntity getEntity(UUID id) { - return this.players.contains(id) ? this.server.getPlayerManager().getPlayer(id) : null; + return this.players.contains(id) ? this.playerGetter.apply(id) : null; } @Override @@ -56,8 +68,8 @@ public boolean contains(UUID id) { } @Override - public Iterator iterator() { - var playerManager = this.server.getPlayerManager(); + public @NotNull Iterator iterator() { + var playerGetter = this.playerGetter; var ids = this.players.iterator(); return new AbstractIterator<>() { @@ -65,7 +77,7 @@ public Iterator iterator() { protected ServerPlayerEntity computeNext() { while (ids.hasNext()) { var id = ids.next(); - var player = playerManager.getPlayer(id); + var player = playerGetter.apply(id); if (player != null) { return player; } diff --git a/src/main/java/xyz/nucleoid/plasmid/api/game/player/PlayerSet.java b/src/main/java/xyz/nucleoid/plasmid/api/game/player/PlayerSet.java index 0d8a3103..c257dc43 100644 --- a/src/main/java/xyz/nucleoid/plasmid/api/game/player/PlayerSet.java +++ b/src/main/java/xyz/nucleoid/plasmid/api/game/player/PlayerSet.java @@ -3,6 +3,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.plasmid.api.util.PlayerRef; import xyz.nucleoid.plasmid.impl.player.EmptyPlayerSet; @@ -104,5 +105,6 @@ default MutablePlayerSet copy(MinecraftServer server) { * @return an iterator over the online {@link ServerPlayerEntity} within this {@link PlayerSet} */ @Override + @NotNull Iterator iterator(); } diff --git a/src/main/java/xyz/nucleoid/plasmid/impl/game/manager/ManagedGameSpacePlayers.java b/src/main/java/xyz/nucleoid/plasmid/impl/game/manager/ManagedGameSpacePlayers.java index ce981a10..23ff114f 100644 --- a/src/main/java/xyz/nucleoid/plasmid/impl/game/manager/ManagedGameSpacePlayers.java +++ b/src/main/java/xyz/nucleoid/plasmid/impl/game/manager/ManagedGameSpacePlayers.java @@ -1,6 +1,7 @@ package xyz.nucleoid.plasmid.impl.game.manager; import net.minecraft.server.network.ServerPlayerEntity; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.plasmid.api.game.player.*; import xyz.nucleoid.plasmid.impl.player.LocalJoinAcceptor; @@ -174,7 +175,7 @@ public int size() { } @Override - public Iterator iterator() { + public @NotNull Iterator iterator() { return this.set.iterator(); } diff --git a/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerPlayerSet.java b/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerPlayerSet.java index aebe9d00..c54b8e2f 100644 --- a/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerPlayerSet.java +++ b/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerPlayerSet.java @@ -2,6 +2,7 @@ import net.minecraft.server.PlayerManager; import net.minecraft.server.network.ServerPlayerEntity; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.plasmid.api.game.player.PlayerSet; @@ -26,7 +27,7 @@ public int size() { } @Override - public Iterator iterator() { + public @NotNull Iterator iterator() { return this.players.getPlayerList().iterator(); } } diff --git a/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerWorldPlayerSet.java b/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerWorldPlayerSet.java index b87ea5d7..afe61428 100644 --- a/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerWorldPlayerSet.java +++ b/src/main/java/xyz/nucleoid/plasmid/impl/player/ServerWorldPlayerSet.java @@ -2,6 +2,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.plasmid.api.game.player.PlayerSet; @@ -26,7 +27,7 @@ public int size() { } @Override - public Iterator iterator() { + public @NotNull Iterator iterator() { return this.world.getPlayers().iterator(); } } diff --git a/src/main/resources/data/plasmid/lang/en_us.json b/src/main/resources/data/plasmid/lang/en_us.json index d0245fb9..f4294ab5 100644 --- a/src/main/resources/data/plasmid/lang/en_us.json +++ b/src/main/resources/data/plasmid/lang/en_us.json @@ -68,6 +68,8 @@ "text.plasmid.join_result.in_other_game": "You must %s before joining another game!", "text.plasmid.join_result.in_other_game.leave_this_game": "leave this game", "text.plasmid.join_result.not_allowed": "You are not allowed to join this game!", + "text.plasmid.join_result.spectators_only": "You are not allowed to participate in this game!", + "text.plasmid.join_result.participants_only": "You are not allowed to spectate this game!", "text.plasmid.map_workspace.workspace_not_found": "Map with id '%s' was not found!", "text.plasmid.map.bounds.get": "The bounds for the workspace are %s to %s", "text.plasmid.map.bounds.set": "Updated bounds for workspace",