Skip to content
Open
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
2 changes: 2 additions & 0 deletions common/src/main/java/io/github/gaming32/bingo/Bingo.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.github.gaming32.bingo.network.messages.s2c.RemoveBoardPayload;
import io.github.gaming32.bingo.network.messages.s2c.ResyncStatesPayload;
import io.github.gaming32.bingo.network.messages.s2c.SyncTeamPayload;
import io.github.gaming32.bingo.network.messages.s2c.UpdateEndTimePayload;
import io.github.gaming32.bingo.network.messages.s2c.UpdateProgressPayload;
import io.github.gaming32.bingo.network.messages.s2c.UpdateStatePayload;
import io.github.gaming32.bingo.platform.BingoPlatform;
Expand Down Expand Up @@ -179,6 +180,7 @@ private static void registerPayloadHandlers() {
registrar.register(PacketFlow.CLIENTBOUND, SyncTeamPayload.TYPE, SyncTeamPayload.CODEC);
registrar.register(PacketFlow.CLIENTBOUND, UpdateProgressPayload.TYPE, UpdateProgressPayload.CODEC);
registrar.register(PacketFlow.CLIENTBOUND, UpdateStatePayload.TYPE, UpdateStatePayload.CODEC);
registrar.register(PacketFlow.CLIENTBOUND, UpdateEndTimePayload.TYPE, UpdateEndTimePayload.CODEC);
});
}

Expand Down
26 changes: 26 additions & 0 deletions common/src/main/java/io/github/gaming32/bingo/BingoCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ public class BingoCommand {
private static final CommandSwitch<Long> SEED = CommandSwitch
.argument("--seed", LongArgumentType.longArg())
.build(RandomSupport::generateUniqueSeed);
private static final CommandSwitch<Integer> TIME_LIMIT = CommandSwitch
.argument("--time-limit", TimeArgument.time(-1))
.getter(IntegerArgumentType::getInteger)
.build(() -> -1);
private static final CommandSwitch<Integer> AUTO_FORFEIT_TIME = CommandSwitch
.argument("--auto-forfeit-time", TimeArgument.time(0))
.getter(IntegerArgumentType::getInteger)
Expand Down Expand Up @@ -353,6 +357,23 @@ public Component getDisplayName() {
)
)
)
.then(literal("time-limit")
.requires(source -> source.hasPermission(2))
.then(literal("set")
.then(argument("time-limit", TimeArgument.time())
.executes(ctx -> {
final var game = ctx.getSource().getServer().bingo$getGame();
if (game == null) {
throw NO_GAME_RUNNING.create();
}
int time = IntegerArgumentType.getInteger(ctx, "time-limit");
game.setScheduledEndTime(ctx.getSource().getServer().overworld().getGameTime() + time);
game.updateRemainingTime(ctx.getSource().getServer());
return 1;
})
)
)
)
);

