Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove player entity context from player offers #298

Merged
merged 13 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,10 @@ However! Before we give functionality to our brilliant example game, we need to
An example offer listener may look like:
```java
activity.listen(GamePlayerEvents.OFFER, offer -> {
ServerPlayerEntity player = offer.player();
return offer.accept(world, new Vec3d(0.0, 64.0, 0.0))
.and(() -> {
player.changeGameMode(GameMode.ADVENTURE);
});
return offer.accept(world, new Vec3d(0.0, 65.0, 0.0))
.thenRunForEach(player -> {
player.changeGameMode(GameMode.ADVENTURE);
});
});
```

Expand Down Expand Up @@ -271,9 +270,8 @@ public final class ExampleGame {
}

private PlayerOfferResult onPlayerOffer(PlayerOffer offer) {
ServerPlayerEntity player = offer.player();
return offer.accept(this.world, new Vec3d(0.0, 64.0, 0.0))
.and(() -> {
return offer.accept(this.world, new Vec3d(0.0, 65.0, 0.0))
.thenRunForEach(player -> {
player.changeGameMode(GameMode.ADVENTURE);
});
}
Expand Down
38 changes: 19 additions & 19 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,25 @@ dependencies {

modApi "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"

modApi include('xyz.nucleoid:server-translations-api:2.3.0+1.20.5-rc2')
modApi include('xyz.nucleoid:packet-tweaker:0.5.1+1.20.6')
modApi include('xyz.nucleoid:fantasy:0.6.2+1.20.6')
modApi include('xyz.nucleoid:more-codecs:0.3.3+1.20.2')
modApi include('xyz.nucleoid:stimuli:0.4.11+1.20.6')
modApi include('xyz.nucleoid:map-templates:0.1.9+1.20.4')
modApi include('xyz.nucleoid:substrate:0.2.2+1.20.1')
modApi 'eu.pb4:polymer-core:0.8.2+1.20.6'
modApi 'eu.pb4:polymer-resource-pack:0.8.2+1.20.6'
modApi 'eu.pb4:polymer-blocks:0.8.2+1.20.6'
modApi 'eu.pb4:polymer-virtual-entity:0.8.2+1.20.6'
modApi include('eu.pb4:sgui:1.5.1+1.20.5')
modApi include('eu.pb4:sidebar-api:0.4.0+1.20.5')
modApi include("eu.pb4:placeholder-api:2.4.0-pre.1+1.20.5")
modApi include("eu.pb4:map-canvas-api:0.3.0+1.20.6")
modApi include("eu.pb4:player-data-api:0.5.0+1.20.5")
modApi include("eu.pb4:predicate-api:0.4.0+1.20.5")

modImplementation include("me.lucko:fabric-permissions-api:0.2-SNAPSHOT")
modApi include("xyz.nucleoid:server-translations-api:${project.server_translations_version}")
modApi include("xyz.nucleoid:packet-tweaker:${project.packet_tweaker_version}")
modApi include("xyz.nucleoid:fantasy:${project.fantasy_version}")
modApi include("xyz.nucleoid:more-codecs:${project.more_codecs_version}")
modApi include("xyz.nucleoid:stimuli:${project.stimuli_version}")
modApi include("xyz.nucleoid:map-templates:${project.map_templates_version}")
modApi include("xyz.nucleoid:substrate:${project.substrate_version}")
modApi "eu.pb4:polymer-core:${project.polymer_version}"
modApi "eu.pb4:polymer-resource-pack:${project.polymer_version}"
modApi "eu.pb4:polymer-blocks:${project.polymer_version}"
modApi "eu.pb4:polymer-virtual-entity:${project.polymer_version}"
modApi include("eu.pb4:sgui:${project.sgui_version}")
modApi include("eu.pb4:sidebar-api:${project.sidebar_api_version}")
modApi include("eu.pb4:placeholder-api:${project.placeholder_api_version}")
modApi include("eu.pb4:map-canvas-api:${project.map_canvas_api_version}")
modApi include("eu.pb4:player-data-api:${project.player_data_api_version}")
modApi include("eu.pb4:predicate-api:${project.predicate_api_version}")

modImplementation include("me.lucko:fabric-permissions-api:${project.permission_api_version}")

modCompileOnly('xyz.nucleoid:disguiselib-fabric:1.3.2')
modCompileOnly('maven.modrinth:afkdisplay:1.1.0')
Expand Down
17 changes: 16 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,23 @@ minecraft_version=1.20.6
yarn_mappings=1.20.6+build.1
loader_version=0.15.10

#Fabric api
# Dependencies
fabric_version=0.99.0+1.20.6
polymer_version=0.8.2+1.20.6
server_translations_version=2.3.0+1.20.5-rc2
packet_tweaker_version=0.5.1+1.20.6
fantasy_version=0.6.2+1.20.6
more_codecs_version=0.3.3+1.20.2
stimuli_version=0.4.11+1.20.6
map_templates_version=0.1.9+1.20.4
substrate_version=0.2.2+1.20.1
sgui_version=1.5.1+1.20.5
sidebar_api_version=0.4.0+1.20.5
placeholder_api_version=2.4.0-pre.1+1.20.5
map_canvas_api_version=0.3.0+1.20.6
player_data_api_version=0.5.0+1.20.5
predicate_api_version=0.4.0+1.20.5
permission_api_version=0.2-SNAPSHOT

# Mod Properties
mod_version=0.6
Expand Down
19 changes: 9 additions & 10 deletions src/main/java/xyz/nucleoid/plasmid/command/GameCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import com.mojang.logging.LogUtils;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.command.argument.NbtCompoundArgumentType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtOps;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.command.ServerCommandSource;
Expand All @@ -30,6 +29,7 @@
import xyz.nucleoid.plasmid.game.config.GameConfigs;
import xyz.nucleoid.plasmid.game.manager.GameSpaceManager;
import xyz.nucleoid.plasmid.game.player.GamePlayerJoiner;
import xyz.nucleoid.plasmid.game.player.JoinIntent;
import xyz.nucleoid.plasmid.util.Scheduler;

import java.util.Comparator;
Expand Down Expand Up @@ -286,19 +286,18 @@ private static void joinAllPlayersToGame(ServerCommandSource source, GameSpace g
.filter(player -> !GameSpaceManager.get().inGame(player))
.collect(Collectors.toList());

var screen = gameSpace.getPlayers().screenJoins(players);
if (screen.isOk()) {
for (var player : players) {
gameSpace.getPlayers().offer(player);
}
} else {
source.sendError(screen.errorCopy().formatted(Formatting.RED));
var intent = JoinIntent.ANY;
var result = gameSpace.getPlayers().offer(players, intent);
if (result.isError()) {
source.sendError(result.errorCopy().formatted(Formatting.RED));
}
}

private static void tryJoinGame(ServerPlayerEntity player, GameSpace gameSpace) {
var results = GamePlayerJoiner.tryJoin(player, gameSpace);
results.sendErrorsTo(player);
var result = GamePlayerJoiner.tryJoin(player, gameSpace, JoinIntent.ANY);
if (result.isError()) {
player.sendMessage(result.errorCopy().formatted(Formatting.RED));
}
}

private static GameSpace getJoinableGameSpace() throws CommandSyntaxException {
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/xyz/nucleoid/plasmid/command/ui/GameJoinUi.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import xyz.nucleoid.plasmid.game.manager.GameSpaceManager;
import xyz.nucleoid.plasmid.game.manager.ManagedGameSpace;
import xyz.nucleoid.plasmid.game.player.GamePlayerJoiner;
import xyz.nucleoid.plasmid.game.player.JoinIntent;
import xyz.nucleoid.plasmid.util.Guis;

import java.util.ArrayList;
Expand All @@ -38,8 +39,10 @@ public GameJoinUi(ServerPlayerEntity player) {

private static void tryJoinGame(ServerPlayerEntity player, GameSpace gameSpace) {
player.server.execute(() -> {
var results = GamePlayerJoiner.tryJoin(player, gameSpace);
results.sendErrorsTo(player);
var result = GamePlayerJoiner.tryJoin(player, gameSpace, JoinIntent.ANY);
if (result.isError()) {
player.sendMessage(result.errorCopy().formatted(Formatting.RED));
}
});
}

Expand Down
22 changes: 12 additions & 10 deletions src/main/java/xyz/nucleoid/plasmid/game/GameSpacePlayers.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import net.minecraft.server.network.ServerPlayerEntity;
import xyz.nucleoid.plasmid.game.event.GamePlayerEvents;
import xyz.nucleoid.plasmid.game.player.JoinIntent;
import xyz.nucleoid.plasmid.game.player.PlayerOps;
import xyz.nucleoid.plasmid.game.player.PlayerSet;

Expand All @@ -16,30 +17,31 @@
*/
public interface GameSpacePlayers extends PlayerSet {
/**
* Screens a group of players and returns whether the collective group should be allowed into the game.
* Simulates offer to join a player or group of players and returns whether they should be allowed into the game.
* <p>
* This logic is controlled through the active {@link GameActivity} through {@link GamePlayerEvents#SCREEN_JOINS}.
* This logic is controlled through the active {@link GameActivity} through {@link GamePlayerEvents#OFFER}.
*
* @param players the group of players trying to join
* @return a {@link GameResult} describing whether this group can join this game, or an error if not
* @see GamePlayerEvents#SCREEN_JOINS
* @see GameSpacePlayers#offer(ServerPlayerEntity)
* @param intent the intent of the players trying to join, such as whether they want to participate or spectate
* @return a {@link GameResult} describing whether these players can join this game, or an error if not
* @see GameSpacePlayers#offer(Collection, JoinIntent)
* @see xyz.nucleoid.plasmid.game.player.GamePlayerJoiner
*/
GameResult screenJoins(Collection<ServerPlayerEntity> players);
GameResult simulateOffer(Collection<ServerPlayerEntity> players, JoinIntent intent);

/**
* Offers an individual player to join this game. If accepted, they will be teleported into the game, and if not
* Offers a player or group of players to join this game. If accepted, they will be teleported into the game, and if not
* an error {@link GameResult} will be returned.
* <p>
* This logic is controlled through the active {@link GameActivity} through {@link GamePlayerEvents#OFFER}.
*
* @param player the player trying to join
* @return a {@link GameResult} describing whether this player joined the game, or an error if not
* @param players the players trying to join
* @param intent the intent of the players trying to join, such as whether they want to participate or spectate
* @return a {@link GameResult} describing whether these players joined the game, or an error if not
* @see GamePlayerEvents#OFFER
* @see xyz.nucleoid.plasmid.game.player.GamePlayerJoiner
*/
GameResult offer(ServerPlayerEntity player);
GameResult offer(Collection<ServerPlayerEntity> players, JoinIntent intent);

/**
* Attempts to remove the given {@link ServerPlayerEntity} from this {@link GameSpace}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package xyz.nucleoid.plasmid.game.common;

import com.mojang.authlib.GameProfile;
import net.minecraft.entity.boss.BossBar;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.server.network.ServerPlayerEntity;
Expand All @@ -21,8 +22,8 @@
import xyz.nucleoid.plasmid.game.event.GameActivityEvents;
import xyz.nucleoid.plasmid.game.event.GamePlayerEvents;
import xyz.nucleoid.plasmid.game.manager.GameSpaceManager;
import xyz.nucleoid.plasmid.game.player.PlayerOffer;
import xyz.nucleoid.plasmid.game.player.PlayerOfferResult;
import xyz.nucleoid.plasmid.game.player.JoinOffer;
import xyz.nucleoid.plasmid.game.player.JoinOfferResult;
import xyz.nucleoid.plasmid.game.rule.GameRuleType;
import xyz.nucleoid.plasmid.util.compatibility.AfkDisplayCompatibility;

Expand Down Expand Up @@ -88,7 +89,6 @@ public static GameWaitingLobby addTo(GameActivity activity, PlayerConfig playerC

activity.listen(GameActivityEvents.TICK, lobby::onTick);
activity.listen(GameActivityEvents.REQUEST_START, lobby::requestStart);
activity.listen(GamePlayerEvents.SCREEN_JOINS, lobby::screenJoins);
activity.listen(GamePlayerEvents.OFFER, lobby::offerPlayer);
activity.listen(GamePlayerEvents.REMOVE, lobby::onRemovePlayer);

Expand Down Expand Up @@ -169,17 +169,9 @@ private GameResult requestStart() {
}
}

private GameResult screenJoins(Collection<ServerPlayerEntity> players) {
int newPlayerCount = this.gameSpace.getPlayers().size() + players.size();
private JoinOfferResult offerPlayer(JoinOffer offer) {
int newPlayerCount = this.gameSpace.getPlayers().size() + offer.players().size();
if (newPlayerCount > this.playerConfig.maxPlayers()) {
return GameResult.error(GameTexts.Join.gameFull());
}

return GameResult.ok();
}

private PlayerOfferResult offerPlayer(PlayerOffer offer) {
if (this.isFull()) {
return offer.reject(GameTexts.Join.gameFull());
}

Expand Down
60 changes: 28 additions & 32 deletions src/main/java/xyz/nucleoid/plasmid/game/event/GamePlayerEvents.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package xyz.nucleoid.plasmid.game.event;

import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.math.Vec3d;
import xyz.nucleoid.plasmid.game.GameActivity;
import xyz.nucleoid.plasmid.game.GameResult;
import xyz.nucleoid.plasmid.game.GameSpace;
import xyz.nucleoid.plasmid.game.GameTexts;
import xyz.nucleoid.plasmid.game.player.PlayerOffer;
import xyz.nucleoid.plasmid.game.player.PlayerOfferResult;
import xyz.nucleoid.plasmid.game.player.JoinAcceptor;
import xyz.nucleoid.plasmid.game.player.JoinAcceptorResult;
import xyz.nucleoid.plasmid.game.player.JoinOffer;
import xyz.nucleoid.plasmid.game.player.JoinOfferResult;
import xyz.nucleoid.stimuli.event.StimulusEvent;

import java.util.Collection;

/**
* Events relating to players being added and removed from a {@link GameSpace} or {@link GameActivity}.
*/
Expand Down Expand Up @@ -100,53 +97,52 @@ public final class GamePlayerEvents {
});

/**
* Called when a group of players try to join this game. This should be used to reject multiple players as a group,
* such as when a party tries to join but has too many players to fit into the game.
* Called when a group of {@link ServerPlayerEntity} tries to join this game.
* <p>
* This is called before {@link GamePlayerEvents#OFFER} which handles specifically bringing a player into the game.
* Games must respond to this event in order for players to be able to join by returning either
* {@link JoinOffer#accept()} or {@link JoinOffer#reject(Text)}.
*
* @see GamePlayerEvents#OFFER
* @see JoinOffer
* @see JoinOfferResult
* @see GamePlayerEvents#ACCEPT
*/
public static final StimulusEvent<ScreenJoins> SCREEN_JOINS = StimulusEvent.create(ScreenJoins.class, ctx -> players -> {
public static final StimulusEvent<Offer> OFFER = StimulusEvent.create(Offer.class, ctx -> offer -> {
try {
for (var listener : ctx.getListeners()) {
var result = listener.screenJoins(players);
if (result.isError()) {
var result = listener.onOfferPlayers(offer);
if (!(result instanceof JoinOfferResult.Pass)) {
return result;
}
}
return GameResult.ok();
return offer.pass();
} catch (Throwable throwable) {
ctx.handleException(throwable);
return GameResult.error(GameTexts.Join.unexpectedError());
return offer.reject(GameTexts.Join.unexpectedError());
}
});

/**
* Called when a single {@link ServerPlayerEntity} tries to join this game. This event is responsible for bringing
* the player into the {@link GameSpace} world in the correct location.
* Called when a group of {@link ServerPlayerEntity} is accepted to join this game. This event is responsible for bringing
* the players into the {@link GameSpace} world in the correct location.
* <p>
* Games must respond to this event in order for a player to be able to join by returning either
* {@link PlayerOffer#accept(ServerWorld, Vec3d)} or {@link PlayerOffer#reject(Text)}.
* Games must respond to this event in order for players to be able to join.
*
* @see PlayerOffer
* @see PlayerOfferResult
* @see GamePlayerEvents#SCREEN_JOINS
* @see JoinAcceptor
* @see JoinAcceptorResult
* @see GamePlayerEvents#JOIN
*/
public static final StimulusEvent<Offer> OFFER = StimulusEvent.create(Offer.class, ctx -> offer -> {
public static final StimulusEvent<Accept> ACCEPT = StimulusEvent.create(Accept.class, ctx -> accept -> {
try {
for (var listener : ctx.getListeners()) {
var result = listener.onOfferPlayer(offer);
if (result.isTerminal()) {
var result = listener.onAcceptPlayers(accept);
if (!(result instanceof JoinAcceptorResult.Pass)) {
return result;
}
}
return offer.pass();
} catch (Throwable throwable) {
ctx.handleException(throwable);
return offer.reject(GameTexts.Join.unexpectedError());
}
return accept.pass();
});

/**
Expand All @@ -173,12 +169,12 @@ public interface Remove {
void onRemovePlayer(ServerPlayerEntity player);
}

public interface ScreenJoins {
GameResult screenJoins(Collection<ServerPlayerEntity> players);
public interface Offer {
JoinOfferResult onOfferPlayers(JoinOffer offer);
}

public interface Offer {
PlayerOfferResult onOfferPlayer(PlayerOffer offer);
public interface Accept {
JoinAcceptorResult onAcceptPlayers(JoinAcceptor acceptor);
}

public interface Name {
Expand Down
Loading
Loading