Skip to content

Commit 7265575

Browse files
committed
add optional time limit
1 parent e6871e0 commit 7265575

12 files changed

Lines changed: 241 additions & 43 deletions

File tree

common/src/main/java/io/github/gaming32/bingo/Bingo.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.github.gaming32.bingo.network.messages.s2c.RemoveBoardPayload;
2222
import io.github.gaming32.bingo.network.messages.s2c.ResyncStatesPayload;
2323
import io.github.gaming32.bingo.network.messages.s2c.SyncTeamPayload;
24+
import io.github.gaming32.bingo.network.messages.s2c.UpdateEndTimePayload;
2425
import io.github.gaming32.bingo.network.messages.s2c.UpdateProgressPayload;
2526
import io.github.gaming32.bingo.network.messages.s2c.UpdateStatePayload;
2627
import io.github.gaming32.bingo.platform.BingoPlatform;
@@ -181,6 +182,7 @@ private static void registerPayloadHandlers() {
181182
registrar.register(PacketFlow.CLIENTBOUND, SyncTeamPayload.TYPE, SyncTeamPayload.CODEC);
182183
registrar.register(PacketFlow.CLIENTBOUND, UpdateProgressPayload.TYPE, UpdateProgressPayload.CODEC);
183184
registrar.register(PacketFlow.CLIENTBOUND, UpdateStatePayload.TYPE, UpdateStatePayload.CODEC);
185+
registrar.register(PacketFlow.CLIENTBOUND, UpdateEndTimePayload.TYPE, UpdateEndTimePayload.CODEC);
184186
});
185187
}
186188

common/src/main/java/io/github/gaming32/bingo/BingoCommand.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ public class BingoCommand {
129129
private static final CommandSwitch<Long> SEED = CommandSwitch
130130
.argument("--seed", LongArgumentType.longArg())
131131
.build(RandomSupport::generateUniqueSeed);
132+
private static final CommandSwitch<Integer> TIME = CommandSwitch
133+
.argument("--time", IntegerArgumentType.integer())
134+
.getter(IntegerArgumentType::getInteger)
135+
.build(() -> 1);
132136
private static final CommandSwitch<Integer> AUTO_FORFEIT_TIME = CommandSwitch
133137
.argument("--auto-forfeit-time", TimeArgument.time(0))
134138
.getter(IntegerArgumentType::getInteger)
@@ -353,6 +357,23 @@ public Component getDisplayName() {
353357
)
354358
)
355359
)
360+
.then(literal("time")
361+
.requires(source -> source.hasPermission(2))
362+
.then(literal("set")
363+
.then(argument("time", IntegerArgumentType.integer())
364+
.executes(ctx -> {
365+
final var game = ctx.getSource().getServer().bingo$getGame();
366+
if (game == null) {
367+
throw NO_GAME_RUNNING.create();
368+
}
369+
int time = IntegerArgumentType.getInteger(ctx, "time");
370+
game.setScheduledEndTime(System.currentTimeMillis() + (long) time * 1000 * 60);
371+
game.updateRemainingTime(ctx.getSource().getServer().getPlayerList());
372+
return 1;
373+
})
374+
)
375+
)
376+
)
356377
);
357378