{
Expand All @@ -364,6 +385,7 @@ public Component getDisplayName() {

SIZE.addTo(startCommand);
SEED.addTo(startCommand);
TIME_LIMIT.addTo(startCommand);
AUTO_FORFEIT_TIME.addTo(startCommand);
DIFFICULTY.addTo(startCommand);
GAMEMODE.addTo(startCommand);
Expand Down Expand Up @@ -403,6 +425,7 @@ private static int startGame(CommandContext<CommandSourceStack> context, int tea
final boolean continueAfterWin = CONTINUE_AFTER_WIN.get(context);
final boolean includeInactiveTeams = INCLUDE_INACTIVE_TEAMS.get(context);
final int autoForfeitTicks = AUTO_FORFEIT_TIME.get(context);
final int timeLimitTicks = TIME_LIMIT.get(context);

final Set<PlayerTeam> teams = LinkedHashSet.newLinkedHashSet(teamCount);
for (int i = 1; i <= teamCount; i++) {
Expand Down Expand Up @@ -452,6 +475,9 @@ private static int startGame(CommandContext<CommandSourceStack> context, int tea
Bingo.LOGGER.info("Generated board (seed {}):\n{}", seed, board);

final var game = new BingoGame(board, gamemode, requireClient, continueAfterWin, autoForfeitTicks, teams.toArray(PlayerTeam[]::new));
if (timeLimitTicks > 0) {
game.setScheduledEndTime(context.getSource().getServer().overworld().getGameTime() + timeLimitTicks);
}
server.bingo$setGame(game);
Bingo.updateCommandTree(playerList);
new ArrayList<>(playerList.getPlayers()).forEach(game::addPlayer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import io.github.gaming32.bingo.platform.BingoPlatform;
import io.github.gaming32.bingo.platform.event.ClientEvents;
import io.github.gaming32.bingo.platform.registrar.KeyMappingBuilder;
import io.github.gaming32.bingo.util.BingoUtil;
import io.github.gaming32.bingo.util.ResourceLocations;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
Expand Down Expand Up @@ -139,7 +140,35 @@ public static void renderBoardOnHud(Minecraft minecraft, GuiGraphics graphics) {
final PositionAndScale pos = getBoardPosition();
renderBingo(graphics, minecraft.screen instanceof ChatScreen, pos);

if (CONFIG.isShowScoreCounter() && clientGame.renderMode() == BingoGameMode.RenderMode.ALL_TEAMS) {
final Font font = minecraft.font;
final int scoreX = (int)(pos.x() * pos.scale() + getBoardWidth() * pos.scale() / 2);
int scoreY;
if (CONFIG.getBoardCorner().isOnBottom) {
scoreY = (int)((pos.y() - BOARD_OFFSET) * pos.scale() - font.lineHeight);
} else {
scoreY = (int)(pos.y() * pos.scale() + (getBoardHeight() + BOARD_OFFSET) * pos.scale());
}
final int shift = CONFIG.getBoardCorner().isOnBottom ? -12 : 12;

if (clientGame.getScheduledEndTime() > 0) {
long serverTime = 0;
if (minecraft.level instanceof ClientLevel clientLevel) {
serverTime = clientLevel.getGameTime();
}
long remainingTimeTicks = clientGame.getScheduledEndTime() - serverTime;
String formatedRemainingTime = " - " + BingoUtil.formatRemainingTime(remainingTimeTicks);
int color = 0xffffffff;
if (remainingTimeTicks < 30 * 60 * 20)
color = 0xffffaf00;
if (remainingTimeTicks < 5 * 60 * 20)
color = 0xffff0000;
final MutableComponent remainingTimeLabel = Component.translatable("bingo.remaining_time");
graphics.drawString(font, remainingTimeLabel, scoreX - font.width(remainingTimeLabel), scoreY, color);
graphics.drawString(font, Component.literal(formatedRemainingTime), scoreX, scoreY, color);
scoreY += shift;
}

if (CONFIG.isShowScoreCounter() && clientGame.getRenderMode() == BingoGameMode.RenderMode.ALL_TEAMS) {
class TeamValue {
final BingoBoard.Teams team;
int score;
Expand All @@ -149,13 +178,13 @@ class TeamValue {
}
}

final TeamValue[] teams = new TeamValue[clientGame.teams().length];
final TeamValue[] teams = new TeamValue[clientGame.getTeams().length];
for (int i = 0; i < teams.length; i++) {
teams[i] = new TeamValue(BingoBoard.Teams.fromOne(i));
}

int totalScore = 0;
for (final BingoBoard.Teams state : clientGame.states()) {
for (final BingoBoard.Teams state : clientGame.getStates()) {
if (state.any()) {
totalScore++;
teams[state.getFirstIndex()].score++;
Expand All @@ -164,18 +193,9 @@ class TeamValue {

Arrays.sort(teams, Comparator.comparing(v -> -v.score)); // Sort in reverse

final Font font = minecraft.font;
final int scoreX = (int)(pos.x() * pos.scale() + getBoardWidth() * pos.scale() / 2);
int scoreY;
if (CONFIG.getBoardCorner().isOnBottom) {
scoreY = (int)((pos.y() - BOARD_OFFSET) * pos.scale() - font.lineHeight);
} else {
scoreY = (int)(pos.y() * pos.scale() + (getBoardHeight() + BOARD_OFFSET) * pos.scale());
}
final int shift = CONFIG.getBoardCorner().isOnBottom ? -12 : 12;
for (final TeamValue teamValue : teams) {
if (teamValue.score == 0) break;
final PlayerTeam team = clientGame.teams()[teamValue.team.getFirstIndex()];
final PlayerTeam team = clientGame.getTeams()[teamValue.team.getFirstIndex()];
final MutableComponent leftText = getDisplayName(team).copy();
final MutableComponent rightText = Component.literal(" - " + teamValue.score);
if (team.getColor() != ChatFormatting.RESET) {
Expand All @@ -188,18 +208,18 @@ class TeamValue {
}

final MutableComponent leftText = Component.translatable("bingo.unclaimed");
final MutableComponent rightText = Component.literal(" - " + (clientGame.states().length - totalScore));
final MutableComponent rightText = Component.literal(" - " + (clientGame.getStates().length - totalScore));
graphics.drawString(font, leftText, scoreX - font.width(leftText), scoreY, 0xffffffff);
graphics.drawString(font, rightText, scoreX, scoreY, 0xffffffff);
}
}

public static int getBoardWidth() {
return 14 + 18 * clientGame.size();
return 14 + 18 * clientGame.getSize();
}

public static int getBoardHeight() {
return 24 + 18 * clientGame.size();
return 24 + 18 * clientGame.getSize();
}

public static void renderBingo(GuiGraphics graphics, boolean mouseHover, PositionAndScale pos) {
Expand All @@ -213,13 +233,13 @@ public static void renderBingo(GuiGraphics graphics, boolean mouseHover, Positio
graphics.pose().scale(pos.scale(), pos.scale(), 1);
graphics.pose().translate(pos.x(), pos.y(), 0);

final BingoMousePos mousePos = mouseHover ? BingoMousePos.getPos(minecraft, clientGame.size(), pos) : null;
final BingoMousePos mousePos = mouseHover ? BingoMousePos.getPos(minecraft, clientGame.getSize(), pos) : null;

graphics.blitSprite(
RenderType::guiTextured,
BOARD_TEXTURE, 0, 0,
7 + 18 * clientGame.size() + 7,
17 + 18 * clientGame.size() + 7
7 + 18 * clientGame.getSize() + 7,
17 + 18 * clientGame.getSize() + 7
);
renderBoardTitle(graphics, minecraft.font);

Expand All @@ -232,8 +252,8 @@ public static void renderBingo(GuiGraphics graphics, boolean mouseHover, Positio
}

final boolean spectator = minecraft.player != null && minecraft.player.isSpectator();
for (int sx = 0; sx < clientGame.size(); sx++) {
for (int sy = 0; sy < clientGame.size(); sy++) {
for (int sx = 0; sx < clientGame.getSize(); sx++) {
for (int sy = 0; sy < clientGame.getSize(); sy++) {
final var goal = clientGame.getGoal(sx, sy);
final int slotX = sx * 18 + 8;
final int slotY = sy * 18 + 18;
Expand All @@ -244,14 +264,14 @@ public static void renderBingo(GuiGraphics graphics, boolean mouseHover, Positio
final BingoBoard.Teams state = clientGame.getState(sx, sy);
boolean isGoalCompleted = state.and(clientTeam);

final Integer color = switch (clientGame.renderMode()) {
final Integer color = switch (clientGame.getRenderMode()) {
case FANCY -> isGoalCompleted ? Integer.valueOf(0x55ff55) : goal.specialType().incompleteColor;
case ALL_TEAMS -> {
if (!state.any()) {
yield null;
}
final BingoBoard.Teams team = isGoalCompleted ? clientTeam : state;
final Integer maybeColor = clientGame.teams()[team.getFirstIndex()].getColor().getColor();
final Integer maybeColor = clientGame.getTeams()[team.getFirstIndex()].getColor().getColor();
yield maybeColor != null ? maybeColor : 0x55ff55;
}
};
Expand Down Expand Up @@ -338,7 +358,7 @@ public static boolean detectClickOrPress(InputConstants.Key key, PositionAndScal
return false;
}

final BingoMousePos mousePos = BingoMousePos.getPos(Minecraft.getInstance(), clientGame.size(), boardPos);
final BingoMousePos mousePos = BingoMousePos.getPos(Minecraft.getInstance(), clientGame.getSize(), boardPos);
if (!mousePos.hasSlotPos()) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi
BingoClient.renderBingo(graphics, true, pos);
assert minecraft != null;
if (minecraft.player != null && minecraft.player.isSpectator()) {
final PlayerTeam team = BingoClient.clientGame.teams()[BingoClient.clientTeam.getFirstIndex()];
final PlayerTeam team = BingoClient.clientGame.getTeams()[BingoClient.clientTeam.getFirstIndex()];
final Integer color = team.getColor().getColor();
graphics.drawCenteredString(
font,
Expand Down Expand Up @@ -105,7 +105,7 @@ private void updateButtonVisibility() {

private void switchTeam(int dir) {
final int currentIndex = BingoClient.clientTeam.getFirstIndex();
final int newIndex = Math.floorMod(currentIndex + dir, BingoClient.clientGame.teams().length);
final int newIndex = Math.floorMod(currentIndex + dir, BingoClient.clientGame.getTeams().length);
BingoClient.clientTeam = BingoBoard.Teams.fromOne(newIndex);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,31 @@
import net.minecraft.world.scores.PlayerTeam;
import org.jetbrains.annotations.Nullable;

public record ClientGame(
int size,
BingoBoard.Teams[] states,
ActiveGoal[] goals,
PlayerTeam[] teams,
BingoGameMode.RenderMode renderMode,
@Nullable GoalProgress[] progress
) {
public final class ClientGame {
private final int size;
private final BingoBoard.Teams[] states;
private final ActiveGoal[] goals;
private final PlayerTeam[] teams;
private final BingoGameMode.RenderMode renderMode;
private final GoalProgress @Nullable [] progress;
private long scheduledEndTime = -1;

public ClientGame(
int size,
BingoBoard.Teams[] states,
ActiveGoal[] goals,
PlayerTeam[] teams,
BingoGameMode.RenderMode renderMode,
@Nullable GoalProgress[] progress
) {
this.size = size;
this.states = states;
this.goals = goals;
this.teams = teams;
this.renderMode = renderMode;
this.progress = progress;
}

public BingoBoard.Teams getState(int x, int y) {
return states[getIndex(x, y)];
}
Expand All @@ -23,11 +40,43 @@ public ActiveGoal getGoal(int x, int y) {
return goals[getIndex(x, y)];
}

public GoalProgress[] getProgress() {
return progress;
}

@Nullable
public GoalProgress getProgress(int x, int y) {
return progress[getIndex(x, y)];
}

public int getSize() {
return size;
}

public BingoBoard.Teams[] getStates() {
return states;
}

public ActiveGoal[] getGoals() {
return goals;
}

public PlayerTeam[] getTeams() {
return teams;
}

public BingoGameMode.RenderMode getRenderMode() {
return renderMode;
}

public void setScheduledEndTime(long endTime) {
this.scheduledEndTime = endTime;
}

public long getScheduledEndTime() {
return scheduledEndTime;
}

private int getIndex(int x, int y) {
return y * size + x;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.github.gaming32.bingo.network.messages.s2c.InitBoardPayload;
import io.github.gaming32.bingo.network.messages.s2c.ResyncStatesPayload;
import io.github.gaming32.bingo.network.messages.s2c.SyncTeamPayload;
import io.github.gaming32.bingo.network.messages.s2c.UpdateEndTimePayload;
import io.github.gaming32.bingo.network.messages.s2c.UpdateProgressPayload;
import io.github.gaming32.bingo.network.messages.s2c.UpdateStatePayload;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
Expand Down Expand Up @@ -50,8 +51,8 @@ public void handleResyncStates(ResyncStatesPayload payload) {
if (!checkGamePresent(payload)) return;
System.arraycopy(
payload.states(), 0,
BingoClient.clientGame.states(), 0,
BingoClient.clientGame.size() * BingoClient.clientGame.size()
BingoClient.clientGame.getStates(), 0,
BingoClient.clientGame.getSize() * BingoClient.clientGame.getSize()
);
}

Expand All @@ -63,18 +64,24 @@ public void handleSyncTeam(SyncTeamPayload payload) {
@Override
public void handleUpdateProgress(UpdateProgressPayload payload) {
if (!checkGamePresent(payload)) return;
BingoClient.clientGame.progress()[payload.index()] = new GoalProgress(payload.progress(), payload.maxProgress());
BingoClient.clientGame.getProgress()[payload.index()] = new GoalProgress(payload.progress(), payload.maxProgress());
}

@Override
public void handleUpdateState(UpdateStatePayload payload) {
if (!checkGamePresent(payload)) return;
final int index = payload.index();
if (index < 0 || index >= BingoClient.clientGame.size() * BingoClient.clientGame.size()) {
if (index < 0 || index >= BingoClient.clientGame.getSize() * BingoClient.clientGame.getSize()) {
Bingo.LOGGER.warn("Invalid {} payload: invalid board index {}", UpdateStatePayload.TYPE, index);
return;
}
BingoClient.clientGame.states()[index] = payload.newState();
BingoClient.clientGame.getStates()[index] = payload.newState();
}

@Override
public void handleUpdateEndTime(UpdateEndTimePayload payload) {
if (!checkGamePresent(payload)) return;
BingoClient.clientGame.setScheduledEndTime(payload.endTime());
}

private static boolean checkGamePresent(CustomPacketPayload payload) {
Expand Down
Loading