Compare commits

..

100 Commits

Author SHA1 Message Date
jonah 82db2bdab1 fixed server build script 2022-01-17 12:19:52 +01:00
jonah 96ed5ac483 improved error handling 2022-01-17 00:41:27 +01:00
jonah a9d9d209b9 fixed npe in Session 2022-01-17 00:38:49 +01:00
jonah 86307e997b fixed bug in ChangePredictionOverlay 2022-01-16 23:47:36 +01:00
jonah ae8f33e598 improved error handling 2022-01-16 23:07:29 +01:00
jonah dcfea1854c added "end card" 2022-01-15 00:47:17 +01:00
jonah 111d089b1f added trick count label 2022-01-14 23:20:44 +01:00
jonah 607d6d104e bugfixes 2022-01-14 22:41:51 +01:00
jonah 1e4c772a66 added support for changeling and improved support for cloud and juggler 2022-01-14 21:57:30 +01:00
jonah ccc0dc2972 improved instructions screen (#18) 2022-01-14 13:58:06 +01:00
Johannes-coderer 0f61b25d4f Anleitungsscreen(#18) 2022-01-14 13:31:10 +01:00
jonah e015f2af81 multiple bugfixes 2022-01-14 09:15:10 +01:00
jonah 3e9e0edd70 Merge remote-tracking branch 'origin/main' into main 2022-01-14 09:01:03 +01:00
jonah e094a210f4 font adjustments 2022-01-14 09:00:39 +01:00
rbenedikt 850c5aa985 Sound Effects 2022-01-14 02:07:18 +01:00
Johannes-coderer 96b999dd39 Anleitungsscreen(#18) 2022-01-14 00:32:13 +01:00
Teubler ee0f2384be #16 started useful error handling 2022-01-13 23:09:20 +01:00
Teubler 114cae0d6c #16 added basic error screen 2022-01-13 22:30:09 +01:00
Teubler 07633da4ee #16 added internationalized messages 2022-01-13 22:25:39 +01:00
jonah a5b00ac0a1 rejoin support for libgdx client 2022-01-13 22:05:47 +01:00
jonah 891e47ffec bugfixes 2022-01-13 22:04:54 +01:00
jonah d26d6646c5 refactoring 2022-01-13 19:26:26 +01:00
jonah d2468557b5 refactoring 2022-01-13 19:23:52 +01:00
jonah e44e0db63e bugfixes 2022-01-13 16:30:09 +01:00
jonah 3b9becbbda added name validation 2022-01-13 16:25:47 +01:00
jonah 2e9549e4e0 fixed dimming behind overlays
added menu
2022-01-12 21:11:57 +01:00
jonah c2a81febb9 migration to asset manager 2022-01-12 16:01:49 +01:00
jonah 0e6658c2d9 improved menu accessibility 2022-01-12 14:44:04 +01:00
jonah 93e341d445 bugfixes 2022-01-12 12:51:22 +01:00
jonah b5d82ac8de added debug websocket 2022-01-12 12:15:52 +01:00
jonah 155049830b improved null safety 2022-01-12 11:35:02 +01:00
jonah 94ac10e93b migrated to jackson 2022-01-12 10:28:31 +01:00
jonah b20f300260 bugfixes and improvements
* fixed inconsistent player order
* minor visual adjustments
* refactoring
2022-01-11 14:00:28 +01:00
jonah 8c719a8835 support for juggling and multicolored cards 2022-01-10 22:00:37 +01:00
jonah 3adaeffe2d changes to sync 2022-01-10 20:22:07 +01:00
rbenedikt ee2367643d Kartenbilder jpg@250x400px 2022-01-10 16:10:59 +01:00
jonah bf87f4af1c internationalization of game screen 2022-01-10 15:12:42 +01:00
jonah f7d753e7e0 game logic 2022-01-10 14:30:27 +01:00
jonah 4eb1b61e7b added sync point after trump determination 2022-01-10 04:06:27 +01:00
jonah 298167d4c9 improved menus in libGDX client 2022-01-10 03:10:32 +01:00
jonah 7a25d3b881 improved libGDX client logging 2022-01-09 22:49:32 +01:00
jonah 50fe4b7681 added suit cards 2022-01-09 22:24:08 +01:00
jonah a977e4dca1 Updated Log4j2 dependency 2022-01-09 22:23:54 +01:00
jonah 238c67ce48 visual improvements 2021-12-14 19:28:02 +01:00
jonah 2d3477ffc5 added sync at start of round and trick 2021-12-14 17:34:20 +01:00
jonah 62b6c3fd81 added TimeoutMessage 2021-12-14 16:26:02 +01:00
jonah 62f04dfded visual improvements 2021-12-14 14:00:59 +01:00
jonah 6fe8a70d9e improved CreateGameScreen 2021-12-14 12:55:18 +01:00
jonah 1e5ed45c63 fixed game creation screen 99c4f688 #16 2021-12-14 11:16:26 +01:00
jonah 44162b5bf3 Update .gitlab-ci.yml file 2021-12-14 10:59:04 +01:00
jonah 64152219a0 Updated Dependencies 2021-12-14 09:03:10 +01:00
Teubler 99c4f68893 #16 + updated CreateGameScreen
functionality of CreateGameScreen WIP
2021-12-09 21:36:40 +01:00
Jonah 5e428d1301 fixed 1fc7103d (#17) 2021-12-07 17:25:59 +01:00
Jonah e5e67a3418 reconnect in server and cli 2021-12-05 11:21:46 +01:00
Johannes-coderer 1fc7103d66 Spielscreen (#17) 2021-12-04 15:14:00 +01:00
Jonah 17ec7a1a90 #17 2021-12-03 10:53:52 +01:00
Jonah 4a6e1e81e4 Cleanup 2021-12-02 22:44:27 +01:00
Jonah fb400afdc2 Cleanup 2021-12-02 22:24:45 +01:00
riedlsepp 3bd95c0b61 Kartenbilder jpg@250x400px 2021-12-02 14:45:03 +01:00
riedlsepp a9e4644b06 Einzelgrafikelemente #7 2021-12-02 03:02:30 +01:00
Jonah 442fc6c7d0 shrank client size 2021-12-01 17:58:53 +01:00
Jonah c7344a502f improved GameScreen 2021-12-01 14:28:03 +01:00
Jonah 4cd5e90e2b bugfixes in server and cli-client 2021-11-30 11:23:41 +01:00
vi-ahirmer 3179a17b36 #14 2021-11-29 15:56:32 +01:00
Jonah db07bfa453 CLI Client #15 2021-11-25 23:17:29 +01:00
Jonah 1cc4c3eeb9 CLI Client #15 2021-11-25 19:36:52 +01:00
Jonah 766e923713 CLI Client #15 2021-11-25 19:33:31 +01:00
Johannes-coderer 34f6d9848b Erste Grundlage für den Spielscreen (#17) 2021-11-25 19:28:14 +01:00
Johannes-coderer 6fc1c9429e Erste Grundlage für den Spielscreen (#17) 2021-11-25 19:19:55 +01:00
vi-ahirmer 5cf4bc506f Ticket #14 2021-11-23 16:00:14 +01:00
BuildTools 3e9b9d1f31 improved libGDX client performance
added automatic texture packing
2021-11-19 17:55:46 +01:00
Jonah 96a2d43aaf extracted dependencies info into Dependencies.kt 2021-11-19 10:42:31 +01:00
Jonah 9bc2d08ddd migration to gradle kotlin dsl 2021-11-19 09:59:40 +01:00
Jonah 73ff37cc38 added distribution task to client buildscript 2021-11-17 12:31:35 +01:00
Jonah 2b86d0d86c added parse method to messages 2021-11-15 18:29:25 +01:00
BuildTools 7f33529e52 Refactored LibGDX Client 2021-11-12 22:34:14 +01:00
Teubler 4ed23e1a0f Initial libGDX Code Commit #11 2021-11-12 18:34:00 +01:00
BuildTools 385c6ba50a Sample LibGDX project setup 2021-11-12 18:16:28 +01:00
riedlsepp 270bc40fa3 Einzelgrafikelemente #7 2021-11-12 10:25:55 +01:00
Jonah 67bb44eb39 Fixed Gradle Tests 2021-11-12 09:23:49 +01:00
Jonah 544f9c0877 Migration from Maven to Gradle 7.3 2021-11-12 09:06:59 +01:00
Johannes-coderer 36deb15f02 Weitere Client- und ServerMessages für Verbindungsverlust und VoteCick 2021-11-11 13:06:08 +01:00
Jonah a24e8b0223 Reworked state machine 2021-11-11 09:48:59 +01:00
Johannes-coderer b6868db2c6 Merge remote-tracking branch 'origin/main' 2021-11-10 20:27:40 +01:00
Johannes-coderer 649fd581f8 Bugfixes 2021-11-10 20:27:19 +01:00
Benedikt Riedl d1acde7bde Upload New File 2021-11-09 12:38:29 +00:00
Benedikt Riedl 74c5e7709a Upload New File 2021-11-09 12:38:09 +00:00
Benedikt Riedl a0b483a4f0 Upload New File 2021-11-09 12:37:33 +00:00
Benedikt Riedl f04ee9177f Upload New File 2021-11-09 12:36:56 +00:00
Benedikt Riedl 5d9c958732 Menügrafiken 2021-11-09 12:36:06 +00:00
Benedikt Riedl 4946c214be Konzeptgrafiken 2021-11-09 12:35:45 +00:00
Johannes-coderer ceb4c49e01 Client- und Server-Nachrichten verbessert(#9) 2021-11-05 12:43:58 +01:00
Jonah 7f84889a02 Fehler in Spiellogik von Jongleur und Wolke behoben (#12) 2021-11-05 01:31:20 +01:00
Johannes-coderer 7e1d15591e Client- und Server-Nachrichten implementiert(#9) 2021-11-04 22:54:40 +01:00
Jonah 2f1794973a - Jubiläumsedition implementiert (#12)
- Tests verbessert
2021-11-04 20:18:26 +01:00
Jonah eba221525f - refactored GameData
- removed reference to Context in State
2021-10-29 22:58:11 +02:00
Jonah Bauer c301d08094 Update .gitlab-ci.yml file 2021-10-28 21:05:47 +00:00
Jonah bba7153801 Issue #5: Grundspiel implementieren 2021-10-28 23:04:49 +02:00
Jonah b32ff5aa6f project setup 2021-10-18 16:30:07 +02:00
Jonah Bauer ca5401cbe2 Initial commit 2021-10-11 13:50:11 +00:00
113 changed files with 581 additions and 768 deletions
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
@@ -2,8 +2,8 @@ package eu.jonahbauer.wizard.client.cli.commands;
import eu.jonahbauer.wizard.client.cli.Client;
import eu.jonahbauer.wizard.client.cli.state.Game;
import eu.jonahbauer.wizard.client.cli.util.Pair;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import java.util.List;
import java.util.Map;
@@ -2,6 +2,7 @@ package eu.jonahbauer.wizard.client.cli.state;
import eu.jonahbauer.wizard.client.cli.Client;
import eu.jonahbauer.wizard.client.cli.commands.GameCommand;
import eu.jonahbauer.wizard.client.cli.util.Pair;
import eu.jonahbauer.wizard.common.messages.client.InteractionMessage;
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
import eu.jonahbauer.wizard.common.messages.observer.*;
@@ -11,7 +12,6 @@ import eu.jonahbauer.wizard.common.messages.server.GameMessage;
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import lombok.Getter;
import java.time.Instant;
@@ -0,0 +1,24 @@
package eu.jonahbauer.wizard.client.cli.util;
import java.util.Map;
public record Pair<F,S>(F first, S second) implements Map.Entry<F, S> {
public static <F,S> Pair<F,S> of(F first, S second) {
return new Pair<>(first, second);
}
@Override
public F getKey() {
return first();
}
@Override
public S getValue() {
return second();
}
@Override
public S setValue(S value) {
throw new UnsupportedOperationException();
}
}
@@ -1,5 +1,6 @@
package eu.jonahbauer.wizard.client.cli.util;
import eu.jonahbauer.wizard.client.cli.Client;
import eu.jonahbauer.wizard.client.cli.state.ClientState;
import picocli.CommandLine;
@@ -9,7 +9,6 @@ import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import eu.jonahbauer.wizard.client.libgdx.screens.MainMenuScreen;
import eu.jonahbauer.wizard.client.libgdx.util.SavedData;
import eu.jonahbauer.wizard.client.libgdx.util.SoundManager;
import eu.jonahbauer.wizard.client.libgdx.util.WizardAssetManager;
import lombok.Getter;
@@ -20,8 +19,6 @@ public class WizardGame extends Game {
public SpriteBatch batch;
public WizardAssetManager assets;
public SoundManager sounds;
public final SavedData storage = new SavedData();
private boolean fullscreenToggle;
@@ -38,8 +35,6 @@ public class WizardGame extends Game {
assets.loadShared();
assets.finishLoading();
sounds = new SoundManager(assets);
// background music
Music backgroundMusic = assets.get(WizardAssetManager.MUSIC_BACKGROUND, Music.class);
backgroundMusic.setLooping(true);
@@ -82,7 +77,6 @@ public class WizardGame extends Game {
@Override
public void dispose () {
batch.dispose();
sounds.dispose();
assets.dispose();
client.shutdownNow();
var socket = client.getSocket();
@@ -1,53 +0,0 @@
package eu.jonahbauer.wizard.client.libgdx.actors;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.scenes.scene2d.ui.List;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Align;
import lombok.Getter;
import lombok.Setter;
public abstract class IconList<T> extends List<T> {
@Getter
@Setter
private float iconWidth = -1;
@Getter
@Setter
private float iconPadding = 8;
@SuppressWarnings("unused")
public IconList(Skin skin) {
super(skin);
}
@SuppressWarnings("unused")
public IconList(Skin skin, String styleName) {
super(skin, styleName);
}
@SuppressWarnings("unused")
public IconList(ListStyle style) {
super(style);
}
public abstract Drawable getIcon(T item);
@Override
@Deprecated
public void setAlignment(int alignment) {}
@Override
protected GlyphLayout drawItem(Batch batch, BitmapFont font, int index, T item, float x, float y, float width) {
var text = toString(item);
var icon = getIcon(item);
var height = font.getCapHeight();
var iconWidth = this.iconWidth < 0 ? height : this.iconWidth;
icon.draw(batch, x, y - height, iconWidth, height);
return font.draw(batch, text, x + iconWidth + iconPadding, y, 0, text.length(), width - iconWidth - iconPadding, Align.left, false, "...");
}
}
@@ -1,21 +0,0 @@
package eu.jonahbauer.wizard.client.libgdx.listeners;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import eu.jonahbauer.wizard.client.libgdx.util.SoundManager;
public class ButtonClickListener extends ChangeListener {
private final SoundManager sounds;
public ButtonClickListener(SoundManager sounds) {
this.sounds = sounds;
}
@Override
public void changed(ChangeEvent event, Actor actor) {
if (actor instanceof Button) {
sounds.sfxClick();
}
}
}
@@ -29,6 +29,7 @@ public class ConnectScreen extends MenuScreen {
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonBack) {
game.getClient().execute(Menu.class, Menu::showMenuScreen);
sfxClick();
} else if (actor == buttonConnect) {
try {
var uriString = ConnectScreen.this.uriField.getText();
@@ -38,6 +39,8 @@ public class ConnectScreen extends MenuScreen {
} catch (URISyntaxException e) {
uriField.setStyle(getTextFieldErrorStyle());
}
sfxClick();
}
}
};
@@ -31,8 +31,10 @@ public class CreateGameScreen extends MenuScreen {
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonBack) {
game.getClient().execute(Lobby.class, Lobby::showListScreen);
sfxClick();
} else if (actor == buttonContinue) {
create();
sfxClick();
}
}
};
@@ -18,6 +18,7 @@ public class ErrorScreen extends MenuScreen {
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonBack) {
game.getClient().execute(BaseState.class, BaseState::dismissErrorScreen);
sfxClick();
}
}
};
@@ -22,7 +22,10 @@ import eu.jonahbauer.wizard.client.libgdx.actors.CardsGroup;
import eu.jonahbauer.wizard.client.libgdx.actors.PadOfTruth;
import eu.jonahbauer.wizard.client.libgdx.state.Game;
import eu.jonahbauer.wizard.client.libgdx.state.Session;
import eu.jonahbauer.wizard.client.libgdx.util.*;
import eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings;
import eu.jonahbauer.wizard.client.libgdx.util.CardUtil;
import eu.jonahbauer.wizard.client.libgdx.util.Pair;
import eu.jonahbauer.wizard.client.libgdx.util.WizardAssetManager;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.model.Card;
import lombok.Getter;
@@ -418,13 +421,6 @@ public class GameScreen extends WizardScreen {
execute(new StartRoundOverlay(this, round));
}
public void deal() {
execute(parallel(
run(() -> game.sounds.sfxShuffle()),
delay(SoundManager.CARD_SHUFFLE_DURATION)
));
}
public void startTrick() {
clearActivePlayer();
execute(() -> cardStack.clearChildren());
@@ -535,8 +531,6 @@ public class GameScreen extends WizardScreen {
cardStack.add(seat, actor);
sequence.addAction(delay(actor));
sequence.addAction(delay(AnimationTimings.STACK_HOLD));
game.sounds.sfxPlayCard();
}));
execute(sequence);
}
@@ -16,7 +16,7 @@ import eu.jonahbauer.wizard.common.model.Card;
public class InstructionScreen extends MenuScreen {
private static final int MAX_PAGE = 3;
private TextButton buttonBack;
private TextButton buttonOK;
private VerticalGroup content;
private ScrollPane scrollPane;
private TextButton nextPageButton;
@@ -29,14 +29,17 @@ public class InstructionScreen extends MenuScreen {
private final ChangeListener listener = new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonBack) {
if (actor == buttonOK) {
game.getClient().execute(Menu.class, Menu::showMenuScreen);
sfxClick();
} else if (actor == nextPageButton) {
currentPage = MathUtils.clamp(currentPage + 1, 0, MAX_PAGE);
showPage(currentPage);
sfxClick();
} else if (actor == previousPageButton) {
currentPage = MathUtils.clamp(currentPage - 1, 0, MAX_PAGE);
showPage(currentPage);
sfxClick();
}
}
};
@@ -67,9 +70,9 @@ public class InstructionScreen extends MenuScreen {
previousPageButton.addListener(listener);
getButtonGroup().addActor(previousPageButton);
buttonBack = new TextButton(messages.get("menu.instruction.back"), skin);
buttonBack.addListener(listener);
getButtonGroup().addActor(buttonBack);
buttonOK = new TextButton(messages.get("menu.instruction.back"), skin);
buttonOK.addListener(listener);
getButtonGroup().addActor(buttonOK);
nextPageButton = new TextButton(messages.get("menu.instruction.nextPageButton"), skin);
nextPageButton.addListener(listener);
@@ -80,7 +83,7 @@ public class InstructionScreen extends MenuScreen {
scrollPane.setSize(0.65f * WizardGame.WIDTH, 400 + 0.1f * WizardGame.HEIGHT + 80);
stage.addActor(scrollPane);
stage.addCaptureListener(new KeyboardFocusManager(scrollPane, previousPageButton, buttonBack, nextPageButton));
stage.addCaptureListener(new KeyboardFocusManager(scrollPane, previousPageButton, buttonOK, nextPageButton));
showFirstPage();
}
@@ -163,8 +166,9 @@ public class InstructionScreen extends MenuScreen {
reset();
startSection("menu.instruction.variant.title");
addParagraph("menu.instruction.variant.intro");
Label variantsIntro = new Label(messages.get("menu.instruction.variant.intro"), skin);
content.addActor(variantsIntro);
Table table = new Table(skin).padTop(10);
table.defaults().space(10.0f).left().top();
table.columnDefaults(1).grow();
@@ -1,5 +1,6 @@
package eu.jonahbauer.wizard.client.libgdx.screens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
@@ -3,10 +3,7 @@ package eu.jonahbauer.wizard.client.libgdx.screens;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import eu.jonahbauer.wizard.client.libgdx.UiskinAtlas;
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
import eu.jonahbauer.wizard.client.libgdx.actors.IconList;
import eu.jonahbauer.wizard.client.libgdx.listeners.KeyboardFocusManager;
import eu.jonahbauer.wizard.client.libgdx.listeners.ResetErrorListener;
import eu.jonahbauer.wizard.client.libgdx.state.Lobby;
@@ -20,6 +17,7 @@ public class LobbyScreen extends MenuScreen {
private TextButton buttonBack;
private TextButton buttonJoin;
private TextButton buttonRejoin;
private TextButton buttonCreate;
private TextField playerName;
@@ -28,7 +26,6 @@ public class LobbyScreen extends MenuScreen {
private Label labelSessionConfiguration;
private UUID selectedSession;
private boolean rejoin = false;
private List<SessionData> sessions;
private ScrollPane sessionListContainer;
@@ -37,14 +34,16 @@ public class LobbyScreen extends MenuScreen {
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonBack) {
game.getClient().execute(Lobby.class, Lobby::disconnect);
sfxClick();
} else if (actor == buttonJoin) {
if (rejoin) {
game.getClient().execute(Lobby.class, Lobby::showRejoinScreen);
} else {
join();
}
join();
sfxClick();
} else if (actor == buttonCreate) {
game.getClient().execute(Lobby.class, Lobby::showCreateScreen);
sfxClick();
} else if (actor == buttonRejoin) {
game.getClient().execute(Lobby.class, Lobby::showRejoinScreen);
sfxClick();
}
}
};
@@ -65,26 +64,21 @@ public class LobbyScreen extends MenuScreen {
buttonCreate.addListener(listener);
getButtonGroup().addActor(buttonCreate);
buttonRejoin = new TextButton(messages.get("menu.lobby.rejoin"), skin);
buttonRejoin.addListener(listener);
getButtonGroup().addActor(buttonRejoin);
buttonJoin = new TextButton(messages.get("menu.lobby.join"), skin);
buttonJoin.addListener(listener);
getButtonGroup().addActor(buttonJoin);
getButtonGroup().setWidth(0.55f * WizardGame.WIDTH);
sessions = new IconList<>(skin) {
// TODO better icons
private final Drawable running = skin.getDrawable(UiskinAtlas.NOT_READY);
private final Drawable notRunning = skin.getDrawable(UiskinAtlas.READY);
sessions = new List<>(skin) {
@Override
public String toString(SessionData session) {
return session.getName();
}
@Override
public Drawable getIcon(SessionData item) {
return item.isRunning() ? running : notRunning;
}
};
sessions.addListener(new ChangeListener() {
@Override
@@ -108,11 +102,12 @@ public class LobbyScreen extends MenuScreen {
stage.addActor(content);
stage.addCaptureListener(new KeyboardFocusManager(
sessions, playerName, buttonBack, buttonCreate, buttonJoin
sessions, playerName, buttonBack, buttonCreate, buttonRejoin, buttonJoin
));
buttonBack.setName("button_back");
buttonJoin.setName("button_join");
buttonJoin.setName("button_rejoin");
buttonCreate.setName("button_create");
sessions.setName("session_list");
playerName.setName("player_name");
@@ -199,21 +194,14 @@ public class LobbyScreen extends MenuScreen {
labelSessionPlayerCount.setText(Integer.toString(data.getPlayerCount()));
labelSessionConfiguration.setText(data.getConfiguration().toString());
selectedSession = data.getUuid();
updateRejoin(data.isRunning());
} else {
labelSessionName.setText("");
labelSessionPlayerCount.setText("");
labelSessionConfiguration.setText("");
selectedSession = null;
updateRejoin(false);
}
}
private void updateRejoin(boolean rejoin) {
this.rejoin = rejoin;
buttonJoin.setText(messages.get("menu.lobby." + (rejoin ? "rejoin" : "join")));
}
private void join() {
boolean error = false;
@@ -23,10 +23,13 @@ public class MainMenuScreen extends MenuScreen {
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonPlay) {
game.getClient().execute(Menu.class, Menu::showConnectScreen);
sfxClick();
} else if (actor == buttonQuit) {
sfxClick();
Gdx.app.exit();
} else if (actor == buttonInstruction) {
game.getClient().execute(Menu.class, Menu::showInstructionScreen);
sfxClick();
}
}
};
@@ -26,8 +26,10 @@ public class RejoinScreen extends MenuScreen {
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonBack) {
game.getClient().execute(Lobby.class, Lobby::showListScreen);
sfxClick();
} else if (actor == buttonContinue) {
rejoin();
sfxClick();
}
}
};
@@ -1,12 +1,15 @@
package eu.jonahbauer.wizard.client.libgdx.screens;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Align;
import eu.jonahbauer.wizard.client.libgdx.UiskinAtlas;
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
import eu.jonahbauer.wizard.client.libgdx.actors.IconList;
import eu.jonahbauer.wizard.client.libgdx.listeners.KeyboardFocusManager;
import eu.jonahbauer.wizard.client.libgdx.state.Session;
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
@@ -14,7 +17,7 @@ import eu.jonahbauer.wizard.common.model.Configuration;
import java.util.UUID;
public class SessionScreen extends MenuScreen {
public class WaitingScreen extends MenuScreen {
private TextButton buttonLeave;
private TextButton buttonReady;
@@ -31,13 +34,15 @@ public class SessionScreen extends MenuScreen {
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonLeave) {
game.getClient().execute(Session.class, Session::leave);
sfxClick();
} else if (actor == buttonReady) {
game.getClient().execute(Session.class, Session::toggleReady);
sfxClick();
}
}
};
public SessionScreen(WizardGame game) {
public WaitingScreen(WizardGame game) {
super(game);
}
@@ -45,19 +50,19 @@ public class SessionScreen extends MenuScreen {
public void show() {
super.show();
buttonLeave = new TextButton(messages.get("menu.session.leave"), skin);
buttonLeave = new TextButton(messages.get("menu.waiting.leave"), skin);
buttonLeave.addListener(listener);
getButtonGroup().addActor(buttonLeave);
buttonReady = new TextButton(messages.get("menu.session.ready"), skin);
buttonReady = new TextButton(messages.get("menu.waiting.ready"), skin);
buttonReady.addListener(listener);
getButtonGroup().addActor(buttonReady);
getButtonGroup().setWidth(0.55f * WizardGame.WIDTH);
players = new IconList<>(skin) {
private final Drawable ready = skin.getDrawable(UiskinAtlas.READY);
private final Drawable notReady = skin.getDrawable(UiskinAtlas.NOT_READY);
players = new List<>(skin) {
private final TextureRegion ready = skin.getRegion(UiskinAtlas.READY);
private final TextureRegion notReady = skin.getRegion(UiskinAtlas.NOT_READY);
@Override
public String toString(PlayerData player) {
@@ -65,8 +70,16 @@ public class SessionScreen extends MenuScreen {
}
@Override
public Drawable getIcon(PlayerData item) {
return item.isReady() ? ready : notReady;
@SuppressWarnings("SuspiciousNameCombination")
protected GlyphLayout drawItem(Batch batch, BitmapFont font, int index, PlayerData item, float x, float y, float width) {
String string = toString(item);
var height = font.getCapHeight();
if (item.isReady()) {
batch.draw(ready, x, y - height, height, height);
} else {
batch.draw(notReady, x, y - height, height, height);
}
return font.draw(batch, string, x + height + 8, y, 0, string.length(), width - height - 8, Align.left, false, "...");
}
};
@@ -108,13 +121,13 @@ public class SessionScreen extends MenuScreen {
infoTable.columnDefaults(0).growX().width(infoTableWidth);
infoTable.setSize(infoTableWidth, 400);
infoTable.add(messages.get("menu.session.session_name.label")).row();
infoTable.add(messages.get("menu.waiting.session_name.label")).row();
infoTable.add(labelSessionName).row();
infoTable.add(messages.get("menu.session.session_uuid.label")).row();
infoTable.add(messages.get("menu.waiting.session_uuid.label")).row();
infoTable.add(labelSessionUUID).row();
infoTable.add(messages.get("menu.session.session_configuration.label")).row();
infoTable.add(messages.get("menu.waiting.session_configuration.label")).row();
infoTable.add(labelSessionConfiguration).row();
infoTable.add(messages.get("menu.session.player_name.label")).row();
infoTable.add(messages.get("menu.waiting.player_name.label")).row();
infoTable.add(labelPlayerName).row();
return infoTable;
@@ -125,7 +138,7 @@ public class SessionScreen extends MenuScreen {
}
public void setReady(boolean ready) {
buttonReady.setText(messages.get(ready ? "menu.session.not_ready" : "menu.session.ready"));
buttonReady.setText(messages.get(ready ? "menu.waiting.not_ready" : "menu.waiting.ready"));
}
public void addPlayer(PlayerData player) {
@@ -2,6 +2,7 @@ package eu.jonahbauer.wizard.client.libgdx.screens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
@@ -15,7 +16,6 @@ import com.badlogic.gdx.utils.viewport.Viewport;
import eu.jonahbauer.wizard.client.libgdx.UiskinAtlas;
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
import eu.jonahbauer.wizard.client.libgdx.listeners.AutoFocusListener;
import eu.jonahbauer.wizard.client.libgdx.listeners.ButtonClickListener;
import eu.jonahbauer.wizard.client.libgdx.listeners.ButtonKeyListener;
import eu.jonahbauer.wizard.client.libgdx.util.WizardAssetManager;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
@@ -31,6 +31,7 @@ public abstract class WizardScreen implements Screen {
protected Viewport viewport;
private Image background;
private Sound sfxClick;
protected float offsetX;
protected float offsetY;
@@ -55,10 +56,11 @@ public abstract class WizardScreen implements Screen {
stage = new Stage(viewport);
stage.addListener(new ButtonKeyListener());
stage.addListener(new AutoFocusListener());
stage.addListener(new ButtonClickListener(game.sounds));
stage.setDebugAll(WizardGame.DEBUG);
Gdx.input.setInputProcessor(stage);
sfxClick = assets.get(WizardAssetManager.SFX_CLICK);
}
@Override
@@ -108,4 +110,8 @@ public abstract class WizardScreen implements Screen {
public void dispose() {
stage.dispose();
}
protected void sfxClick() {
sfxClick.play(0.6f);
}
}
@@ -68,7 +68,7 @@ public final class AwaitingJoinSession extends Awaiting {
));
} else {
return Optional.of(new Session(
session, sessionName, configuration,
new SessionData(session, sessionName, -1, configuration),
players,
player
));
@@ -6,6 +6,7 @@ import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
import eu.jonahbauer.wizard.client.libgdx.util.Pair;
import eu.jonahbauer.wizard.common.messages.client.InteractionMessage;
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
import eu.jonahbauer.wizard.common.messages.data.SessionData;
import eu.jonahbauer.wizard.common.messages.observer.*;
import eu.jonahbauer.wizard.common.messages.player.*;
import eu.jonahbauer.wizard.common.messages.server.AckMessage;
@@ -117,7 +118,6 @@ public final class Game extends BaseState {
case "starting_round" -> {
return onStartRound(client);
}
case "dealing" -> onDealing();
case "starting_trick" -> onStartTrick();
case "juggling" -> onJuggle();
case "finishing_round" -> onFinishingRound();
@@ -190,10 +190,6 @@ public final class Game extends BaseState {
return Optional.empty();
}
private void onDealing() {
if (gameScreen != null) gameScreen.deal();
}
private void onStartTrick() {
log.info("Trick {} is starting...", trick + 1);
trick ++;
@@ -437,7 +433,7 @@ public final class Game extends BaseState {
private Optional<ClientState> returnToSession() {
return Optional.of(new Session(
session, sessionName, configuration,
new SessionData(session, sessionName, -1, configuration),
players.entrySet().stream()
.map(entry -> new PlayerData(entry.getKey(), entry.getValue(), false))
.toList(),
@@ -1,10 +1,11 @@
package eu.jonahbauer.wizard.client.libgdx.state;
import eu.jonahbauer.wizard.client.libgdx.Client;
import eu.jonahbauer.wizard.client.libgdx.screens.SessionScreen;
import eu.jonahbauer.wizard.client.libgdx.screens.WaitingScreen;
import eu.jonahbauer.wizard.common.messages.client.LeaveSessionMessage;
import eu.jonahbauer.wizard.common.messages.client.ReadyMessage;
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
import eu.jonahbauer.wizard.common.messages.data.SessionData;
import eu.jonahbauer.wizard.common.messages.server.*;
import eu.jonahbauer.wizard.common.model.Configuration;
import lombok.Getter;
@@ -15,7 +16,7 @@ import java.util.*;
@Log4j2
@Getter
public final class Session extends BaseState {
private SessionScreen sessionScreen;
private WaitingScreen sessionScreen;
private final UUID self;
@@ -27,14 +28,14 @@ public final class Session extends BaseState {
private boolean sending;
public Session(UUID session, String name, Configuration configuration, Collection<PlayerData> players, UUID self) {
this(session, name, configuration, players, self, false);
public Session(SessionData session, Collection<PlayerData> players, UUID self) {
this(session, players, self, false);
}
public Session(UUID session, String name, Configuration configuration, Collection<PlayerData> players, UUID self, boolean dontSwitchScreen) {
this.session = session;
this.sessionName = name;
this.configuration = configuration;
public Session(SessionData session, Collection<PlayerData> players, UUID self, boolean dontSwitchScreen) {
this.session = session.getUuid();
this.sessionName = session.getName();
this.configuration = session.getConfiguration();
players.forEach(p -> this.players.put(p.getUuid(), p));
this.dontSwitchScreen = dontSwitchScreen;
@@ -121,7 +122,7 @@ public final class Session extends BaseState {
}
public Optional<ClientState> showInfoScreen(Client client) {
sessionScreen = new SessionScreen(client.getGame());
sessionScreen = new WaitingScreen(client.getGame());
client.getGame().setScreen(sessionScreen);
sessionScreen.setPlayers(players.values().toArray(new PlayerData[0]));
sessionScreen.setReady(players.get(self).isReady());
@@ -70,6 +70,6 @@ public class CardUtil {
);
public Card.Suit getDefaultTrumpSuit(Card card) {
return card == null ? Card.Suit.NONE : DEFAULT_SUITES.get(card);
return DEFAULT_SUITES.get(card);
}
}
@@ -1,47 +0,0 @@
package eu.jonahbauer.wizard.client.libgdx.util;
import com.badlogic.gdx.audio.Sound;
import lombok.Setter;
public class SoundManager {
public static final float CARD_SHUFFLE_DURATION = 4.2f;
private final WizardAssetManager assets;
@Setter
private float sfxVolume = 1;
private final Sound click;
private final Sound cardPlayed;
private final Sound cardShuffle;
public SoundManager(WizardAssetManager assets) {
this.assets = assets;
assets.load(WizardAssetManager.SFX_CLICK, Sound.class);
assets.load(WizardAssetManager.SFX_CARD_PLAYED, Sound.class);
assets.load(WizardAssetManager.SFX_CARD_SHUFFLE, Sound.class);
assets.finishLoading();
this.click = assets.get(WizardAssetManager.SFX_CLICK);
this.cardPlayed = assets.get(WizardAssetManager.SFX_CARD_PLAYED);
this.cardShuffle = assets.get(WizardAssetManager.SFX_CARD_SHUFFLE);
}
public void sfxClick() {
this.click.play(sfxVolume);
}
public void sfxShuffle() {
this.cardShuffle.play(sfxVolume);
}
public void sfxPlayCard() {
this.cardPlayed.play(sfxVolume);
}
public void dispose() {
assets.unload(WizardAssetManager.SFX_CLICK);
assets.unload(WizardAssetManager.SFX_CARD_PLAYED);
assets.unload(WizardAssetManager.SFX_CARD_SHUFFLE);
}
}
@@ -4,6 +4,7 @@ import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.I18NBundleLoader;
import com.badlogic.gdx.assets.loaders.SkinLoader;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
@@ -19,9 +20,7 @@ public class WizardAssetManager {
public static final String ATLAS_SKIN = UiskinAtlas.$PATH;
public static final String ATLAS_GAME = GameAtlas.$PATH;
public static final String SFX_CLICK = "sound/button_click.mp3";
public static final String SFX_CARD_PLAYED = "sound/card_played.mp3";
public static final String SFX_CARD_SHUFFLE = "sound/card_shuffle.mp3";
public static final String SFX_CLICK = "button_click_s.mp3";
public static final String MUSIC_BACKGROUND = "background.mp3";
public static final String CURSOR = "cursor.png";
@@ -36,6 +35,7 @@ public class WizardAssetManager {
manager.load(SKIN, Skin.class, new SkinLoader.SkinParameter(ATLAS_SKIN));
manager.load(MUSIC_BACKGROUND, Music.class);
manager.load(SFX_CLICK, Sound.class);
}
public void loadGame() {
@@ -150,14 +150,14 @@ menu.loading.joining_session=Joining session...
menu.loading.joining_lobby=Joining lobby...
menu.loading.back=Return To Main Menu
menu.session.ready=Ready
menu.session.not_ready=Not Ready
menu.session.leave=Leave
menu.waiting.ready=Ready
menu.waiting.not_ready=Not Ready
menu.waiting.leave=Leave
menu.session.player_name.label=Own Name
menu.session.session_name.label=Session Name
menu.session.session_uuid.label=Session UUID
menu.session.session_configuration.label=Configuration
menu.waiting.player_name.label=Own Name
menu.waiting.session_name.label=Session Name
menu.waiting.session_uuid.label=Session UUID
menu.waiting.session_configuration.label=Configuration
menu.error.malformed_message=Error: Malformed Message
menu.error.unexpected_message=Error: Unexpected Message
@@ -143,14 +143,14 @@ menu.loading.joining_session=Trete Sitzung bei...
menu.loading.joining_lobby=Trete Warteraum bei...
menu.loading.back=Zurück zum Hauptmenü
menu.session.ready=Bereit
menu.session.not_ready=Nicht Bereit
menu.session.leave=Verlassen
menu.waiting.ready=Bereit
menu.waiting.not_ready=Nicht Bereit
menu.waiting.leave=Verlassen
menu.session.player_name.label=Eigener Name
menu.session.session_name.label=Sitzungsname
menu.session.session_uuid.label=Sitzungs-ID
menu.session.session_configuration.label=Spielvariante
menu.waiting.player_name.label=Eigener Name
menu.waiting.session_name.label=Sitzungsname
menu.waiting.session_uuid.label=Sitzungs-ID
menu.waiting.session_configuration.label=Spielvariante
menu.error.malformed_message=Fehler: Missgebildete Nachricht
menu.error.unexpected_message=Fehler: Unerwartete Nachricht
@@ -3,7 +3,7 @@ package eu.jonahbauer.wizard.common.messages.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.jonahbauer.wizard.common.messages.ParseException;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.common.messages.util.SerializationUtil;
import eu.jonahbauer.wizard.common.util.SerializationUtil;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
@@ -26,8 +26,4 @@ public class SessionData {
* Configuration of the session
*/
private final @NonNull Configuration configuration;
/**
* Whether the session is running.
*/
private final boolean running;
}
@@ -2,7 +2,7 @@ package eu.jonahbauer.wizard.common.messages.observer;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.jonahbauer.wizard.common.messages.ParseException;
import eu.jonahbauer.wizard.common.messages.util.SerializationUtil;
import eu.jonahbauer.wizard.common.util.SerializationUtil;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
@@ -2,7 +2,7 @@ package eu.jonahbauer.wizard.common.messages.player;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.jonahbauer.wizard.common.messages.ParseException;
import eu.jonahbauer.wizard.common.messages.util.SerializationUtil;
import eu.jonahbauer.wizard.common.util.SerializationUtil;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
@@ -0,0 +1,26 @@
package eu.jonahbauer.wizard.common.messages.server;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.UUID;
@Getter
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
public final class KickVotedMessage extends ServerMessage {
/**
* UUID of the voting player
*/
private final @NonNull UUID voter;
/**
* UUID of player who is supposed to be kicked
*/
private final @NonNull UUID player;
/**
* Time until the vote ends in {@link System#currentTimeMillis() UNIX time}
*/
private final long timeout;
}
@@ -0,0 +1,18 @@
package eu.jonahbauer.wizard.common.messages.server;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.UUID;
@Getter
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
public final class KickedMessage extends ServerMessage {
/**
* UUID of player who was kicked
*/
private final @NonNull UUID player;
}
@@ -3,12 +3,12 @@ package eu.jonahbauer.wizard.common.messages.server;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.jonahbauer.wizard.common.messages.ParseException;
import eu.jonahbauer.wizard.common.messages.observer.ObserverMessage;
import eu.jonahbauer.wizard.common.messages.util.SerializationUtil;
import eu.jonahbauer.wizard.common.util.SerializationUtil;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
@EqualsAndHashCode
public abstract sealed class ServerMessage permits AckMessage, GameMessage, NackMessage, PlayerLeftMessage, PlayerModifiedMessage, SessionJoinedMessage, SessionListMessage, SessionModifiedMessage, SessionRemovedMessage, StartingGameMessage {
public abstract sealed class ServerMessage permits AckMessage, GameMessage, KickVotedMessage, KickedMessage, NackMessage, PlayerLeftMessage, PlayerModifiedMessage, SessionJoinedMessage, SessionListMessage, SessionModifiedMessage, SessionRemovedMessage, StartingGameMessage {
private static final ObjectMapper MAPPER = SerializationUtil.newObjectMapper(ServerMessage.class, ObserverMessage.class);
public static ServerMessage parse(String json) throws ParseException {
@@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.common.messages.util;
package eu.jonahbauer.wizard.common.util;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@@ -10,10 +10,10 @@ import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import eu.jonahbauer.wizard.common.messages.ParseException;
import eu.jonahbauer.wizard.common.util.StringUtil;
import lombok.experimental.UtilityClass;
import java.lang.reflect.Modifier;
import java.util.Locale;
@UtilityClass
public class SerializationUtil {
@@ -61,7 +61,7 @@ public class SerializationUtil {
if (Modifier.isFinal(modifiers) || subclass.isSealed() && !Modifier.isAbstract(modifiers)) {
var name = subclass.getSimpleName();
if (name.endsWith(suffix)) name = name.substring(0, name.length() - suffix.length());
name = StringUtil.toSnakeCase(name);
name = name.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase(Locale.ROOT);
objectMapper.registerSubtypes(new NamedType(subclass, name));
}
@@ -1,23 +0,0 @@
module eu.jonahbauer.wizard.common {
exports eu.jonahbauer.wizard.common.machine;
exports eu.jonahbauer.wizard.common.messages;
exports eu.jonahbauer.wizard.common.messages.client;
exports eu.jonahbauer.wizard.common.messages.data;
exports eu.jonahbauer.wizard.common.messages.observer;
exports eu.jonahbauer.wizard.common.messages.player;
exports eu.jonahbauer.wizard.common.messages.server;
exports eu.jonahbauer.wizard.common.model;
exports eu.jonahbauer.wizard.common.util;
opens eu.jonahbauer.wizard.common.messages.client to com.fasterxml.jackson.databind;
opens eu.jonahbauer.wizard.common.messages.data to com.fasterxml.jackson.databind;
opens eu.jonahbauer.wizard.common.messages.observer to com.fasterxml.jackson.databind;
opens eu.jonahbauer.wizard.common.messages.player to com.fasterxml.jackson.databind;
opens eu.jonahbauer.wizard.common.messages.server to com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.module.paramnames;
requires static lombok;
requires static org.jetbrains.annotations;
}
@@ -0,0 +1,72 @@
package eu.jonahbauer.wizard.core;
import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayCardMessage;
import eu.jonahbauer.wizard.common.messages.player.PredictMessage;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.messages.Observer;
import eu.jonahbauer.wizard.core.model.GameConfiguration;
import eu.jonahbauer.wizard.core.model.Configurations;
import java.util.List;
import java.util.Scanner;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CLI {
public static void main(String[] args) {
GameConfiguration config = Configurations.DEFAULT;
Observer observer = (player, msg) -> System.out.println(msg);
Game game = new Game(config, observer);
var players = List.of(
UUID.randomUUID(),
UUID.randomUUID(),
UUID.randomUUID(),
UUID.randomUUID()
);
game.start(players);
Scanner scanner = new Scanner(System.in);
Pattern pattern = Pattern.compile("(\\d) ([a-z]+) (.*)");
while (scanner.hasNextLine()) {
try {
Matcher matcher = pattern.matcher(scanner.nextLine());
if (!matcher.find()) {
System.err.println("Format is \"(\\d) ([a-z]+) (.*)\"");
continue;
}
String player = matcher.group(1);
String command = matcher.group(2);
String param = matcher.group(3);
int id = Integer.parseInt(player);
if (id > players.size()) {
System.err.println("ID must be between 0 and " + (players.size() - 1));
continue;
}
switch (command) {
case "predict" -> {
int prediction = Integer.parseInt(param);
game.onMessage(players.get(id), new PredictMessage(prediction));
}
case "play" -> {
Card card = Card.valueOf(param);
game.onMessage(players.get(id), new PlayCardMessage(card));
}
case "trump" -> {
Card.Suit suit = Card.Suit.valueOf(param);
game.onMessage(players.get(id), new PickTrumpMessage(suit));
}
default -> System.err.println("Unknown command: " + command);
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
}
@@ -1,22 +1,18 @@
package eu.jonahbauer.wizard.core;
package eu.jonahbauer.wizard.core.machine;
import eu.jonahbauer.wizard.common.machine.TimeoutContext;
import eu.jonahbauer.wizard.common.messages.observer.ObserverMessage;
import eu.jonahbauer.wizard.common.messages.observer.StateMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.common.model.Configuration;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.TransientState;
import eu.jonahbauer.wizard.core.states.game.Created;
import eu.jonahbauer.wizard.core.states.game.Error;
import eu.jonahbauer.wizard.core.model.Configurations;
import eu.jonahbauer.wizard.core.machine.states.TransientState;
import eu.jonahbauer.wizard.core.machine.states.game.Created;
import eu.jonahbauer.wizard.core.machine.states.game.Error;
import eu.jonahbauer.wizard.core.messages.Observer;
import eu.jonahbauer.wizard.core.model.GameConfiguration;
import eu.jonahbauer.wizard.common.util.StringUtil;
import eu.jonahbauer.wizard.core.util.Util;
import lombok.Getter;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.annotations.VisibleForTesting;
import java.util.List;
import java.util.Random;
@@ -34,25 +30,20 @@ public final class Game extends TimeoutContext<GameState, Game> {
private final CompletableFuture<Void> future = new CompletableFuture<>();
private Game(Random random, Configuration config, long timeout, long syncTimeout, Observer observer) {
public Game(GameConfiguration config, Observer observer) {
super(new Created());
this.random = random;
this.config = Configurations.get(config).withTimeout(timeout).withSyncTimeout(syncTimeout);
this.random = new Random();
this.config = config;
this.observer = observer;
}
public Game(Configuration config, long timeout, long syncTimeout, Observer observer) {
this(new Random(), config, timeout, syncTimeout, observer);
public Game(long seed, GameConfiguration config, Observer observer) {
super(new Created());
this.random = new Random(seed);
this.config = config;
this.observer = observer;
}
@TestOnly
public Game(long seed, Configuration config, long timeout, long syncTimeout, Observer observer) {
this(new Random(seed), config, timeout, syncTimeout, observer);
}
@TestOnly
@VisibleForTesting
@SuppressWarnings("ClassEscapesDefinedScope")
public void resume(GameState state) {
transition(new Created(), state);
}
@@ -65,17 +56,10 @@ public final class Game extends TimeoutContext<GameState, Game> {
execute(s -> s.onMessage(this, player, message));
}
public void onMessage(UUID player, PlayerMessage message, Runnable preHandleMessage) {
execute(s -> {
preHandleMessage.run();
return s.onMessage(this, player, message);
});
}
@Override
protected void onTransition(GameState from, GameState to) {
if (!(to instanceof TransientState)) {
notify(new StateMessage(to != null ? StringUtil.toSnakeCase(to.getClass().getSimpleName()) : "null"));
notify(new StateMessage(to != null ? Util.toSnakeCase(to.getClass().getSimpleName()) : "null"));
}
}
@@ -1,9 +1,10 @@
package eu.jonahbauer.wizard.core.states;
package eu.jonahbauer.wizard.core.machine;
import eu.jonahbauer.wizard.common.machine.TimeoutState;
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.states.SyncState;
import lombok.Getter;
import org.jetbrains.annotations.Unmodifiable;
@@ -12,8 +13,8 @@ import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import static eu.jonahbauer.wizard.core.states.GameData.CURRENT_PLAYER;
import static eu.jonahbauer.wizard.core.states.GameData.PLAYERS;
import static eu.jonahbauer.wizard.core.machine.states.GameData.CURRENT_PLAYER;
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
@Unmodifiable
public abstract class GameState implements TimeoutState<GameState, Game> {
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.states;
package eu.jonahbauer.wizard.core.machine.states;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
@@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.core.states;
package eu.jonahbauer.wizard.core.machine.states;
public class InvalidDataException extends RuntimeException {
public InvalidDataException(String message) {
@@ -1,10 +1,11 @@
package eu.jonahbauer.wizard.core.states;
package eu.jonahbauer.wizard.core.machine.states;
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import java.util.HashSet;
import java.util.Optional;
@@ -13,7 +14,7 @@ import java.util.UUID;
import java.util.function.Function;
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC;
import static eu.jonahbauer.wizard.core.states.GameData.PLAYERS;
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
public final class SyncState extends GameState implements TransientState {
private final transient Set<UUID> ready = new HashSet<>();
@@ -0,0 +1,4 @@
package eu.jonahbauer.wizard.core.machine.states;
public interface TransientState {
}
@@ -1,8 +1,8 @@
package eu.jonahbauer.wizard.core.states.game;
package eu.jonahbauer.wizard.core.machine.states.game;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import java.util.List;
import java.util.Optional;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.states.game;
package eu.jonahbauer.wizard.core.machine.states.game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import lombok.Getter;
@Getter
@@ -1,8 +1,8 @@
package eu.jonahbauer.wizard.core.states.game;
package eu.jonahbauer.wizard.core.machine.states.game;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import java.util.Optional;
@@ -1,13 +1,13 @@
package eu.jonahbauer.wizard.core.states.game;
package eu.jonahbauer.wizard.core.machine.states.game;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.common.messages.observer.ScoreMessage;
import java.util.Optional;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public final class Finishing extends GameState {
@@ -0,0 +1,22 @@
package eu.jonahbauer.wizard.core.machine.states.game;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.round.StartingRound;
import java.util.Optional;
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
public final class Starting extends GameState {
public Starting(GameData data) {
super(data.require(PLAYERS));
}
@Override
public Optional<GameState> onEnter(Game game) {
return transition(new StartingRound(getData()));
}
}
@@ -1,14 +1,14 @@
package eu.jonahbauer.wizard.core.states.round;
package eu.jonahbauer.wizard.core.machine.states.round;
import eu.jonahbauer.wizard.common.messages.observer.PredictionMessage;
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.common.messages.player.PredictMessage;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.InvalidDataException;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.InvalidDataException;
import java.util.HashMap;
import java.util.Map;
@@ -16,7 +16,7 @@ import java.util.Optional;
import java.util.UUID;
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.CHANGE_PREDICTION;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public final class ChangingPrediction extends RoundState {
private transient final int oldPrediction;
@@ -1,15 +1,15 @@
package eu.jonahbauer.wizard.core.states.round;
package eu.jonahbauer.wizard.core.machine.states.round;
import eu.jonahbauer.wizard.common.messages.observer.HandMessage;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.model.deck.Deck;
import java.util.*;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public final class Dealing extends RoundState {
@@ -1,50 +1,69 @@
package eu.jonahbauer.wizard.core.states.round;
package eu.jonahbauer.wizard.core.machine.states.round;
import eu.jonahbauer.wizard.common.messages.observer.HandMessage;
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.common.messages.observer.HandMessage;
import eu.jonahbauer.wizard.common.messages.observer.TrumpMessage;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.TransientState;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.model.card.GameCards;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.PICK_TRUMP;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.states.GameData.TRUMP_CARD;
public final class DeterminingTrumpUserInput extends RoundState implements TransientState {
private final transient UUID player;
private final transient boolean werewolf;
public final class DeterminingTrump extends RoundState {
private transient UUID player;
private transient boolean werewolf;
public DeterminingTrumpUserInput(GameData data) {
super(data.require(TRUMP_CARD).requireEach(PLAYERS, HANDS).require(CURRENT_PLAYER));
this.player = get(CURRENT_PLAYER);
this.werewolf = get(HANDS).get(this.player).contains(Card.WEREWOLF);
public DeterminingTrump(GameData data) {
super(data.require(TRUMP_CARD).requireEach(PLAYERS, HANDS));
}
@Override
public Optional<GameState> onEnter(Game game) {
game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true)));
return timeout(game);
Card trumpCard = get(TRUMP_CARD);
// handle werewolf
for (Map.Entry<UUID, List<Card>> entry : get(HANDS).entrySet()) {
var player = entry.getKey();
var hand = entry.getValue();
if (hand.contains(Card.WEREWOLF)) {
this.player = player;
this.werewolf = true;
game.notify(new TrumpMessage(trumpCard, null));
game.notify(new TrumpMessage(Card.WEREWOLF, null));
game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true)));
return timeout(game);
}
}
// default trump handling
Card.Suit trumpSuit = trumpCard != null ? GameCards.get(trumpCard).getTrumpSuit() : Card.Suit.NONE;
if (trumpSuit == null) {
this.player = getDealer();
game.notify(new TrumpMessage(trumpCard, null));
game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true)));
return timeout(game);
} else {
return transition(game, trumpSuit);
}
}
@Override
public Optional<GameState> onTimeout(Game game) {
game.notify(new TimeoutMessage());
Card.Suit[] suits;
if (werewolf) {
suits = new Card.Suit[] {Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW, Card.Suit.NONE};
suits = new Card.Suit[]{Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW, Card.Suit.NONE};
} else {
suits = new Card.Suit[] {Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW};
suits = new Card.Suit[]{Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW};
}
return transition(game, suits[game.getRandom().nextInt(suits.length)]);
}
@@ -1,9 +1,9 @@
package eu.jonahbauer.wizard.core.states.round;
package eu.jonahbauer.wizard.core.machine.states.round;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.game.Finishing;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.game.Finishing;
import eu.jonahbauer.wizard.common.messages.observer.ScoreMessage;
import java.util.HashMap;
@@ -11,7 +11,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public final class FinishingRound extends RoundState {
@@ -1,10 +1,10 @@
package eu.jonahbauer.wizard.core.states.round;
package eu.jonahbauer.wizard.core.machine.states.round;
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.trick.StartingTrick;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.trick.StartingTrick;
import eu.jonahbauer.wizard.common.messages.observer.PredictionMessage;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
@@ -16,7 +16,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.MAKE_PREDICTION;
@Getter
@@ -1,11 +1,11 @@
package eu.jonahbauer.wizard.core.states.round;
package eu.jonahbauer.wizard.core.machine.states.round;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import java.util.UUID;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public abstract class RoundState extends GameState {
public static GameData requirements(GameData data) {
@@ -1,8 +1,8 @@
package eu.jonahbauer.wizard.core.states.round;
package eu.jonahbauer.wizard.core.machine.states.round;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import java.util.Optional;
@@ -1,19 +1,19 @@
package eu.jonahbauer.wizard.core.states.trick;
package eu.jonahbauer.wizard.core.machine.states.trick;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.InvalidDataException;
import eu.jonahbauer.wizard.core.states.round.ChangingPrediction;
import eu.jonahbauer.wizard.core.states.round.FinishingRound;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.InvalidDataException;
import eu.jonahbauer.wizard.core.machine.states.round.ChangingPrediction;
import eu.jonahbauer.wizard.core.machine.states.round.FinishingRound;
import eu.jonahbauer.wizard.common.messages.observer.TrickMessage;
import eu.jonahbauer.wizard.core.model.card.*;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import java.util.*;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public final class FinishingTrick extends TrickState {
@@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.core.states.trick;
package eu.jonahbauer.wizard.core.machine.states.trick;
import eu.jonahbauer.wizard.common.messages.observer.HandMessage;
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
@@ -6,15 +6,15 @@ import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.JuggleMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.GameState;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.*;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public final class Juggling extends TrickState {
private final transient Map<UUID, Card> juggledCards = new ConcurrentHashMap<>();
@@ -1,22 +1,22 @@
package eu.jonahbauer.wizard.core.states.trick;
package eu.jonahbauer.wizard.core.machine.states.trick;
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.InvalidDataException;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.InvalidDataException;
import eu.jonahbauer.wizard.common.messages.observer.CardMessage;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayCardMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.core.model.card.GameCards;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.PLAY_CARD;
public final class PlayingCard extends TrickState {
@@ -1,8 +1,8 @@
package eu.jonahbauer.wizard.core.states.trick;
package eu.jonahbauer.wizard.core.machine.states.trick;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import java.util.Optional;
@@ -1,9 +1,9 @@
package eu.jonahbauer.wizard.core.states.trick;
package eu.jonahbauer.wizard.core.machine.states.trick;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.round.RoundState;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.states.round.RoundState;
import static eu.jonahbauer.wizard.core.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
public abstract class TrickState extends RoundState {
public static GameData requirements(GameData data) {
@@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.core;
package eu.jonahbauer.wizard.core.messages;
import eu.jonahbauer.wizard.common.messages.observer.ObserverMessage;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.model.card;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import lombok.experimental.UtilityClass;
import java.util.Comparator;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.model.card;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import java.util.List;
import java.util.UUID;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.model.card;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import java.util.List;
import java.util.UUID;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.model.card;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import lombok.Getter;
import java.util.List;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.model.card;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import lombok.Getter;
import java.util.List;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.model.card;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.Contract;
@@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.core.model.card;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.util.Pair;
import eu.jonahbauer.wizard.core.util.Pair;
import lombok.Getter;
import java.util.List;
@@ -1,4 +0,0 @@
package eu.jonahbauer.wizard.core.states;
public interface TransientState {
}
@@ -1,22 +0,0 @@
package eu.jonahbauer.wizard.core.states.game;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.states.round.StartingRound;
import java.util.Optional;
import static eu.jonahbauer.wizard.core.states.GameData.PLAYERS;
public final class Starting extends GameState {
public Starting(GameData data) {
super(data.require(PLAYERS));
}
@Override
public Optional<GameState> onEnter(Game game) {
return transition(new StartingRound(getData()));
}
}
@@ -1,56 +0,0 @@
package eu.jonahbauer.wizard.core.states.round;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.common.messages.observer.TrumpMessage;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.model.card.GameCards;
import java.util.*;
import static eu.jonahbauer.wizard.core.states.GameData.*;
public final class DeterminingTrump extends RoundState {
public DeterminingTrump(GameData data) {
super(data.require(TRUMP_CARD).requireEach(PLAYERS, HANDS));
}
@Override
public Optional<GameState> onEnter(Game game) {
Card trumpCard = get(TRUMP_CARD);
// handle werewolf
for (Map.Entry<UUID, List<Card>> entry : get(HANDS).entrySet()) {
var player = entry.getKey();
var hand = entry.getValue();
if (hand.contains(Card.WEREWOLF)) {
game.notify(new TrumpMessage(trumpCard, null));
game.notify(new TrumpMessage(Card.WEREWOLF, null));
var data = getData().with(CURRENT_PLAYER, player);
return sync(data, DeterminingTrumpUserInput::new);
}
}
// default trump handling
Card.Suit trumpSuit = trumpCard != null ? GameCards.get(trumpCard).getTrumpSuit() : Card.Suit.NONE;
if (trumpSuit == null) {
var player = getDealer();
game.notify(new TrumpMessage(trumpCard, null));
var data = getData().with(CURRENT_PLAYER, player);
return sync(data, DeterminingTrumpUserInput::new);
} else {
var data = getData().with(
TRUMP_SUIT, trumpSuit,
CURRENT_PLAYER, getNextPlayer(getDealer())
);
game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit));
return sync(data, Predicting::new);
}
}
}
@@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.common.util;
package eu.jonahbauer.wizard.core.util;
import java.util.Map;
@@ -1,11 +1,11 @@
package eu.jonahbauer.wizard.common.util;
package eu.jonahbauer.wizard.core.util;
import lombok.experimental.UtilityClass;
import java.util.Locale;
@UtilityClass
public class StringUtil {
public class Util {
public static String toSnakeCase(String str) {
return str.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase(Locale.ROOT);
}
@@ -1,8 +0,0 @@
module eu.jonahbauer.wizard.core {
exports eu.jonahbauer.wizard.core;
requires eu.jonahbauer.wizard.common;
requires static lombok;
requires static org.jetbrains.annotations;
}
@@ -1,7 +1,6 @@
package eu.jonahbauer.wizard.core;
package eu.jonahbauer.wizard.core.machine;
import eu.jonahbauer.wizard.common.model.Configuration;
import eu.jonahbauer.wizard.core.Game;
import eu.jonahbauer.wizard.core.model.Configurations;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
@@ -14,7 +13,7 @@ public class GameTest {
public void runDefault(RepetitionInfo repetitionInfo) throws InterruptedException, ExecutionException {
Game game = new Game(
repetitionInfo.getCurrentRepetition(),
Configuration.DEFAULT, 0, 0,
Configurations.DEFAULT.withTimeout(0).withSyncTimeout(0),
(player, msg) -> System.out.println(msg)
);
var players = List.of(
@@ -32,7 +31,7 @@ public class GameTest {
public void runAnniversary2016(RepetitionInfo repetitionInfo) throws InterruptedException, ExecutionException {
Game game = new Game(
repetitionInfo.getCurrentRepetition(),
Configuration.ANNIVERSARY_2016, 0, 0,
Configurations.ANNIVERSARY_2016.withTimeout(0).withSyncTimeout(0),
(player, msg) -> System.out.println(msg)
);
var players = List.of(
@@ -50,7 +49,7 @@ public class GameTest {
public void runAnniversary2021(RepetitionInfo repetitionInfo) throws InterruptedException, ExecutionException {
Game game = new Game(
repetitionInfo.getCurrentRepetition(),
Configuration.ANNIVERSARY_2021, 0, 0,
Configurations.ANNIVERSARY_2021.withTimeout(0).withSyncTimeout(0),
(player, msg) -> System.out.println(msg)
);
var players = List.of(
@@ -1,6 +1,6 @@
package eu.jonahbauer.wizard.core;
package eu.jonahbauer.wizard.core.machine;
import eu.jonahbauer.wizard.core.states.game.Finished;
import eu.jonahbauer.wizard.core.machine.states.game.Finished;
import lombok.experimental.UtilityClass;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
@@ -1,11 +1,11 @@
package eu.jonahbauer.wizard.core;
package eu.jonahbauer.wizard.core.machine;
import eu.jonahbauer.wizard.common.messages.observer.ObserverMessage;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.*;
import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.states.GameData;
import eu.jonahbauer.wizard.core.states.GameState;
import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.messages.Observer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

Some files were not shown because too many files have changed in this diff Show More