358379
{
@@ -364,6 +385,7 @@ public Component getDisplayName() {
364385

365386
SIZE.addTo(startCommand);
366387
SEED.addTo(startCommand);
388+
TIME.addTo(startCommand);
367389
AUTO_FORFEIT_TIME.addTo(startCommand);
368390
DIFFICULTY.addTo(startCommand);
369391
GAMEMODE.addTo(startCommand);
@@ -403,6 +425,7 @@ private static int startGame(CommandContext<CommandSourceStack> context, int tea
403425
final boolean continueAfterWin = CONTINUE_AFTER_WIN.get(context);
404426
final boolean includeInactiveTeams = INCLUDE_INACTIVE_TEAMS.get(context);
405427
final int autoForfeitTicks = AUTO_FORFEIT_TIME.get(context);
428+
final int time = TIME.get(context);
406429

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

454477
final var game = new BingoGame(board, gamemode, requireClient, continueAfterWin, autoForfeitTicks, teams.toArray(PlayerTeam[]::new));
478+
if (time > 0) {
479+
game.setScheduledEndTime(System.currentTimeMillis() + (long) time * 1000 * 60);
480+
}
455481
server.bingo$setGame(game);
456482
Bingo.updateCommandTree(playerList);
457483
new ArrayList<>(playerList.getPlayers()).forEach(game::addPlayer);

common/src/main/java/io/github/gaming32/bingo/client/BingoClient.java

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import io.github.gaming32.bingo.platform.BingoPlatform;
1717
import io.github.gaming32.bingo.platform.event.ClientEvents;
1818
import io.github.gaming32.bingo.platform.registrar.KeyMappingBuilder;
19+
import io.github.gaming32.bingo.util.BingoUtil;
1920
import io.github.gaming32.bingo.util.ResourceLocations;
2021
import net.minecraft.ChatFormatting;
2122
import net.minecraft.client.Minecraft;
@@ -139,7 +140,31 @@ public static void renderBoardOnHud(Minecraft minecraft, GuiGraphics graphics) {
139140
final PositionAndScale pos = getBoardPosition();
140141
renderBingo(graphics, minecraft.screen instanceof ChatScreen, pos);
141142

142-
if (CONFIG.isShowScoreCounter() && clientGame.renderMode() == BingoGameMode.RenderMode.ALL_TEAMS) {
143+
final Font font = minecraft.font;
144+
final int scoreX = (int)(pos.x() * pos.scale() + getBoardWidth() * pos.scale() / 2);
145+
int scoreY;
146+
if (CONFIG.getBoardCorner().isOnBottom) {
147+
scoreY = (int)((pos.y() - BOARD_OFFSET) * pos.scale() - font.lineHeight);
148+
} else {
149+
scoreY = (int)(pos.y() * pos.scale() + (getBoardHeight() + BOARD_OFFSET) * pos.scale());
150+
}
151+
final int shift = CONFIG.getBoardCorner().isOnBottom ? -12 : 12;
152+
153+
if (clientGame.getScheduledEndTime() > 0) {
154+
long remainingTime = clientGame.getScheduledEndTime() - System.currentTimeMillis();
155+
String formatedRemainingTime = " - " + BingoUtil.formatRemainingTime(remainingTime);
156+
int color = 0xffffffff;
157+
if (remainingTime < 30 * 60 * 1000)
158+
color = 0xffffaf00;
159+
if (remainingTime < 5 * 60 * 1000)
160+
color = 0xffff0000;
161+
final MutableComponent remainingTimeLabel = Component.translatable("bingo.remaining_time");
162+
graphics.drawString(font, remainingTimeLabel, scoreX - font.width(remainingTimeLabel), scoreY, color);
163+
graphics.drawString(font, Component.literal(formatedRemainingTime), scoreX, scoreY, color);
164+
scoreY += shift;
165+
}
166+
167+
if (CONFIG.isShowScoreCounter() && clientGame.getRenderMode() == BingoGameMode.RenderMode.ALL_TEAMS) {
143168
class TeamValue {
144169
final BingoBoard.Teams team;
145170
int score;
@@ -149,13 +174,13 @@ class TeamValue {
149174
}
150175
}
151176

152-
final TeamValue[] teams = new TeamValue[clientGame.teams().length];
177+
final TeamValue[] teams = new TeamValue[clientGame.getTeams().length];
153178
for (int i = 0; i < teams.length; i++) {
154179
teams[i] = new TeamValue(BingoBoard.Teams.fromOne(i));
155180
}
156181

157182
int totalScore = 0;
158-
for (final BingoBoard.Teams state : clientGame.states()) {
183+
for (final BingoBoard.Teams state : clientGame.getStates()) {
159184
if (state.any()) {
160185
totalScore++;
161186
teams[state.getFirstIndex()].score++;
@@ -164,18 +189,9 @@ class TeamValue {
164189

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

167-
final Font font = minecraft.font;
168-
final int scoreX = (int)(pos.x() * pos.scale() + getBoardWidth() * pos.scale() / 2);
169-
int scoreY;
170-
if (CONFIG.getBoardCorner().isOnBottom) {
171-
scoreY = (int)((pos.y() - BOARD_OFFSET) * pos.scale() - font.lineHeight);
172-
} else {
173-
scoreY = (int)(pos.y() * pos.scale() + (getBoardHeight() + BOARD_OFFSET) * pos.scale());
174-
}
175-
final int shift = CONFIG.getBoardCorner().isOnBottom ? -12 : 12;
176192
for (final TeamValue teamValue : teams) {
177193
if (teamValue.score == 0) break;
178-
final PlayerTeam team = clientGame.teams()[teamValue.team.getFirstIndex()];
194+
final PlayerTeam team = clientGame.getTeams()[teamValue.team.getFirstIndex()];
179195
final MutableComponent leftText = getDisplayName(team).copy();
180196
final MutableComponent rightText = Component.literal(" - " + teamValue.score);
181197
if (team.getColor() != ChatFormatting.RESET) {
@@ -188,18 +204,18 @@ class TeamValue {
188204
}
189205

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

197213
public static int getBoardWidth() {
198-
return 14 + 18 * clientGame.size();
214+
return 14 + 18 * clientGame.getSize();
199215
}
200216

201217
public static int getBoardHeight() {
202-
return 24 + 18 * clientGame.size();
218+
return 24 + 18 * clientGame.getSize();
203219
}
204220

205221
public static void renderBingo(GuiGraphics graphics, boolean mouseHover, PositionAndScale pos) {
@@ -213,13 +229,13 @@ public static void renderBingo(GuiGraphics graphics, boolean mouseHover, Positio
213229
graphics.pose().scale(pos.scale(), pos.scale(), 1);
214230
graphics.pose().translate(pos.x(), pos.y(), 0);
215231

216-
final BingoMousePos mousePos = mouseHover ? BingoMousePos.getPos(minecraft, clientGame.size(), pos) : null;
232+
final BingoMousePos mousePos = mouseHover ? BingoMousePos.getPos(minecraft, clientGame.getSize(), pos) : null;
217233

218234
graphics.blitSprite(
219235
RenderType::guiTextured,
220236
BOARD_TEXTURE, 0, 0,
221-
7 + 18 * clientGame.size() + 7,
222-
17 + 18 * clientGame.size() + 7
237+
7 + 18 * clientGame.getSize() + 7,
238+
17 + 18 * clientGame.getSize() + 7
223239
);
224240
renderBoardTitle(graphics, minecraft.font);
225241

@@ -232,8 +248,8 @@ public static void renderBingo(GuiGraphics graphics, boolean mouseHover, Positio
232248
}
233249

234250
final boolean spectator = minecraft.player != null && minecraft.player.isSpectator();
235-
for (int sx = 0; sx < clientGame.size(); sx++) {
236-
for (int sy = 0; sy < clientGame.size(); sy++) {
251+
for (int sx = 0; sx < clientGame.getSize(); sx++) {
252+
for (int sy = 0; sy < clientGame.getSize(); sy++) {
237253
final var goal = clientGame.getGoal(sx, sy);
238254
final int slotX = sx * 18 + 8;
239255
final int slotY = sy * 18 + 18;
@@ -244,14 +260,14 @@ public static void renderBingo(GuiGraphics graphics, boolean mouseHover, Positio
244260
final BingoBoard.Teams state = clientGame.getState(sx, sy);
245261
boolean isGoalCompleted = state.and(clientTeam);
246262

247-
final Integer color = switch (clientGame.renderMode()) {
263+
final Integer color = switch (clientGame.getRenderMode()) {
248264
case FANCY -> isGoalCompleted ? Integer.valueOf(0x55ff55) : goal.specialType().incompleteColor;
249265
case ALL_TEAMS -> {
250266
if (!state.any()) {
251267
yield null;
252268
}
253269
final BingoBoard.Teams team = isGoalCompleted ? clientTeam : state;
254-
final Integer maybeColor = clientGame.teams()[team.getFirstIndex()].getColor().getColor();
270+
final Integer maybeColor = clientGame.getTeams()[team.getFirstIndex()].getColor().getColor();
255271
yield maybeColor != null ? maybeColor : 0x55ff55;
256272
}
257273
};
@@ -338,7 +354,7 @@ public static boolean detectClickOrPress(InputConstants.Key key, PositionAndScal
338354
return false;
339355
}
340356

341-
final BingoMousePos mousePos = BingoMousePos.getPos(Minecraft.getInstance(), clientGame.size(), boardPos);
357+
final BingoMousePos mousePos = BingoMousePos.getPos(Minecraft.getInstance(), clientGame.getSize(), boardPos);
342358
if (!mousePos.hasSlotPos()) {
343359
return false;
344360
}

common/src/main/java/io/github/gaming32/bingo/client/BoardScreen.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi
4141
BingoClient.renderBingo(graphics, true, pos);
4242
assert minecraft != null;
4343
if (minecraft.player != null && minecraft.player.isSpectator()) {
44-
final PlayerTeam team = BingoClient.clientGame.teams()[BingoClient.clientTeam.getFirstIndex()];
44+
final PlayerTeam team = BingoClient.clientGame.getTeams()[BingoClient.clientTeam.getFirstIndex()];
4545
final Integer color = team.getColor().getColor();
4646
graphics.drawCenteredString(
4747
font,
@@ -105,7 +105,7 @@ private void updateButtonVisibility() {
105105

106106
private void switchTeam(int dir) {
107107
final int currentIndex = BingoClient.clientTeam.getFirstIndex();
108-
final int newIndex = Math.floorMod(currentIndex + dir, BingoClient.clientGame.teams().length);
108+
final int newIndex = Math.floorMod(currentIndex + dir, BingoClient.clientGame.getTeams().length);
109109
BingoClient.clientTeam = BingoBoard.Teams.fromOne(newIndex);
110110
}
111111
}

common/src/main/java/io/github/gaming32/bingo/client/ClientGame.java

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,31 @@
77
import net.minecraft.world.scores.PlayerTeam;
88
import org.jetbrains.annotations.Nullable;
99

10-
public record ClientGame(
11-
int size,
12-
BingoBoard.Teams[] states,
13-
ActiveGoal[] goals,
14-
PlayerTeam[] teams,
15-
BingoGameMode.RenderMode renderMode,
16-
@Nullable GoalProgress[] progress
17-
) {
10+
public final class ClientGame {
11+
private final int size;
12+
private final BingoBoard.Teams[] states;
13+
private final ActiveGoal[] goals;
14+
private final PlayerTeam[] teams;
15+
private final BingoGameMode.RenderMode renderMode;
16+
private final GoalProgress @Nullable [] progress;
17+
private long scheduledEndTime = -1;
18+
19+
public ClientGame(
20+
int size,
21+
BingoBoard.Teams[] states,
22+
ActiveGoal[] goals,
23+
PlayerTeam[] teams,
24+
BingoGameMode.RenderMode renderMode,
25+
@Nullable GoalProgress[] progress
26+
) {
27+
this.size = size;
28+
this.states = states;
29+
this.goals = goals;
30+
this.teams = teams;
31+
this.renderMode = renderMode;
32+
this.progress = progress;
33+
}
34+
1835
public BingoBoard.Teams getState(int x, int y) {
1936
return states[getIndex(x, y)];
2037
}
@@ -23,11 +40,43 @@ public ActiveGoal getGoal(int x, int y) {
2340
return goals[getIndex(x, y)];
2441
}
2542

43+
public GoalProgress[] getProgress() {
44+
return progress;
45+
}
46+
2647
@Nullable
2748
public GoalProgress getProgress(int x, int y) {
2849
return progress[getIndex(x, y)];
2950
}
3051

52+
public int getSize() {
53+
return size;
54+
}
55+
56+
public BingoBoard.Teams[] getStates() {
57+
return states;
58+
}
59+
60+
public ActiveGoal[] getGoals() {
61+
return goals;
62+
}
63+
64+
public PlayerTeam[] getTeams() {
65+
return teams;
66+
}
67+
68+
public BingoGameMode.RenderMode getRenderMode() {
69+
return renderMode;
70+
}
71+
72+
public void setScheduledEndTime(long endTime) {
73+
this.scheduledEndTime = endTime;
74+
}
75+
76+
public long getScheduledEndTime() {
77+
return scheduledEndTime;
78+
}
79+
3180
private int getIndex(int x, int y) {
3281
return y * size + x;
3382
}

common/src/main/java/io/github/gaming32/bingo/client/ClientPayloadHandlerImpl.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.github.gaming32.bingo.network.messages.s2c.InitBoardPayload;
77
import io.github.gaming32.bingo.network.messages.s2c.ResyncStatesPayload;
88
import io.github.gaming32.bingo.network.messages.s2c.SyncTeamPayload;
9+
import io.github.gaming32.bingo.network.messages.s2c.UpdateEndTimePayload;
910
import io.github.gaming32.bingo.network.messages.s2c.UpdateProgressPayload;
1011
import io.github.gaming32.bingo.network.messages.s2c.UpdateStatePayload;
1112
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
@@ -50,8 +51,8 @@ public void handleResyncStates(ResyncStatesPayload payload) {
5051
if (!checkGamePresent(payload)) return;
5152
System.arraycopy(
5253
payload.states(), 0,
53-
BingoClient.clientGame.states(), 0,
54-
BingoClient.clientGame.size() * BingoClient.clientGame.size()
54+
BingoClient.clientGame.getStates(), 0,
55+
BingoClient.clientGame.getSize() * BingoClient.clientGame.getSize()
5556
);
5657
}
5758

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

6970
@Override
7071
public void handleUpdateState(UpdateStatePayload payload) {
7172
if (!checkGamePresent(payload)) return;
7273
final int index = payload.index();
73-
if (index < 0 || index >= BingoClient.clientGame.size() * BingoClient.clientGame.size()) {
74+
if (index < 0 || index >= BingoClient.clientGame.getSize() * BingoClient.clientGame.getSize()) {
7475
Bingo.LOGGER.warn("Invalid {} payload: invalid board index {}", UpdateStatePayload.TYPE, index);
7576
return;
7677
}
77-
BingoClient.clientGame.states()[index] = payload.newState();
78+
BingoClient.clientGame.getStates()[index] = payload.newState();
79+
}
80+
81+
@Override
82+
public void handleUpdateEndTime(UpdateEndTimePayload payload) {
83+
if (!checkGamePresent(payload)) return;
84+
BingoClient.clientGame.setScheduledEndTime(payload.endTime());
7885
}
7986

8087
private static boolean checkGamePresent(CustomPacketPayload payload) {

0 commit comments

Comments
 (0)