670 Commits

Author SHA1 Message Date
Fleischer Hanno
ec295c94f1 fixed the equals method in piece 2024-12-08 11:23:53 +01:00
Hanno Fleischer
c9c99709ba added more communication fixes, states now use correct messages 2024-12-08 09:52:23 +01:00
Hanno Fleischer
8b27ccce22 adjusted stattransition methods to work correctly 2024-12-08 03:08:47 +01:00
Hanno Fleischer
8c22d935a9 implemented rest of the server logic in choosepiece substates, and began to fix bugs after testing 2024-12-08 01:59:29 +01:00
Hanno Fleischer
0c49d7ed1c Merge branch 'dev/server_h' of https://athene1.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into dev/server_h 2024-12-07 15:37:02 +01:00
Hanno Fleischer
2ba6a22422 Merge branch 'development' into 'dev/server_h'
Development

See merge request progproj/gruppen-ht24/Gruppe-01!37
2024-12-07 14:36:25 +00:00
Hanno Fleischer
c37bac4614 replaced DicaAgain message with DicveNow 2024-12-07 15:34:34 +01:00
Felix Koppe
06b37584cb Merge dev/client_beck into development 2024-12-07 15:05:03 +01:00
Felix Koppe
0c42a2df88 Merge branch 'dev/client_beck' into development
# Conflicts:
#	Projekte/mdga/client/src/main/java/pp/mdga/client/Asset.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/InputSynchronizer.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/AcousticHandler.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/MdgaSound.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/SoundAsset.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/animation/JetAnimation.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/board/BoardHandler.java
#	Projekte/mdga/model/src/main/java/pp/mdga/client/gamestate/GameStates.java
2024-12-07 15:00:27 +01:00
Felix Koppe
d75d704878 Add smoke effekt to missileAnimation 2024-12-07 14:55:08 +01:00
Cedric Beck
6d3c733f91 added effect for shell flying 2024-12-07 14:45:39 +01:00
Felix Koppe
f96da2c46c Add notification delay 2024-12-07 14:37:19 +01:00
Cedric Beck
1a079dad44 added shell asset for ShellAnimation 2024-12-07 14:22:36 +01:00
Cedric Beck
32f49a6181 added shellAnimation without shell asset 2024-12-07 13:30:30 +01:00
Felix Koppe
525809899e Minor improvements 2024-12-07 11:03:30 +01:00
Felix Koppe
fd9708752c Merge dev/model into development 2024-12-06 18:49:15 +01:00
Hanno Fleischer
5a9f7a8118 added AnimationEndMessages to 'RollDiceState', 'MovePieceState' and 'PlayPowerCardState' 2024-12-06 18:45:14 +01:00
Felix Koppe
236d3db930 Add ambience 2024-12-06 18:10:09 +01:00
Cedric Beck
29c6b13300 added MatrixAnimation 2024-12-06 17:09:06 +01:00
Felix Koppe
6059e93276 Fix interruptDialog 2024-12-06 16:52:08 +01:00
Felix Koppe
f2eeb6dab4 Fix logic error regarding cardSelection 2024-12-06 16:27:01 +01:00
Hanno Fleischer
2e1fe3c050 fixed a missing method call ind TurnState and removed debug sout statements ind 'RollDiceMessage' 2024-12-06 15:19:04 +01:00
Cedric Beck
2ac2de645b working on matrix-animation 2024-12-06 14:56:04 +01:00
Felix Koppe
d39f85fbe9 Add some javaDoc to client 2024-12-06 14:26:13 +01:00
Felix Koppe
960a57caba Fix broken lose sound 2024-12-06 13:28:38 +01:00
Felix Koppe
36631df2e9 Fix broken jet-sound 2024-12-06 13:26:28 +01:00
Felix Koppe
df27c23cd5 Fix shadercode 2024-12-06 13:19:17 +01:00
Felix Koppe
acd64d1507 Fix shadercode 2024-12-06 13:14:54 +01:00
Felix Koppe
76f86c8a66 Improve audioSettings 2024-12-06 11:35:05 +01:00
Hanno Fleischer
308b592b65 Merge branch 'development' into 'dev/model'
Development merge

See merge request progproj/gruppen-ht24/Gruppe-01!36
2024-12-06 09:55:19 +00:00
Felix Koppe
c4e7fb1d41 Fix logic in modelSyncronizer 2024-12-06 10:54:02 +01:00
Felix Koppe
aacc0440b3 Update .gitignore 2024-12-06 10:33:13 +01:00
Hanno Fleischer
43c0e3bcc7 Merge branch 'development' into 'dev/model'
Development

See merge request progproj/gruppen-ht24/Gruppe-01!35
2024-12-06 09:09:29 +00:00
Felix Koppe
95635f5fb7 Fix ownColor in gameView 2024-12-06 09:59:28 +01:00
Felix Koppe
e337b1f888 Fix card select issue 2024-12-06 09:57:28 +01:00
Felix Koppe
0237bcc4be Fix card select issue 2024-12-06 09:51:17 +01:00
Felix Koppe
26836d16cc Fix card select issue 2024-12-06 09:48:24 +01:00
Felix Koppe
a6c8cc33f4 Make cardSelect trigger needCconfirm 2024-12-06 09:31:02 +01:00
Felix Koppe
7f5f4b8c68 Fix broken sound 2024-12-06 09:24:49 +01:00
Felix Koppe
7f3483aa6b Add broken sound 2024-12-06 09:22:10 +01:00
Felix Koppe
8422b7be1e Merge branch 'development' into dev/client_koppe2 2024-12-06 09:11:09 +01:00
Felix Koppe
f0b23ab9c2 Readd broken files 2024-12-06 09:10:47 +01:00
Felix Koppe
78f1dbb3d3 Remove broken files 2024-12-06 09:08:52 +01:00
Daniel Grigencha
4904b32ea3 Updated 'ChoosePieceState' class.
Updated the 'ChoosePieceState' class by adding the 'RequestMoveMessage' handling to it.
2024-12-06 08:58:51 +01:00
Daniel Grigencha
b00219c4fb Updated 'PlayPowerCardState' class.
Updated the 'PlayPowerCardState' class by adding the 'AnimationEndMessage' handling to it.
2024-12-06 08:58:01 +01:00
Daniel Grigencha
12cf5f3e71 Updated 'PowerCardState' class.
Updated the 'PowerCardState' class by adding the 'SelectedPiecesMessage' handling to it.
2024-12-06 08:57:08 +01:00
Daniel Grigencha
77b0207214 Updated 'TurnState' class.
Updated the 'TurnState' class by adding the 'SelectedPiecesMessage', 'NoPowerCardMessage', 'RequestDieMessage' and 'ReuqestMoveMessage' handling to it.
2024-12-06 08:56:21 +01:00
Daniel Grigencha
a18165bc02 Updated 'Game' class.
Updated the 'Game' class by commenting out the creation of turbo and shield cards. This is only for testing purposes.
2024-12-06 08:55:01 +01:00
Felix Koppe
9e758e4417 Merge branch 'dev/model' into dev/client_koppe2 2024-12-06 08:11:37 +01:00
Daniel Grigencha
62ceff822f Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by adding logic for the roll again event to the 'RequestDieMessage' handling.
2024-12-06 04:54:14 +01:00
Hanno Fleischer
33afc4ab3b added selectDice method in RollDiceState 2024-12-06 04:48:05 +01:00
Daniel Grigencha
322d539cfd Merge branch 'dev/model' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into dev/model 2024-12-06 04:28:40 +01:00
Daniel Grigencha
9c4f2387ee Updated 'FirstRollState', 'SecondRollState' and 'ThirdROllState' classes.
Updated the 'FirstRollState', 'SecondRollState' and 'ThirdROllState' class by adding the 'received(RequestDieMessage msg, int from)' method to them.
2024-12-06 04:28:33 +01:00
Daniel Grigencha
9d1430e488 Updated 'AnimationState' class.
Updated the 'AnimationState' class by setting the data type of 'messageReceived' from 'Map' to 'Set'.
2024-12-06 04:27:10 +01:00
Daniel Grigencha
dd2146d417 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by setting the data type of 'messageReceived' from 'Map' to 'Set'.
2024-12-06 04:26:38 +01:00
Daniel Grigencha
d9ad0f0a4b Updated 'LobbyState' class.
Updated the 'LobbyState' class by setting the first waiting piece on the start node.
2024-12-06 04:25:45 +01:00
Hanno Fleischer
0368ec8541 implemented the correct transition, when the player can play no powercard 2024-12-06 04:18:58 +01:00
Daniel Grigencha
72f0bc5a2f Updated 'RollDiceState' class.
Updated the 'RollDiceState' class by adding the 'received(RequestDieMessage msg, int from)' method to it.
2024-12-06 04:17:29 +01:00
Daniel Grigencha
23ae4a3080 Updated 'DetermineStartPlayaerState' class.
Updated the 'DetermineStartPlayerState' class by calling the right method of the 'entry' inside the 'RequestDieMessage' handling.
2024-12-06 04:14:42 +01:00
Daniel Grigencha
765b1884fe Updated 'AnimationState' class.
Updated the 'AnimationState' class by removing the unused 'DiceNowMessage' call from it.
2024-12-06 03:57:42 +01:00
Daniel Grigencha
e3febd6ba1 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by removing the 'rolls' attribute and its usage from it.
2024-12-06 03:49:39 +01:00
Daniel Grigencha
1a562a8d38 Updated 'DeterminStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by adding the multi roll support to it. In Addition, the server model will be updated correctly.
2024-12-06 03:29:11 +01:00
Daniel Grigencha
39ed4238b5 Updated 'AnimationState' class.
Updated the 'AnimationState' class by adding a missing semicolon.
2024-12-06 03:27:55 +01:00
Daniel Grigencha
620063e894 Updated 'AnimationState' class.
Updated the 'AnimationState' class by updating the 'messageReceived' attribute in it. In Addition, the 'AnimationEndMessage' handling was updated.
2024-12-06 03:22:25 +01:00
Daniel Grigencha
2d0788eb72 Updated 'TurnState' class.
Updated the 'TurnState' class by updating the imports in it.
2024-12-06 03:20:28 +01:00
Daniel Grigencha
8470a96908 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by updating the 'AnimationEndMessage' handling in it. In Addition, the 'RequestDieMessage' handling was updated as well.
2024-12-06 02:55:14 +01:00
Hanno Fleischer
a6205c982a now sending AnimationEndMessage when in Waitranking State 2024-12-06 02:40:16 +01:00
Daniel Grigencha
58b9298c91 Merge branch 'dev/model' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into dev/model 2024-12-06 02:38:53 +01:00
Daniel Grigencha
1e6856744b Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by adding the 'received(AnimationEndMessage msg, int from)' method to it.
2024-12-06 02:38:46 +01:00
Hanno Fleischer
f713e00c36 made all 'PowerCards' serializable 2024-12-06 02:30:13 +01:00
Daniel Grigencha
81ae896ae8 Updated 'TurnState' class.
Updated the 'TurnState' class by removing the start state of this state machine of the constructor.
2024-12-06 02:22:46 +01:00
Daniel Grigencha
5b55d39c9a Updated 'AnimationState' class.
Updated the 'AnimationState' class by solving the transition error due to the separat state change.
2024-12-06 02:22:07 +01:00
Hanno Fleischer
f36e2ff7bb adjusted the getter for the card in the intro to get BonusCards instead of PowerCards 2024-12-06 02:16:58 +01:00
Hanno Fleischer
16afe95aa6 Merge branch 'dev/model' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into dev/model 2024-12-06 02:13:08 +01:00
Hanno Fleischer
55d398b428 adjusted all useages of the SelectedPieces consturctor to transfer the right parameters 2024-12-06 02:12:59 +01:00
Daniel Grigencha
affa2ecd7e Added 'ChoosePowerCardState', 'ShieldCardState', 'SwapCardState' and 'TurboCardState' classes.
Updated the 'ChoosePowerCardState', 'ShieldCardState', 'SwapCardState' and 'TurboCardState' classes to this project. They will be used inside the power card state. In Addition, the abstract 'PowerCardAutomatonState' class was added.
2024-12-06 02:11:32 +01:00
Hanno Fleischer
0a1bd1f503 adjusted all State containing 'received(PlayCardMessage msg)' to work with the new message 2024-12-06 02:04:55 +01:00
Daniel Grigencha
a2867fc88a Added 'ServerCardVisitor' class.
Added the 'ServerCardVisitor' class to this project. It will be used as a visitor on the server to differentiate between all types of power cards.
2024-12-06 01:41:45 +01:00
Daniel Grigencha
c6761d91d1 Updated 'PowerCardState' class.
Updated the 'PowerCardState' class by updating the content of the 'enter' in it.
2024-12-06 01:37:24 +01:00
Daniel Grigencha
5708ee6ffe Updated 'PlayCardMessage' class.
Updated the 'PlayCardMessage' class by removing the 'ownPieceID' and 'enemyPieceID' attributes and their getter methods from it. In Addition, the 'pieces' attribute and its getter method was added.
2024-12-06 01:28:44 +01:00
Hanno Fleischer
d61b68aa41 overrode hachCode and equals method of Piece 2024-12-06 01:15:06 +01:00
Daniel Grigencha
e98418b274 Merge branch 'dev/model' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into dev/model 2024-12-06 01:06:20 +01:00
Daniel Grigencha
66dc9c02ea Updated 'PowerCardState' class.
Updated the 'PowerCardState' class by adding the 'currentState', 'choosePowerCardState', 'shieldCardState', 'swapCardState' and 'turboCardState' attributes and its getter methods to it. In Addition, logic was written into the 'enter' method.
2024-12-06 00:53:11 +01:00
Daniel Grigencha
dd95356abd Updated 'TurnState' class.
Updated the 'TurnState' class by adding the 'player' attribute and its getter method to it.
2024-12-06 00:50:48 +01:00
Daniel Grigencha
84776c71b2 Updated 'SelectedPiecesMessage' class.
Updated the 'SelectedPiecesMessage' class by removing 'pieceIdentifier' attribute and its getter method from it. In Addition, the 'pieces' attribute and its getter method was added.
2024-12-06 00:47:33 +01:00
Daniel Grigencha
d07eee6251 Updated 'Piece' class.
Updated the 'Piece' class by overwriting the 'toString' method in it.
2024-12-06 00:45:56 +01:00
Hanno Fleischer
b601ff2cf7 renamed 'PossibleCardMEssage' to 'PossibleCardsMessage' and completed JavaDocs for method 'getPowerCardByType' in 'Player' 2024-12-06 00:36:06 +01:00
Hanno Fleischer
04119d2f3e modified 'ChoosePowerCardState' to work with PowerCards as well as adjusted 'SelectcardMessage' to use 'PowerCards' 2024-12-06 00:31:12 +01:00
Hanno Fleischer
a92c06a70e added a method in 'Player' to return the first 'PowerCard' of a specific Type 2024-12-06 00:30:08 +01:00
Daniel Grigencha
50f9c0ef0c Updated 'PossibleCardMessage' class.
Updated the 'PossibleCardMessage' class by replacing all 'BonusCard' with 'PowerCard' in it.
2024-12-06 00:19:11 +01:00
Daniel Grigencha
f7f246daaa Merge branch 'dev/model' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into dev/model 2024-12-06 00:16:42 +01:00
Daniel Grigencha
8a738a3633 Updated 'Game' class.
Updated the 'Game' class by replacing all 'BonusCard' with 'PowerCard' in it.
2024-12-06 00:16:38 +01:00
Daniel Grigencha
3a32a7ebf7 Updated 'Player' class.
Updated the 'Player' class by replacing all 'BonusCard' with 'PowerCard' in it.
2024-12-06 00:11:50 +01:00
Daniel Grigencha
6894802c00 Added 'HiddenCard', 'ShieldCard', 'SwapCard' and 'TurboCard' classes.
Updated the 'HiddenCard', 'ShieldCard', 'SwapCard' and 'TurboCard' classes to this project. They will be used to display different types of power cards.
2024-12-06 00:04:21 +01:00
Daniel Grigencha
a09211da5f Updated abstract 'PowerCard' class.
Updated the abstract 'PowerCard' class by setting the 'card' attribute to 'protected' in it.
2024-12-06 00:03:16 +01:00
Daniel Grigencha
c9c9c5dcf6 Added abstract 'PowerCard' class.
Added the abstract 'PowerCard' class to this project. It will be used to display different types of hand cards.
2024-12-05 23:58:43 +01:00
Daniel Grigencha
1e46b1dc59 Added 'Visitor' interface.
Added the 'Visitor' interface to this project. It will be used to handle all types of power cards.
2024-12-05 23:54:55 +01:00
Hanno Fleischer
6c74acc334 added a getter for the BonusCrad in PowerCard 2024-12-05 23:07:22 +01:00
Hanno Fleischer
421231aa12 made BonusCard Serializable and added the method calls to display handcards during the intro 2024-12-05 22:46:48 +01:00
Daniel Grigencha
d8bb458e9c Updated 'LobbyState' class.
Updated the 'LobbyState' class by updating the 'initializeGame' method in it.
2024-12-05 23:45:24 +01:00
Hanno Fleischer
f0080118d0 Changed and :
removed the selectAnimationEnd Method from Waitranking and moved logic into the receivedActivePlayerMessage. Added in selectStart to always send a StartGameMessage in order to trigger incorrectRequestMEssage
2024-12-05 22:34:53 +01:00
Daniel Grigencha
8a438ab069 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by updating the whole start player determination process in it.
2024-12-05 23:29:21 +01:00
Daniel Grigencha
0ce8184069 Updated 'Game' class.
Updated the 'Game' class by adding the 'draw' method to it. In Addition, the 'initializeDrawPile' method was updated by shuffling the 'drawPile' attribute after filling it.
2024-12-05 23:27:06 +01:00
Felix Koppe
2c524477d7 Merge branch 'dev/model' into dev/client_koppe2 2024-12-05 22:18:00 +01:00
Felix Koppe
587af466e8 Merge branch 'development' into dev/client_koppe2
# Conflicts:
#	Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java
2024-12-05 22:17:53 +01:00
Felix Koppe
8d398450f1 Minor changes 2024-12-05 22:15:59 +01:00
Felix Koppe
0a96dd6f9f Repair sounds 2024-12-05 22:07:36 +01:00
Felix Koppe
e8a556de27 Add missle 2024-12-05 22:02:02 +01:00
Hanno Fleischer
1214d3c87c added an getter for the error id in the IncorrectrequestMessage and implemeted how to handle it in the client game logic. 2024-12-05 21:11:40 +01:00
Daniel Grigencha
f2c34aee2d Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by updating the 'received(RequestDieMessage msg, int from)' method in it.
2024-12-05 22:03:48 +01:00
Daniel Grigencha
2da1fec7dd Updated 'RankingResponseMessage' class.
Updated the 'RankingResponseMessage' class by removing the 'startingPlayerId' attribute and its getter method from it. In Addition the 'rankingResults' attribute and its getter method were added.
2024-12-05 22:01:05 +01:00
Daniel Grigencha
5d76a89b95 Updated 'LobbyState' class.
Updated the 'LobbyState' class by updating the 'JoinedLobbyMessage' and 'LobbyReadyMessage' handlings in it.
2024-12-05 21:58:20 +01:00
Daniel Grigencha
60ebef3518 Updated 'LobbyState' class.
Updated the 'LobbyState' class by adding an 'IncorrectRequestMessage' to the start game handling.
2024-12-05 19:58:23 +01:00
Felix Koppe
a399b14291 Improve interrupt 2024-12-05 18:11:57 +01:00
Felix Koppe
9d21e2ce87 Merge commit 2024-12-05 18:00:27 +01:00
Felix Koppe
2255bfd648 Remove test binding 2024-12-05 18:00:04 +01:00
Hanno Fleischer
74194d8514 Merge branch 'development' into 'dev/model'
Development

See merge request progproj/gruppen-ht24/Gruppe-01!34
2024-12-05 16:58:50 +00:00
Fleischer Hanno
cabd98a24a adjusted a broadcast in lobby state to a send to reduce traffic (original commit f1124f32) and removed souts as well as added comments back into the code 2024-12-05 17:51:18 +01:00
Cedric Beck
f3816cb2a5 added particle_cir.png 2024-12-05 17:49:56 +01:00
Cedric Beck
997c4c589e removed setOwnColor 2024-12-05 17:23:15 +01:00
Cedric Beck
d14a0aef86 fixed ownColor sync problem 2024-12-05 17:22:37 +01:00
Felix Koppe
ac5d7ed74b Add sounds 2024-12-05 17:11:07 +01:00
Felix Koppe
f1124f3245 Fix missing ready update from server on join of new player in LobbyState 2024-12-05 16:38:09 +01:00
Felix Koppe
fc4a357e9e Merge branch 'dev/model' into dev/client_koppe2 2024-12-05 16:25:23 +01:00
Felix Koppe
a8b02faa96 Merge branch 'development' into dev/client_koppe2
# Conflicts:
#	Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java
2024-12-05 16:25:11 +01:00
Felix Koppe
4a7c23708c Add jetAnimation 2024-12-05 16:21:13 +01:00
Hanno Fleischer
4478291852 added the movement of pieces in the intro state to be also done in the model 2024-12-05 15:22:38 +01:00
Hanno Fleischer
0622c35303 fixed state transitions and implemented the Intro state to move the pieces to the correct start setup
added some logic so that the client only transitions to the intro state when the animation has finished at it received the new active Player, and after animating the setup it switches to the corresponding state baserd on  the active player and displays the now new active player.
2024-12-05 14:02:02 +01:00
Daniel Grigencha
3b0cd9ebdb Updated the JavaDocs in multiple classes, to improve readability. 2024-12-05 05:21:33 +01:00
Daniel Grigencha
e81aa67d36 Updated the JavaDocs in multiple classes, to improve readability. 2024-12-05 05:09:15 +01:00
Daniel Grigencha
4fb848420b Updated the 'DisconnectedMessage' class.
Updated the 'DisconnectedMessage' class by adding JavaDocs.
2024-12-05 05:03:39 +01:00
Daniel Grigencha
07a833afe7 Updated the 'ClientInterpreter' interface.
Updated the 'ClientInterpreter' interface by adjusting the JavaDocs.
2024-12-05 05:00:29 +01:00
Daniel Grigencha
6576250113 Updated the 'Player' class.
Updated the 'Player' class by adjusting the JavaDocs and writing the logic for the 'isFinished()' method.
2024-12-05 04:54:12 +01:00
Daniel Grigencha
154efccf31 Updated 'Game' class.
Updated the 'Game' class by adjusting the JavaDocs and rewriting the constructor for maintainability and readability.
2024-12-05 04:52:59 +01:00
Daniel Grigencha
f90aed7bbb Updated 'Color' enum.
Updated the 'Color' enum by adjusting the JavaDocs and adding a new static method 'getColor(int)'
2024-12-05 04:51:55 +01:00
Daniel Grigencha
3a86837307 Updated the JavaDocs in multiple classes, to improve readability. 2024-12-05 04:50:34 +01:00
Daniel Grigencha
da0756452c Updated the JavaDocs in multiple classes, to improve readability. 2024-12-05 04:49:49 +01:00
Daniel Grigencha
bfe8a20f92 Updated 'Board' class.
Updated the 'Board' class by rewriting the constructor, to make it maintainable and scalable.
2024-12-05 04:46:01 +01:00
Felix Koppe
0e6a2499b7 Fix fullscreen issue 2024-12-04 18:38:35 +01:00
Hanno Fleischer
354cdc0a9c added Intro state and its logic 2024-12-04 17:03:57 +01:00
Felix Koppe
00d86c5c10 Improve ceremonyView 2024-12-04 15:33:34 +01:00
Felix Koppe
990e476753 Add Q/E rotation 2024-12-04 15:27:33 +01:00
Felix Koppe
71fc08a05c Add interrupt 2024-12-04 15:11:31 +01:00
Cedric Beck
9e1ca584c7 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-04 13:56:08 +01:00
Cedric Beck
9199fbffd8 removed tests, fixed null exception in CardLayer 2024-12-04 13:56:03 +01:00
Felix Koppe
5c71531277 Merge branch 'development' into dev/client_koppe2 2024-12-04 13:43:33 +01:00
Felix Koppe
6f7c5346d2 Merge commit 2024-12-04 13:34:14 +01:00
Felix Koppe
ef1ce63db6 Try to make server stop on leave 2024-12-04 13:33:39 +01:00
Hanno Fleischer
e8d1442e5b made the model checkstyle compliant 2024-12-04 12:10:48 +01:00
Hanno Fleischer
bdacc4aad3 created the Intro state and renamed all packages to be checkstyle compliant 2024-12-04 12:08:38 +01:00
Cedric Beck
44ef21e6af added handCard Num to playerName display + added remove card in guiHandler 2024-12-04 11:38:35 +01:00
Hanno Fleischer
8e8104b672 forgot to add StartGameMessage in previous commit 2024-12-04 11:10:26 +01:00
Hanno Fleischer
de899cef35 removed from every Message the getInfoTest method and only overrode the toString method in messages with content, in every other message it is handled through the parent class 2024-12-04 11:07:55 +01:00
Felix Koppe
11d6dd4500 Improve video dialog 2024-12-04 10:00:41 +01:00
Felix Koppe
d71f824ca6 Add fullscreen option 2024-12-04 09:41:08 +01:00
Felix Koppe
8e6cb27662 Fix lobbyView ready behavior on tskChange 2024-12-04 07:53:18 +01:00
Daniel Grigencha
29711d6210 Updated 'ClientStartGameMessage' class.
Updated the 'ClientStartGameMesssage' class by preparing it for the correct BPMN diagram.
2024-12-04 02:46:07 +01:00
Daniel Grigencha
29d8e791f6 Updated 'Player' class.
Updated the 'Player' class by adding the 'setPieceInHome' method to it.
2024-12-04 02:44:28 +01:00
Daniel Grigencha
4440341f79 Updated 'LobbyState' class.
Updated the 'LobbyState' class by updating the creation of the 'ServerStartGameMessage' object. In Addition, the start process if all players are ready was removed.
2024-12-04 02:44:03 +01:00
Daniel Grigencha
de5c8bf44c Updated 'Game' class.
Updated the 'Game' class by adding the 'getPlayersAsList' method to it.
2024-12-04 02:43:29 +01:00
Daniel Grigencha
ab5cece1b3 Updated 'StartGameMessage' class.
Updated the 'StartGameMessage' class by removing the unused 'forceStartGame' attribute from it.
2024-12-04 02:42:57 +01:00
Daniel Grigencha
b8ed5060d6 Updated 'Board' class.
Updated the 'Board' class by removing the 'playerData' attribute and its getter method from it.
2024-12-04 02:42:16 +01:00
Daniel Grigencha
c0b72ae4da Updated 'ServerStartGameMessage' class.
Updated the 'ServerStartGameMessage' class by adding the 'players' attribute and its getter method to it.
2024-12-04 02:41:44 +01:00
Daniel Grigencha
c1b4caa82b Updated 'LobbyState' class.
Updated the 'LobbyState' class by updating the 'received(ServerStartGameMessage msg)' method in it after updating the 'ServerStartGameMessage' class.
2024-12-04 02:22:58 +01:00
Daniel Grigencha
a757158477 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by removing the serializer registration in it.
2024-12-04 02:09:20 +01:00
Daniel Grigencha
964ff87b11 Updated client states.
Updated the client states by removing all references to the 'PlayerData' class.
2024-12-04 01:47:31 +01:00
Hanno Fleischer
7053b163e5 adjusted LobbyState in the client to use the correct Data 2024-12-03 18:19:55 +01:00
Hanno Fleischer
81cb2f33ff adjusted all constuctors of nodes so that if someone creates a node the piece will be null and the option for a constuctor without arguments is still given for serialization purposes 2024-12-03 17:56:39 +01:00
Hanno Fleischer
69865bb504 added the playeringamenotification to be created from the right dataset 2024-12-03 16:48:08 +01:00
Felix Koppe
db50986f3f Fix serialisation issue 2024-12-03 15:38:13 +01:00
Felix Koppe
a0a088a0c4 Fix minor error in notification processing 2024-12-03 15:00:00 +01:00
Cedric Beck
c4d11ff961 added window title 2024-12-03 09:15:14 +01:00
Daniel Grigencha
bb51976127 Updated 'Node' class.
Updated the 'Node' class by overload the 'isOccupied' method in it.
2024-12-03 04:57:30 +01:00
Daniel Grigencha
0db1f08f3c Updated abstract 'GameAutomatonState' class.
Updated the abstract 'GameAutomatonState' class by adding the 'getGameAutomaton' method to it.
2024-12-03 04:49:16 +01:00
Daniel Grigencha
336f1ec316 Updated 'Resources' class.
Updated the 'Resources' class by adding the 'MAX_EYES' constant to it.
2024-12-03 04:29:16 +01:00
Daniel Grigencha
a1e687912a Updated abstract 'TurnAutomatonState' class.
Updated the abstract 'TurnAutomatonState' class by adding the 'getTurnAutomaton' method to it.
2024-12-03 04:09:35 +01:00
Daniel Grigencha
2248d044c1 Updated 'AnimationState' class.
Updated the 'AnimationState' class by updating the content inside the 'received(AnimationEndMessage msg, int from) method in it.
2024-12-03 03:41:58 +01:00
Daniel Grigencha
79bf1c16e8 Updated 'Game' class.
Updated the 'Game' class by adding the 'getActivePlayerId' method to it.
2024-12-03 03:40:24 +01:00
Daniel Grigencha
3353a890d3 Updated 'Game' class.
Updated the 'Game' class by adding the 'getPlayerIdByColor' method to it.
2024-12-03 03:36:22 +01:00
Daniel Grigencha
a012402a85 Updated abstract 'TurnAutomatonState' class.
Updated the abstract 'TurnAutomatonState' class by updating the JavaDoc text of the constructor.
2024-12-03 02:15:10 +01:00
Daniel Grigencha
5aaf8d4850 Updated 'TurnState' class.
Updated the 'TurnState' class by setting the start state in it.
2024-12-03 01:31:22 +01:00
Daniel Grigencha
35ab777f04 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by fixing the logic inside the received(RequestDieMessage msg, int from)' method in it.
2024-12-03 01:30:39 +01:00
Daniel Grigencha
c707abc465 Updated 'Die' class.
Updated the 'Die' class by adding another constructor for test cases to it.
2024-12-03 01:04:02 +01:00
Daniel Grigencha
2a84e7cf65 Updated 'Player' class.
Updated the 'Player' class by moving all content of 'PlayerData' class in 'Player' class.
2024-12-03 00:51:45 +01:00
Daniel Grigencha
3a02edb944 Updated 'PlayerData' class.
Updated the 'PlayerData' class by updating the 'Piece' creation inside the constructor.
2024-12-03 00:50:53 +01:00
Daniel Grigencha
1870d4fe0e Updated 'ShieldState' enumeration.
Updated the 'ShieldState' enumeration by removing unused methods from it.
2024-12-03 00:49:09 +01:00
Daniel Grigencha
5cf9746931 Updated 'PieceState' enumeration.
Updated the 'PieceState' enumeration by removing unused methods from it.
2024-12-03 00:48:39 +01:00
Daniel Grigencha
5b9bc7aa36 Updated 'Piece' class.
Updated the 'Piece' class by removing the unused 'id' parameter from the constructor.
2024-12-03 00:38:24 +01:00
Daniel Grigencha
abe66aff5d Updated 'LobbyState' class.
Updated 'LobbyState' class by removed unused imports in it.
2024-12-03 00:37:24 +01:00
Fleischer Hanno
eea566cc8b added the logic for server shutdown 2024-12-02 23:25:54 +01:00
Daniel Grigencha
bd07a44607 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 23:24:02 +01:00
Daniel Grigencha
1f64676d31 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by adding the 'shutdown' message to it.
2024-12-02 23:23:56 +01:00
Daniel Grigencha
838f59b9aa Updated 'ServerState' class.
Updated the 'ServerState' class by filling the 'received(LeaveGameMessage msg, int from)' in it.
2024-12-02 23:22:45 +01:00
Daniel Grigencha
002a42be38 Updated 'LobbyState' class.
Updated the 'LobbyState' class by removing the 'received(LeaveGameMessage msg, int from)' from it.
2024-12-02 23:21:42 +01:00
Daniel Grigencha
a1d10521ac Updated 'ServerSener' interface.
Updated the 'ServerSender' interface by adding the 'shutdown' method to it.
2024-12-02 23:14:29 +01:00
Fleischer Hanno
4e6a272e7a added that when the client is in the game state and recieves the ceremony message it always changes to ceremony state 2024-12-02 23:08:56 +01:00
Daniel Grigencha
516848a67e Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 23:06:49 +01:00
Daniel Grigencha
659d69d3eb Updated 'GameState' class.
Updated the 'GameState' class by sending a broadcast message after a player left the game and only one player is remaining.
2024-12-02 23:06:44 +01:00
Daniel Grigencha
fb6cbeaaf5 Updated 'ServerStartGameMessage' class.
Updated the 'ServerStartGameMessage' class by adding the 'board' attribute and its getter method to it.
2024-12-02 23:00:39 +01:00
Cedric Beck
25f750c8b6 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 22:58:58 +01:00
Cedric Beck
3f49b432c4 added SSAO and FXAA 2024-12-02 22:58:52 +01:00
Daniel Grigencha
252c37ae9a Updated 'LobbyState' class.
Updated the 'LobbyState' class by sending the 'ServerStartGameMessage' with a 'Board' object.
2024-12-02 22:58:46 +01:00
Fleischer Hanno
4566d4c9a8 Merge remote-tracking branch 'origin/development' into development 2024-12-02 22:46:12 +01:00
Fleischer Hanno
e9ba888651 changed the logic so that the isHost is not decided by the client and instead by the server 2024-12-02 22:45:44 +01:00
Cedric Beck
cbbb98037b Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 22:43:16 +01:00
Cedric Beck
aa651ec62f added trees 2024-12-02 22:43:03 +01:00
Daniel Grigencha
e163b87cc4 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by updating the logic inside the 'connectionAdded' method in it.
2024-12-02 22:41:17 +01:00
Daniel Grigencha
1eb24b7a66 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by updating the logic inside the 'connectionAdded' method in it.
2024-12-02 22:37:46 +01:00
Daniel Grigencha
492f7422f5 Updated 'LobbyAcceptMessage' class.
Updated the 'LobbyAcceptMessage' class by adding the 'host' attribute and its getter method to it.
2024-12-02 22:36:48 +01:00
Daniel Grigencha
27f8af70f5 Updated 'Game' class.
Updated the 'Game' class by setting the default value of 'host' attribute. In Addition, the 'isHost' method was added.
2024-12-02 22:34:45 +01:00
Fleischer Hanno
5910fcc701 added the client logic to receive the LobbyAccept and LobbyDeny message 2024-12-02 21:52:07 +01:00
Felix Koppe
e94ed1e019 Fix syntax error 2024-12-02 21:51:09 +01:00
Felix Koppe
7d54a906dd Add some more names 2024-12-02 21:48:23 +01:00
Felix Koppe
5ae65921bf Add more random names 2024-12-02 21:42:12 +01:00
Daniel Grigencha
468e4005dc Updated 'LobbyState' class.
Updated the 'LobbyState' class by sending a broadcast update the new ready state of the client.
2024-12-02 21:23:53 +01:00
Daniel Grigencha
72321eab9a Updated 'LobbyState' class.
Updated the 'LobbyState' class by updating all received methods in it.
2024-12-02 21:22:49 +01:00
Daniel Grigencha
951c92d890 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 21:12:03 +01:00
Felix Koppe
e87eb569c2 Add showInfo to MdgaView 2024-12-02 21:16:50 +01:00
Felix Koppe
baa967ecfc Merge commit 2024-12-02 21:12:56 +01:00
Felix Koppe
8d39d61c71 Add infoNotification 2024-12-02 21:12:43 +01:00
Daniel Grigencha
7fcee3cac0 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by register the 'IncorrectRequestMessage' class to the serializer.
2024-12-02 21:11:59 +01:00
Daniel Grigencha
06d4b322e7 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 21:04:41 +01:00
Daniel Grigencha
1cf14f65bb Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by updating the 'connectionAdded' method in it. In Addition, the JavaDoc text for this method was addded.
2024-12-02 21:04:36 +01:00
Fleischer Hanno
ebb9f839c7 added JavaDocs in Resources.java 2024-12-02 20:58:00 +01:00
Daniel Grigencha
3eef4b2a02 Updated 'PlayerData' class.
Updated the 'PlayerData' class by replacing the magic constants with the 'Resources' class. In Addition, some JavaDoc texts were updated.
2024-12-02 20:56:59 +01:00
Daniel Grigencha
c1fa679261 Updated 'Resources' class.
Updated the 'Resources' class by adding the 'MAX_PIECES' constant to it.
2024-12-02 20:45:07 +01:00
Daniel Grigencha
c48f924ead Updated 'Resources' class.
Updated the 'Resources' class by adding the 'MAX_PLAYERS' constant to it.
2024-12-02 20:43:47 +01:00
Fleischer Hanno
73859d8c81 added methods for getting Boolean, String, Double and int 2024-12-02 20:34:52 +01:00
Felix Koppe
1918aa80ff Merge commit 2024-12-02 20:33:36 +01:00
Felix Koppe
d062b9dabc Add forceStartGameButton to host in lobby 2024-12-02 20:32:46 +01:00
Fleischer Hanno
7ddcdc3f48 added the first error.messages and adjusted 2024-12-02 20:24:17 +01:00
Fleischer Hanno
2cefc2c293 Merge remote-tracking branch 'origin/development' into development 2024-12-02 20:19:44 +01:00
Daniel Grigencha
c4304ae99a Updated 'Game' class.
Updated the 'Game' class by removing the 'allReady' attribute in it. In Addtion, the 'areAllReady' method was added.
2024-12-02 20:19:13 +01:00
Fleischer Hanno
005df94114 added Resources calss to access teh properties 2024-12-02 19:55:18 +01:00
Daniel Grigencha
44f893ccef Updated 'Game' class.
Updated the 'Game' class by setting the 'die' attribute correctly inside the constructor.
2024-12-02 19:45:11 +01:00
Daniel Grigencha
0d9a922f55 Removed 'PlayerDataMessage' and 'StartBriefingMessage'. 2024-12-02 19:16:01 +01:00
Daniel Grigencha
289158cf35 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by removing the 'PlayerDataMessage' and 'StartBriefingMessage' from the serializer.
2024-12-02 19:14:11 +01:00
Fleischer Hanno
0a0762b6c9 removed all instances of PlayerDataMEssage and StartBriefingMessage 2024-12-02 19:07:58 +01:00
Fleischer Hanno
90a21087df added logic for incorrectRequest message and removed messages playerdata and startbriefing and created javadocs 2024-12-02 19:02:00 +01:00
Daniel Grigencha
294ecdc56f Updated 'IncorrectRequestMessage' class.
Updated the 'IncorrectRequestMessage' class by updating the content inside the 'accept' method in it.
2024-12-02 19:00:21 +01:00
Daniel Grigencha
347ed152b8 Added 'IncorrectRequestMessage' class.
Added the 'IncorrectRequestMessage' class to this project. It will be used to send the client an incorrect request message to show they did something wrong.
2024-12-02 18:58:15 +01:00
Daniel Grigencha
3daafde9f1 Updated 'ServerInterpreter' class.
Updated the 'ServerInterpreter' class by adding the 'received(IncorrectRequestMessage msg)' method to it.
2024-12-02 18:50:42 +01:00
Daniel Grigencha
09fda6b167 Updated 'Game' class.
Updated the 'Game' class by adding the 'isColorTaken' method to it.
2024-12-02 18:18:04 +01:00
Cedric Beck
f21fd9b0a6 added setPauseOnLostFocus(false) 2024-12-02 17:28:37 +01:00
Cedric Beck
41e204b1f2 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 17:12:00 +01:00
Cedric Beck
208261c6bf added clickDice Action + modelSync 2024-12-02 17:11:55 +01:00
Hanno Fleischer
0411f2ead4 fixed state transitions in gamestateclient automaton 2024-12-02 17:08:46 +01:00
Cedric Beck
eb819d4d5e merge development 2024-12-02 16:49:37 +01:00
Cedric Beck
a2856bb157 added rollRankingResults 2024-12-02 16:47:28 +01:00
Daniel Grigencha
bcf17a0651 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 16:35:49 +01:00
Daniel Grigencha
eee6fccde5 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by setting the start state correctly and enter it.
2024-12-02 16:35:40 +01:00
Felix Koppe
2118c72891 Adjust RollDiceNotification 2024-12-02 16:34:55 +01:00
Daniel Grigencha
cb362c4d0c Used auto-reformate code. 2024-12-02 16:31:57 +01:00
Daniel Grigencha
1bcb73cff7 Updated 'PlayerData' class.
Updated the 'PlayerData' class by adding the 'isFinished' method to it. In Addition, the empty constructor was optimized to initalize all class attributes for serializable cases.
2024-12-02 16:29:32 +01:00
Daniel Grigencha
167d898a3c Updated 'StartNode' class.
Updated the 'StartNode' class by reverting all enumerations to its origin types in it.
2024-12-02 16:25:33 +01:00
Daniel Grigencha
6c136b78b8 Updated 'Piece' class.
Updated the 'Piece' class by reverting all enumeration to its orgin types.
2024-12-02 16:22:50 +01:00
Felix Koppe
82234a7ff9 Merge commit 2024-12-02 15:44:41 +01:00
Felix Koppe
92d2e74748 Fix error regarding color in lobbyState 2024-12-02 13:06:59 +01:00
Felix Koppe
4561a962d4 Fix lobby isSelf logic and no longer assign color on join 2024-12-02 12:52:07 +01:00
Hanno Fleischer
5db7b64cef fixed bug with seriliazation of Board, now sending playerdata seperate from teh board 2024-12-02 12:16:53 +01:00
Felix Koppe
bb1b721e77 Fix lobby in serverAutomaton and adjust TskUpdateMessage 2024-12-02 11:48:54 +01:00
Cedric Beck
206cad2f79 removed test card 2024-12-02 11:01:02 +01:00
Cedric Beck
3717e7b794 added javadocs to board 2024-12-02 03:48:11 +01:00
Cedric Beck
a15d7932d4 fixed bug 2024-12-02 03:15:18 +01:00
Cedric Beck
d649e41e75 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 03:13:48 +01:00
Cedric Beck
6d0552f5a7 added javadocs to animation; moved outline package 2024-12-02 03:13:42 +01:00
Fleischer Hanno
47f9f46277 Merge remote-tracking branch 'origin/development' into development 2024-12-02 03:03:47 +01:00
Felix Koppe
b87f5de5fb Fix error 2024-12-02 03:03:54 +01:00
Fleischer Hanno
c434bcb684 minor changes 2024-12-02 03:03:36 +01:00
Daniel Grigencha
b9617c0a14 Merge remote-tracking branch 'origin/development' into development 2024-12-02 02:53:05 +01:00
Daniel Grigencha
0aa73ca6ee added the received method for a Shutdown Message 2024-12-02 02:52:48 +01:00
Cedric Beck
fbc7246037 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 02:52:41 +01:00
Cedric Beck
2703084df1 added move/swap/throw animation; reworked waitingNodes logic in BoardHandler 2024-12-02 02:51:52 +01:00
Daniel Grigencha
31b1d535ac added a new 'ShutdownMessage' for the server 2024-12-02 02:32:50 +01:00
Daniel Grigencha
b3fb2f8fa4 added a new 'ShutdownMessage' for the server 2024-12-02 02:31:55 +01:00
Daniel Grigencha
8fcac9b809 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 02:15:29 +01:00
Daniel Grigencha
6985d988f4 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by updating the logic inside the 'received(RequestDieMessage msg, int from)' method in it.
2024-12-02 02:15:22 +01:00
Fleischer Hanno
6c3103b2ed fixing serialization error 2024-12-02 02:14:45 +01:00
Fleischer Hanno
3658c88d72 made all enums look like the color enum 2024-12-02 02:11:40 +01:00
Fleischer Hanno
bfc812b003 minas please help no serialization 2024-12-02 02:07:02 +01:00
Felix Koppe
413f35d7bf Merge commit 2024-12-02 01:59:49 +01:00
Felix Koppe
c5cb3d4dd0 Add restart on resolution change 2024-12-02 01:59:37 +01:00
Daniel Grigencha
efb4439431 Updated 'Game' class.
Updated the 'Game' class by adding the 'setDie' method to it.
2024-12-02 01:53:10 +01:00
Felix Koppe
601366f08d Merge commit 2024-12-02 01:40:58 +01:00
Felix Koppe
918c1f2a8a Add videoSettings 2024-12-02 01:40:45 +01:00
Daniel Grigencha
bf75b8afc9 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 01:39:07 +01:00
Daniel Grigencha
0b45727bd7 Updated 'Die' class.
Updated the 'Die' class by adding a third constructor for test cases.
2024-12-02 01:39:01 +01:00
Daniel Grigencha
a19ac2fc51 Updated 'GameState' class.
Updated the 'GameState' class by changing the data types of 'determineStartPlayerState, 'animationState' and 'turnState' attributes in it.
2024-12-02 01:27:21 +01:00
Daniel Grigencha
79f0e55c52 default value of playerData in 'Board' 2024-12-02 01:19:41 +01:00
Fleischer Hanno
44378486d4 Merge remote-tracking branch 'origin/development' into development 2024-12-02 01:17:14 +01:00
Fleischer Hanno
149931d2cb fixed PlayerData mistake 2024-12-02 01:16:33 +01:00
Daniel Grigencha
1250500558 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 01:01:49 +01:00
Daniel Grigencha
177bfe3001 Updated 'DetermineStartPlayerState' class.
Updated the 'DeterminStartPlayerState' class by removing the 'getDiceResults' method from it. In Addition, the logic inside the 'received(RequestDieMessage msg, int from)' was added.
2024-12-02 01:01:42 +01:00
Felix Koppe
138444439d Merge remote-tracking branch 'origin/development' into development 2024-12-02 00:53:58 +01:00
Felix Koppe
702f96b8db Add videoSettings 2024-12-02 00:53:11 +01:00
Fleischer Hanno
1b6407b75b fixed bug 2024-12-02 00:52:28 +01:00
Fleischer Hanno
c649b8f3ae creating MapCreation Notification 2024-12-02 00:44:11 +01:00
Daniel Grigencha
41a669d44d Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 00:42:17 +01:00
Daniel Grigencha
4b6b12c0ac Updated 'Board' class.
Updated the 'Board' class by adding the 'addPlayerData' method to it.
2024-12-02 00:42:07 +01:00
Daniel Grigencha
c1280ba089 Updated 'LobbyState' class.
Updated the 'LobbyState' class by adding 'initializeGame' method to it.
2024-12-02 00:40:21 +01:00
Felix Koppe
02f285a258 Remove cheat button 2024-12-02 00:39:58 +01:00
Daniel Grigencha
bcb0ebc0f8 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 00:29:21 +01:00
Daniel Grigencha
a19902f819 Updated 'LobbyState' class.
Updated the 'LobbyState' class by changing the method call 'isActive' to 'isReady'.
2024-12-02 00:28:59 +01:00
Fleischer Hanno
585687055c Merge remote-tracking branch 'origin/development' into development 2024-12-02 00:28:41 +01:00
Fleischer Hanno
a86319082c included the LobbyPlayerJoined MEssage parameter of isHost 2024-12-02 00:28:04 +01:00
Daniel Grigencha
7acc55fe25 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by saving the host into the 'Game' class.
2024-12-02 00:28:01 +01:00
Daniel Grigencha
3e56de2a17 Updated 'LobbyState' class.
Updated the 'LobbyState' class by changing the method call 'isActive' to 'isReady'.
2024-12-02 00:23:03 +01:00
Daniel Grigencha
468cd97374 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 00:20:41 +01:00
Daniel Grigencha
dee6bf9f9c Updated 'Game' class.
Updated the 'Game' class by adding the 'host' attribute and its getter method to it.
2024-12-02 00:19:46 +01:00
Daniel Grigencha
ea6431faa4 Updated 'LobbyPlayerJoinedMessage' class.
Updated the 'LobbyPlayerJoinedMessage' class by adding the 'host' attribute and its getter method to.
2024-12-02 00:12:46 +01:00
Cedric Beck
f272fd6f08 fixed bug again 2024-12-02 00:10:58 +01:00
Cedric Beck
bfc74ee126 fixed bug 2024-12-02 00:04:48 +01:00
Cedric Beck
d890d11978 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:58:57 +01:00
Daniel Grigencha
9af20346f1 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:58:44 +01:00
Cedric Beck
f853b0b54f Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:57:59 +01:00
Cedric Beck
9dd2d3f58b added finish text; edited Notifications 2024-12-01 23:57:53 +01:00
Daniel Grigencha
06e43903e6 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:57:39 +01:00
Fleischer Hanno
00a04c2403 fixed a bug 2024-12-01 23:57:39 +01:00
Daniel Grigencha
92cbd9202a Updated 'LobbyState' class.
Updated the 'LobbyState' class by fixing the error by sending the 'ServerStartGameMessage' after all players are ready.
2024-12-01 23:57:26 +01:00
Felix Koppe
9a06afe998 Merge commit 2024-12-01 23:56:33 +01:00
Felix Koppe
289390c528 Add comment 2024-12-01 23:56:24 +01:00
Fleischer Hanno
7712a23d00 added transition from Lobby to Game 2024-12-01 23:50:37 +01:00
Fleischer Hanno
8137a727f5 Merge remote-tracking branch 'origin/development' into development 2024-12-01 23:49:30 +01:00
Felix Koppe
d904a28ee0 Remove mock 2024-12-01 23:48:18 +01:00
Fleischer Hanno
2f2d9c7479 Merge remote-tracking branch 'origin/development' into development 2024-12-01 23:42:56 +01:00
Fleischer Hanno
c2b6e6e9e9 made all classes for ServerStartGameMEssage serializiable 2024-12-01 23:42:32 +01:00
Daniel Grigencha
697b974ce1 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:42:09 +01:00
Felix Koppe
f0cab64910 Minor change 2024-12-01 23:46:46 +01:00
Daniel Grigencha
adcf65d7aa Updated 'LobbyState' class.
Updated the 'LobbyState' class by sending a broadcast message after all players are ready. In Addition, the 'ServerStartGameMessage' getting the 'Board' object.
2024-12-01 23:41:10 +01:00
Daniel Grigencha
8f53b76a3e Updated 'ServerStartGameMessage' class.
Updated the 'ServerStartGameMessage' class by adding the 'board' attribute and its getter method to it.
2024-12-01 23:39:36 +01:00
Cedric Beck
eaef4b20ba Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:34:02 +01:00
Cedric Beck
d3fe2fec14 added show/hide functionality for select button 2024-12-01 23:33:28 +01:00
Daniel Grigencha
02d7ef1dd8 Updated 'ChoosePieceState' class.
Updated the 'ChoosePieceState' to work correctly as a state automaton.
2024-12-01 23:28:50 +01:00
Daniel Grigencha
23aa2db714 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:27:50 +01:00
Daniel Grigencha
e68369074f Updated 'RollDiceState' class.
Updated the 'RollDiceState' class by removing a spelling mistake.
2024-12-01 23:27:45 +01:00
Daniel Grigencha
aafc804c3f Updated 'ChoosePieceState' class.
Updated the 'ChoosePieceState' to work correctly as a state automaton.
2024-12-01 23:26:53 +01:00
Felix Koppe
bec199036c Minor change 2024-12-01 23:10:25 +01:00
Fleischer Hanno
a7e048d4b4 Merge remote-tracking branch 'origin/development' into development 2024-12-01 23:08:50 +01:00
Felix Koppe
bcd510804f Merge commit 2024-12-01 23:12:46 +01:00
Felix Koppe
7319f7a62c Process startMenuNotification in lobby 2024-12-01 23:12:36 +01:00
Fleischer Hanno
a1e51fb2f4 added logic to the leave game method 2024-12-01 23:08:25 +01:00
Daniel Grigencha
f15d0eb5d8 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-01 23:06:31 +01:00
Daniel Grigencha
f484a4abc8 Updated server states.
Updated server stats by adding the logger to all states. In Addition, new joined clients should be updated correctly.
2024-12-01 23:06:02 +01:00
Felix Koppe
5905a232a5 Adjust state 2024-12-01 23:03:26 +01:00
Cedric Beck
12cb87ef70 added outline package back 2024-12-01 22:56:09 +01:00
Cedric Beck
9cb7a156bb Merge branch 'development' into dev/client_beck 2024-12-01 22:47:48 +01:00
Fleischer Hanno
76e2606847 reverted the client state machine 2024-12-01 22:47:13 +01:00
Cedric Beck
7762b97303 added init & taktical view by ownColor 2024-12-01 22:46:17 +01:00
Daniel Grigencha
eaf46f3e14 updated the project to pass the checkstyle 2024-12-01 22:37:49 +01:00
Fleischer Hanno
92be52b62a fixed server join logic 2024-12-01 22:33:30 +01:00
Fleischer Hanno
7a0a3589a5 trying to fix server ip to use outward ip 2024-12-01 22:14:09 +01:00
Cedric Beck
661c28f096 merge to dev/client_beck from development 2024-12-01 22:06:30 +01:00
Cedric Beck
4a94e85aac Merge branch 'dev/client' into dev/client_beck 2024-12-01 21:55:37 +01:00
Felix Koppe
799bd096a0 Merge development 2024-12-01 21:56:52 +01:00
Fleischer Hanno
5a68d3b146 fixed a method call for getMoveIndices 2024-12-01 21:52:28 +01:00
Cedric Beck
63fa692910 removed comments 2024-12-01 21:52:28 +01:00
Felix Koppe
638cb93d7b Merge dev/client_beck 2024-12-01 21:51:01 +01:00
Fleischer Hanno
133f900ec7 added the server and network functionality for mdga and fixed the communication in the Lobby 2024-12-01 21:50:28 +01:00
Fleischer Hanno
33ddea4221 Merge remote-tracking branch 'origin/development' into development 2024-12-01 21:49:30 +01:00
Daniel Grigencha
977a7294ad updated server state diagram and added missing classes 2024-12-01 21:49:11 +01:00
Cedric Beck
7db75a2ca1 added converted assets 2024-12-01 21:48:40 +01:00
Daniel Grigencha
71d5701cc7 added javadoc for the classes in the notification package 2024-12-01 21:44:35 +01:00
Fleischer Hanno
42feca466d Merge remote-tracking branch 'origin/development' into development 2024-12-01 21:05:41 +01:00
Daniel Grigencha
95a1f8d858 removed all inheritance of the automaton for testing purposes 2024-12-01 21:05:22 +01:00
Fleischer Hanno
76757c19a9 Merge remote-tracking branch 'origin/development' into development 2024-12-01 21:02:11 +01:00
Daniel Grigencha
c3fdcf4dc7 added the states of the server automaton for testing purposes 2024-12-01 21:01:37 +01:00
Fleischer Hanno
8ffab12f49 Merge remote-tracking branch 'origin/development' into development 2024-12-01 20:57:57 +01:00
Cedric Beck
da2b1af698 fixed shutdown guiHandler bug 2024-12-01 20:45:24 +01:00
Daniel Grigencha
8369797120 added JavaDocs for the 'InterruptState' classe 2024-12-01 20:41:30 +01:00
Daniel Grigencha
ef450a23f5 added logger to server state chart 2024-12-01 20:35:40 +01:00
Cedric Beck
e5b007accd debug commit 2024-12-01 20:24:26 +01:00
Daniel Grigencha
17f0aa0209 added the 'Die' class to the 'Game' class 2024-12-01 19:46:59 +01:00
Fleischer Hanno
1d8eff8ea9 Merge remote-tracking branch 'origin/development' into development 2024-12-01 19:45:06 +01:00
Daniel Grigencha
ff31335a98 added a new class 'Die' to handle the dice. added this class to the class 'Game' 2024-12-01 19:38:26 +01:00
Daniel Grigencha
3467dd2f04 added a new method getColorByIndex(int) and next() method to the enum 'Color' 2024-12-01 19:37:40 +01:00
Daniel Grigencha
fb6cfaa518 added JavaDocs for the classes in the package 'game' 2024-12-01 19:36:58 +01:00
Cedric Beck
c08c81ea46 edited map 2024-12-01 18:42:57 +01:00
Fleischer Hanno
e9d45f241f Merge remote-tracking branch 'origin/development' into development 2024-12-01 18:22:29 +01:00
Daniel Grigencha
bf38a7e00c added a new method 'disconnectClient' in 'ServerSender' interface 2024-12-01 18:21:54 +01:00
Fleischer Hanno
5d638a1da7 Merge remote-tracking branch 'origin/development' into development 2024-12-01 18:20:16 +01:00
Fleischer Hanno
b83279e835 Merge remote-tracking branch 'origin/development' into development 2024-12-01 18:16:05 +01:00
Daniel Grigencha
eb54cfbc80 adjusted constructor for mdga server 2024-12-01 18:15:56 +01:00
Cedric Beck
453aacfe1a fixed missing messages 2024-12-01 18:12:31 +01:00
Daniel Grigencha
1513576291 added javadocs to the 'ServerState' class 2024-12-01 18:03:46 +01:00
Cedric Beck
2732a89da6 fixed error with SelectObjectOutliner 2024-12-01 17:47:04 +01:00
Felix Koppe
5b8032bed9 Prepare for model 2024-12-01 17:44:37 +01:00
Felix Koppe
21f98de3e6 Minor adjustment 2024-12-01 17:32:05 +01:00
Cedric Beck
b099972656 merge from dev/client_beck 2024-12-01 17:10:04 +01:00
Fleischer Hanno
5206b03966 added java docs 2024-12-01 17:03:56 +01:00
Cedric Beck
eb703cbd2c fixed bad performancegit status!; edited GameNotification; fixed error because of changed 'Color' enum 2024-12-01 17:03:09 +01:00
Daniel Grigencha
8c03b282b3 deleted the color attribute and their usages 2024-12-01 16:58:37 +01:00
Daniel Grigencha
a29e942191 added logic to the 'MdgaServer' class 2024-12-01 16:57:48 +01:00
Daniel Grigencha
efc7a2f09d added logic to the 'LobbyState' class
- for leaving the lobby
2024-12-01 16:49:05 +01:00
Daniel Grigencha
121d668bf2 added logic to the 'LobbyState' class 2024-12-01 16:08:14 +01:00
Fleischer Hanno
ba5b9dc4b4 added the getter for the forcestartGame value in teh corresponding message 2024-12-01 16:04:55 +01:00
Daniel Grigencha
772c7a51e0 updated enum 'Color' 2024-12-01 15:54:06 +01:00
Fleischer Hanno
ed04bc1119 changed all messages to work with a UUID of a piece instead of a string identifier 2024-12-01 15:45:30 +01:00
Fleischer Hanno
7712ee2e7c renamed JoinServerMessage to JoinedLobbyMessage and wrote a getter for the name in the message 2024-12-01 15:14:42 +01:00
Fleischer Hanno
1d5733a4b9 added a method for getting a piece through a uuid 2024-12-01 15:05:26 +01:00
Fleischer Hanno
dfea7e8736 added java docs for choosepowercard 2024-12-01 14:37:04 +01:00
Felix Koppe
2c81665f80 Update startmenu.png 2024-12-01 14:22:18 +01:00
Felix Koppe
150e4e4c22 Merge development 2024-12-01 14:18:44 +01:00
Felix Koppe
4ff84e64ed Merge development 2024-12-01 14:11:10 +01:00
Felix Koppe
e6fb78507c Remove garbarge files 2024-12-01 14:10:04 +01:00
Felix Koppe
9067a9b04c Add javadoc 2024-12-01 14:08:33 +01:00
Felix Koppe
6758abd60e Add javadoc to buttons 2024-12-01 13:56:45 +01:00
Fleischer Hanno
e70331d85d changed parameter of DieMessage and included the force resumgame logic in intterrupt 2024-12-01 13:56:31 +01:00
Felix Koppe
c3ad8fe79a Gerneral improvements 2024-12-01 13:35:14 +01:00
Fleischer Hanno
26d2d0587d added the remaining logic for GameState and its substatemachines 2024-12-01 12:36:44 +01:00
Fleischer Hanno
00b3ef1d80 added selectNext in CLG 2024-12-01 12:12:37 +01:00
Fleischer Hanno
789868863f added some more client game logic 2024-12-01 12:06:06 +01:00
Fleischer Hanno
bdc527b83e added more logic to the client (choosepiece and powercard) 2024-12-01 08:40:16 +01:00
Fleischer Hanno
5ff56ed9d8 added all necessary logic for the turn waiting class and adjusted some messages 2024-11-30 22:23:40 +01:00
Fleischer Hanno
81d037d232 made the determinstartplayer machine fully functional 2024-11-30 20:50:57 +01:00
Fleischer Hanno
422e94ec48 Dialog state machine is now fully functional 2024-11-30 19:49:52 +01:00
Fleischer Hanno
b3d754e77f added all current State getter in every client state machine 2024-11-30 16:42:24 +01:00
Fleischer Hanno
0297193be1 added more functionality to the client state machine and implemeted the first notifications 2024-11-30 16:23:09 +01:00
Felix Koppe
a630ade2e1 Fix lobbyView leave 2024-11-30 14:21:45 +01:00
Felix Koppe
b197d70d44 Fix errors 2024-11-30 14:18:00 +01:00
Felix Koppe
67d120c278 Fix error 2024-11-30 14:10:42 +01:00
Felix Koppe
d53067f21a Merge dev/client 2024-11-30 14:03:54 +01:00
Felix Koppe
4313468a0c Finish merge 2024-11-30 14:00:42 +01:00
Felix Koppe
0393e9b534 Fixing errors 2024-11-30 13:47:34 +01:00
Felix Koppe
f3bc6bc2f0 Fixing errors 2024-11-30 13:38:08 +01:00
Felix Koppe
12abe081c9 Minor changes 2024-11-30 13:21:31 +01:00
Felix Koppe
02b536aa82 102IQ 2024-11-30 13:17:53 +01:00
Felix Koppe
99ffee749e 101IQ 2024-11-30 13:14:41 +01:00
Felix Koppe
6f71a8b16d Work# 2024-11-30 13:12:51 +01:00
Felix Koppe
a78b3acacd 100IQ 2024-11-30 13:10:46 +01:00
Fleischer Hanno
0487ff0238 modified messages to work with piece uuid instead of an identifier. 2024-11-30 13:02:23 +01:00
Felix Koppe
6a85aca970 Readd .run after some fool deleted it 2024-11-30 12:56:12 +01:00
Felix Koppe
c2cfd8c175 Merge remote-tracking branch 'origin/dev/client_beck' into dev/client_beck
# Conflicts:
#	Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java
#	Projekte/mdga/model/src/main/java/pp.mdga/server/Lobby.java
2024-11-30 12:48:49 +01:00
Felix Koppe
af5d4a95cd Remove notifications 2024-11-30 12:45:08 +01:00
Felix Koppe
129ce54dd8 Merge branch 'refs/heads/development' into dev/client_beck
# Conflicts:
#	Projekte/mdga/model/src/main/java/pp.mdga/server/DetermineStartPlayer.java
#	Projekte/mdga/model/src/main/java/pp.mdga/server/Lobby.java
#	Projekte/mdga/model/src/main/java/pp.mdga/server/Turn.java
#	Projekte/mdga/model/src/main/java/pp/mdga/notification/SelectableMoveNotification.java
#	Projekte/mdga/model/src/main/java/pp/mdga/notification/SelectablePiecesNotification.java
#	Projekte/mdga/model/src/main/java/pp/mdga/notification/SelectableSwapNotification.java
2024-11-30 12:44:04 +01:00
Felix Koppe
8c8bd4db0d Add sounds 2024-11-30 12:37:18 +01:00
Cedric Beck
1c222ce0e0 tried mergee with development 2024-11-30 12:36:09 +01:00
Cedric Beck
f7a34d0d59 tried merge with dev/client 2024-11-30 12:34:39 +01:00
Cedric Beck
cbb21e92f8 added init/shutdown 2024-11-30 12:07:42 +01:00
Fleischer Hanno
4d6cd63a3d made all notifications constructors public 2024-11-30 11:24:46 +01:00
Felix Koppe
36d31e99e9 Fix error 2024-11-30 11:19:54 +01:00
Felix Koppe
28a2c9a448 Add confirm button 2024-11-30 11:17:42 +01:00
Felix Koppe
dd8b16f1ac Merge commit 2024-11-30 10:52:44 +01:00
Felix Koppe
be15b3bd63 Minor changes 2024-11-30 10:51:35 +01:00
Cedric Beck
07f0f55192 added further notification implemenation 2024-11-30 00:33:10 +01:00
Cedric Beck
13690cf73d added skybox; reworked guiHandler 2024-11-29 21:28:50 +01:00
Cedric Beck
220d8ff47e added activePlayer+diceNum text display 2024-11-29 17:26:04 +01:00
Cedric Beck
67bb30d124 added new notifications for client-view communication 2024-11-29 15:23:34 +01:00
Felix Koppe
184410ba31 Merge commit 2024-11-29 14:38:23 +01:00
Felix Koppe
3147f5b7a3 Fix some errors 2024-11-29 14:37:46 +01:00
Felix Koppe
0e79f35cb0 Merge dev/client_koppe2 2024-11-29 14:02:59 +01:00
Felix Koppe
f024ba4866 Add preferences and sounds 2024-11-29 14:01:18 +01:00
Felix Koppe
35270cce7b Fix ceremony statistics error 2024-11-29 12:49:07 +01:00
Felix Koppe
b0761082ce Fix error after merge 2024-11-29 12:42:03 +01:00
Felix Koppe
46182b33a8 Merge dev/client_koppe2 and development 2024-11-29 12:36:07 +01:00
Felix Koppe
457023ad93 Work 2024-11-29 12:30:59 +01:00
Felix Koppe
c3055a0646 Work 2024-11-29 12:29:20 +01:00
Felix Koppe
ae1ec74056 Merge dev/client_beck 2024-11-29 10:48:05 +01:00
Felix Koppe
24cc81d9d4 Merge remote-tracking branch 'origin/dev/client_beck' into dev/client_koppe2
# Conflicts:
#	Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/view/GameView.java
2024-11-29 10:13:15 +01:00
Felix Koppe
c25c12d0d6 Work on ceremony2 2024-11-29 09:45:36 +01:00
Felix Koppe
7b689d6bf6 Work on ceremony 2024-11-28 21:39:08 +01:00
Cedric Beck
2099e02567 added board dice; edited DiceControl; added high-res font; working on ActionTextHandler 2024-11-28 20:07:15 +01:00
Fleischer Hanno
7690340b8f added mor client state transitions
and renamed every client state with state as its suffix and renamed every message with messag as its suffix
2024-11-28 18:28:55 +01:00
Cedric Beck
3dcdbdf489 added display of 'colorÃ' to playerName 2024-11-28 17:29:59 +01:00
Felix Koppe
88cb87d4cd Merge commit 2024-11-28 16:25:57 +01:00
Felix Koppe
827e7aac86 Add stuff 2024-11-28 16:25:13 +01:00
Felix Koppe
eec68188ee Make use of parallelProjection 2024-11-28 16:08:33 +01:00
Hanno Fleischer
476ca82bda created the first part of the cliejnt state machine with its corresponding logic 2024-11-28 15:27:31 +01:00
Felix Koppe
3235a46788 Rewrite gui 2024-11-28 15:00:53 +01:00
Cedric Beck
7da388af37 added improved pieces model; added functionality to notifications + todos 2024-11-28 02:08:51 +01:00
Cedric Beck
304acf17a3 added full highlight functionality for bonuscards; added bonus Symbols display 2024-11-28 01:21:15 +01:00
Cedric Beck
9736dc828b added highlight to bonuscards 2024-11-27 19:50:29 +01:00
Hanno Fleischer
cbbef16374 added two more todos 2024-11-27 09:20:22 +01:00
Hanno Fleischer
c9362a7a95 fixed bugs so the programm would start and added some Todo where code is missing or was fraudulent 2024-11-27 09:19:57 +01:00
Cedric Beck
0b9fc90274 added dice, started adding notification implementation, added hover, highlight and select functionality for pieces 2024-11-27 03:05:35 +01:00
Daniel Grigencha
20c9000d56 Merge remote-tracking branch 'origin/development' into development 2024-11-26 23:29:02 +01:00
Daniel Grigencha
5a911326ba minor changes to the server state automaton 2024-11-26 23:28:49 +01:00
Cedric Beck
6528e5c2b6 started adding notifications 2024-11-26 20:53:29 +01:00
Hanno Fleischer
621bb9efae fixed bugs inside of the client state machine and the message UpdateTSK 2024-11-26 20:31:16 +01:00
Fleischer Hanno
84c289cfd1 implemented all methods required for the state pattern in the client and adjusted the messages to work with player ids instead of names 2024-11-26 20:04:58 +01:00
Fleischer Hanno
f827757ad1 added next method for Color 2024-11-26 18:16:19 +01:00
Daniel Grigencha
e4a9b16fd5 Merge remote-tracking branch 'origin/development' into development 2024-11-26 18:12:32 +01:00
Daniel Grigencha
d63d0cc2a0 changed default constructor of 'Player' class 2024-11-26 18:12:08 +01:00
Hanno Fleischer
a127ee524a Merge remote-tracking branch 'origin/development' into development
# Conflicts:
#	Projekte/.run/MdgaApp.run.xml
2024-11-26 18:05:37 +01:00
Hanno Fleischer
5c2df2430d reworked the client state machine and removed the seperate classes for the statemachines
these machines are now directly included in the parent states
2024-11-26 18:04:56 +01:00
Daniel Grigencha
2e76c41d3a added new 'Disconnect' client message and updated 'Player' and 'Game' classes 2024-11-26 18:02:19 +01:00
Cedric Beck
c204a3a4cb change shader folder structure 2024-11-26 17:05:38 +01:00
Cedric Beck
d794ba9d03 added smooth outline 2024-11-26 16:54:40 +01:00
Cedric Beck
e97147d0e9 merge from koppe 2024-11-26 16:47:24 +01:00
Cedric Beck
1b151aabdd added select nodes, cards & pieces 2024-11-26 16:45:13 +01:00
Felix
3e7d3dbc1b Fix 2024-11-26 16:18:33 +01:00
Cedric Beck
7a482b74ab fixed shaders in/out 2024-11-26 13:29:40 +01:00
Cedric Beck
5cc1888794 merge dev/client_koppe into dev/client_beck for camera movement 2024-11-26 13:13:32 +01:00
Cedric Beck
9dd70a96a0 added outline for bonuscards 2024-11-26 12:56:26 +01:00
Cedric Beck
80f5c4ce90 tried adding shield outline, but there is a bug -> black screen 2024-11-26 07:40:41 +01:00
Fleischer Hanno
7eafa3da39 refactored the whole client package structure 2024-11-25 17:43:29 +01:00
Fleischer Hanno
7178935553 refactored the model to incoporate a correct folder structure 2024-11-25 16:41:44 +01:00
Daniel Grigencha
0b538efbfb Merge remote-tracking branch 'origin/development' into development 2024-11-25 16:36:53 +01:00
Daniel Grigencha
f2d5221328 added import statement with the refactored server messages 2024-11-25 16:36:40 +01:00
Daniel Grigencha
06195854d8 added mdga server controller 2024-11-25 16:35:49 +01:00
Daniel Grigencha
321909387d added new server state chart 2024-11-25 16:35:27 +01:00
Hanno Fleischer
933c7ecad7 Merge branch 'dev/test' into 'development'
merge for refactoring of project structure

See merge request progproj/gruppen-ht24/Gruppe-01!15
2024-11-25 15:34:42 +00:00
Felix
806a149bfc Merge dev/client_koppe 2024-11-25 16:33:04 +01:00
Benjamin Feyer
1803fb5549 edted some tests with null tests 2024-11-25 16:32:51 +01:00
Felix
96489f2454 Minor work 2024-11-25 16:32:16 +01:00
Felix
439231aecf Add rotateable cam 2024-11-25 16:15:59 +01:00
Daniel Grigencha
9759b6871b reverted server messages 2024-11-25 16:14:15 +01:00
Daniel Grigencha
52d9fff493 deleted server state automaton 2024-11-25 15:43:29 +01:00
Hanno Fleischer
31b449662f added two Pieces in RequestPlayCard in order to differentiate between own and enemy pieces 2024-11-25 15:09:24 +01:00
Hanno Fleischer
3be037d590 added two lists in PossiblePiece in order to differentiate between own and enemy pieces 2024-11-25 15:07:43 +01:00
Felix
8982662f5b Remove debug statement 2024-11-25 14:01:06 +01:00
Felix
d70efb32ea Fix audio settings 2024-11-25 13:59:55 +01:00
Hanno Fleischer
d15242f816 added static methods to construct a PlayCard message for each card type 2024-11-25 13:42:00 +01:00
Hanno Fleischer
4705512648 added getter for ArrayList Player in Game and created a flag for ready status in Player 2024-11-25 12:52:22 +01:00
Hanno Fleischer
7efb89c634 Merge remote-tracking branch 'origin/development' into development 2024-11-25 11:20:09 +01:00
Hanno Fleischer
15d1c36dad added an ArrayList of Player in game and added the received methods in clientgamelogic 2024-11-25 11:19:17 +01:00
Benjamin Feyer
ce528457a5 added javadocs 2024-11-25 02:30:43 +01:00
Benjamin Feyer
2cfa328c4c added some more testmethods 2024-11-25 01:50:02 +01:00
Benjamin Feyer
928304fb4b corrected testmethods in clientStateTest 2024-11-25 01:24:11 +01:00
Benjamin Feyer
aa88dff566 added tests in the serverStateTest
added the testmethods for rolldice and movepiece
2024-11-25 00:36:59 +01:00
Benjamin Feyer
f7bd9a0f38 edited some tests in ServerStateTest 2024-11-25 00:20:47 +01:00
Daniel Grigencha
cc800a8dd7 added default constructor for serialization purposes 2024-11-24 23:55:48 +01:00
Daniel Grigencha
7c5720cb9d fixed sonarlint errors and deleted map playerConnectionID 2024-11-24 23:06:30 +01:00
Cedric Beck
b9986ded87 try push 2024-11-24 22:41:17 +01:00
Cedric Beck
fd09460d61 try push 2024-11-24 22:40:50 +01:00
Cedric Beck
e5dca013d1 try push 2024-11-24 22:38:23 +01:00
Cedric Beck
7bfc6e7c3e try push 2024-11-24 22:37:37 +01:00
Benjamin Feyer
1821a222e9 minor changes 2024-11-24 22:24:39 +01:00
Benjamin Feyer
2e302ddc75 Merge branch 'development' into 'dev/test'
merge changes into the testbranch

See merge request progproj/gruppen-ht24/Gruppe-01!14
2024-11-24 21:23:23 +00:00
Fleischer Hanno
ed47883281 refactored ceremony message 2024-11-24 22:20:04 +01:00
Fleischer Hanno
599b3e8f47 corrected refactoring mistake, ich which RankingResponce was renamed to RankingResponse 2024-11-24 22:18:48 +01:00
Fleischer Hanno
040b8830ab added getter for dialogstatemachine in dialogs 2024-11-24 22:03:19 +01:00
Benjamin Feyer
6fa3e8c00d Merge branch 'development' into 'dev/test'
Development

See merge request progproj/gruppen-ht24/Gruppe-01!13
2024-11-24 20:58:39 +00:00
Fleischer Hanno
83c79af31a made all con structors of clients states public 2024-11-24 21:56:32 +01:00
Daniel Grigencha
653c3fb962 added javadocs to all server messages 2024-11-24 20:51:03 +01:00
Daniel Grigencha
8932c8a8cd added javadocs to all client messages 2024-11-24 19:56:51 +01:00
Cedric Beck
10428deedd added resource restructuring 2024-11-24 19:54:29 +01:00
Cedric Beck
a196d3d7f2 added basic player name display 2024-11-24 19:49:54 +01:00
Benjamin Feyer
4c078ab0e2 added some testmethods and corrected other in the clientStatemachineTests 2024-11-24 19:37:03 +01:00
Benjamin Feyer
2a97ede985 added some testmethods for the client testing the statechanges in the dialogs 2024-11-24 19:03:19 +01:00
Benjamin Feyer
56492cdda6 added some mor testcases for the clientstatemachine 2024-11-24 18:40:10 +01:00
Benjamin Feyer
a71619612a added the empty testmethods in serverstateTest and edited the testmethods for substates of choocePiece in Client into MovePiece 2024-11-24 18:21:26 +01:00
Benjamin Feyer
f18a62b089 Merge branch 'development' into 'dev/test'
Testmerge

See merge request progproj/gruppen-ht24/Gruppe-01!12
2024-11-24 15:09:07 +00:00
Benjamin Feyer
c204984a74 edited a test in the clientStateTest 2024-11-24 16:03:12 +01:00
Fleischer Hanno
1d4048cf16 added the constructors for all client states and their statemachines 2024-11-24 16:02:04 +01:00
Benjamin Feyer
2095ea5866 editet tests for the server and client statemachines 2024-11-24 15:49:01 +01:00
Daniel Grigencha
f425eff26b added more logic for the server state diagram 2024-11-24 15:27:10 +01:00
Hanno Fleischer
cd22ece485 Merge branch 'dev/client' into 'development'
Merge results from dev/client into development

See merge request progproj/gruppen-ht24/Gruppe-01!11
2024-11-24 09:45:30 +00:00
Cedric Beck
16dc28013e merge development into dev/client 2024-11-24 10:39:28 +01:00
Cedric Beck
9ab71bfaf6 merge dev/client_koppe into dev/client 2024-11-24 10:34:48 +01:00
Cedric Beck
ccad47f95a Merge branch 'dev/client' into dev/client_koppe 2024-11-24 10:32:00 +01:00
Cedric Beck
f830aec8ce Merge branch 'dev/client_beck' into 'dev/client'
Added basic display of bonusCards for presentation on Monday

See merge request progproj/gruppen-ht24/Gruppe-01!10
2024-11-24 09:31:33 +00:00
Cedric Beck
c8c0188452 merge dev/client into dev/client_koppe 2024-11-24 10:30:37 +01:00
Cedric Beck
a5b7488e92 Merge branch 'dev/client' into dev/client_beck 2024-11-24 09:23:57 +01:00
Cedric Beck
11794b6ac7 added GuiHandler and showing bonuscards 2024-11-24 09:21:44 +01:00
Cedric Beck
a8d80fd3f4 Merge branch 'dev/client_beck' into 'dev/client'
Added all basic functionalitites to BoardHandler

See merge request progproj/gruppen-ht24/Gruppe-01!9
2024-11-23 21:12:14 +00:00
Fleischer Hanno
806f0d7d9d added message contents to the messages
addedn the conentents for all messages regarding the BPMN diagramm and own interpretation.
also created an identifier for pieces to be used for network communication between server and client so that they talk about the same piece.
2024-11-23 12:26:20 +01:00
Cedric Beck
7368014b10 merge dev/client into dev/client_beck 2024-11-22 20:38:00 +01:00
Cedric Beck
ebdedc6494 added working piece outline; added final tweaks for boardHandler 2024-11-22 19:53:32 +01:00
Benjamin Feyer
df2a7151f0 Merge branch 'development' into 'dev/test'
Merge Test to Development

See merge request progproj/gruppen-ht24/Gruppe-01!8
2024-11-22 12:56:51 +00:00
Cedric Beck
00014eeb09 tried fixing outline problem 2024-11-22 13:56:43 +01:00
Daniel Grigencha
89232901a7 added more logic for the server state diagram 2024-11-22 09:37:49 +01:00
Felix
a79a315f83 Minor work 2024-11-21 16:44:28 +01:00
Felix
c470c205e4 Add host&join menu and work on modelSyncronizer 2024-11-21 16:16:19 +01:00
Felix
982ca00b55 Make lobby buttons colored 2024-11-21 16:16:19 +01:00
Felix
c1f4ea480c Add host&join menu and work on modelSyncronizer 2024-11-21 16:14:06 +01:00
Cedric Beck
a8a725611f added highlighting -> bug all assets are transparent 2024-11-21 09:56:40 +01:00
Felix
02ce0df614 Make lobby buttons colored 2024-11-20 15:21:07 +01:00
Felix Koppe
6e57e309cc Merge branch 'dev/client_koppe' into 'dev/client'
Merge work

See merge request progproj/gruppen-ht24/Gruppe-01!7
2024-11-20 12:50:00 +00:00
Felix
d87acd46cc Fix camera init/shutdown 2024-11-20 13:48:59 +01:00
Felix
58395fe3cb Merge dev/client_beck 2024-11-20 13:42:10 +01:00
Felix
5f54eff038 Add inputHandler 2024-11-20 13:32:50 +01:00
Felix
184b565526 Add volume controll 2024-11-20 12:40:51 +01:00
Felix
176efc2aca Add settings menus 2024-11-20 09:24:01 +01:00
Felix
bb491a2682 Make button size dynamic 2024-11-19 19:27:04 +01:00
Felix
51e83c5ae4 Implement notificationSyncronizer 2024-11-19 19:01:52 +01:00
Felix
47f0e44d0a Merge development 2024-11-19 18:40:08 +01:00
Felix
80fab1ffdc Begin work on actionHandler 2024-11-19 18:36:49 +01:00
Felix
03eef66332 Finish buttons 2024-11-19 18:28:37 +01:00
Felix
34415bc9f2 Add left/right buttons 2024-11-19 14:16:01 +01:00
Felix
030842d251 Some work 2024-11-19 12:52:43 +01:00
Hanno Fleischer
a3a9f0d88d Merge branch 'development' into 'dev/test'
TestMerge 3

See merge request progproj/gruppen-ht24/Gruppe-01!6
2024-11-19 11:48:06 +00:00
Benjamin Feyer
6790be782e added empty serverstatetests 2024-11-19 12:42:11 +01:00
Cedric Beck
56256fb9c0 fixed rotation and added functionality für BoardHandler; added shiel visual 2024-11-18 21:30:30 +01:00
Felix
c6438d75cc Fix acousticHandler error 2024-11-18 16:40:01 +01:00
Felix
728530a8f2 Finish loop 2024-11-18 16:16:56 +01:00
Felix
7c09107d28 Work on Dialogs 2024-11-18 15:58:30 +01:00
Cedric Beck
2399bf2678 added world and trees for tree positioning 2024-11-18 12:40:40 +01:00
Cedric Beck
06d795b3e6 working on asset simplification 2024-11-18 12:03:42 +01:00
Cedric Beck
8d9a923970 added rotation for move piece, fixed problems because rotation on the z axis is reversed 2024-11-18 01:58:24 +01:00
Cedric Beck
c95beaeb14 working on pieceMovement 2024-11-17 23:57:36 +01:00
Daniel Grigencha
04501de11c Merge remote-tracking branch 'origin/development' into development 2024-11-17 21:18:38 +01:00
Fleischer Hanno
9cd9cc871c fixed a bug with use of addLast method for ArrayList which doesnot exist in Java 20 2024-11-17 21:18:19 +01:00
Fleischer Hanno
f69a2a9fda added a method to check if a player has pieces in his waiting area 2024-11-17 21:04:13 +01:00
Daniel Grigencha
e83ed1c835 Merge remote-tracking branch 'origin/development' into development 2024-11-17 20:17:29 +01:00
Daniel Grigencha
f379a6b638 added more logic for the server state diagram 2024-11-17 20:17:19 +01:00
Hanno Fleischer
90fb6e4133 added the method tryMove and the methods used by it into serverstate 2024-11-17 17:52:25 +01:00
Hanno Fleischer
9662e1f684 fixed a Bug where the import statement thought a package was a class because they where written the same 2024-11-17 15:34:39 +01:00
Daniel Grigencha
aae7ed9a87 added classes for client and server state machine
- a client state machine consits out of a 'ClientState' (every state of the machine) and a 'ClientStateMachine' (every state, which consists out of states), the machine starts with the ClientAutomaton
- analog for server
- started to implement logic for the server, transition from 'Lobby' to 'GameState'
2024-11-17 15:27:09 +01:00
Hanno Fleischer
07bd7dfa3d Merge branch 'development' into 'dev/test'
Testmerge

See merge request progproj/gruppen-ht24/Gruppe-01!5
2024-11-17 14:20:53 +00:00
Felix
b15dd96a86 Improve music fade and mock 2024-11-17 14:28:48 +01:00
Felix
ada90e787d Improve mock 2024-11-17 13:03:54 +01:00
Felix
cbeb296a44 Mock differen Views 2024-11-17 12:42:20 +01:00
Hanno Fleischer
a9fd13caab Merge branch 'dev/client' into 'development'
Client work of the Week

See merge request progproj/gruppen-ht24/Gruppe-01!4
2024-11-17 11:24:45 +00:00
Hanno Fleischer
a926554709 adjusted for check style 2024-11-17 12:01:00 +01:00
Cedric Beck
bbd84dd961 added code + checkstyle 2024-11-17 11:26:45 +01:00
Cedric Beck
e22f675f8b fixed merge conflict 2024-11-17 11:07:53 +01:00
Cedric Beck
956e9dd2fd merge from dev/client 2024-11-17 10:57:05 +01:00
Hanno Fleischer
020aa92cab added 4 more Notifications for Model -> View interaction 2024-11-17 10:39:36 +01:00
Felix Koppe
bb55ba7273 Merge branch 'dev/client_koppe' into 'dev/client'
Work of the week

See merge request progproj/gruppen-ht24/Gruppe-01!3
2024-11-17 09:09:13 +00:00
Cedric Beck
a2c7b9e299 added all assets; added node array; added node/piece_control saving 2024-11-16 23:05:30 +01:00
Hanno Fleischer
0845aa80f9 adjusted the model infield creation to represent the current view postion regarding the placement of the teams on the board 2024-11-16 22:31:11 +01:00
Hanno Fleischer
44b623f9fd added all Notifications for the model view communication
added all required notifications with their content and getter methods.
2024-11-16 18:58:33 +01:00
Felix
bf678000b8 Minor changes 2024-11-16 18:21:02 +01:00
Felix
e128d9e4cc Add docs to Acoustic 2024-11-16 16:33:21 +01:00
Felix
8c10e69eff General improvements 2024-11-16 16:15:08 +01:00
Hanno Fleischer
6b2d775534 added 2 methods for Test usage in Board and PlayerData 2024-11-16 13:31:56 +01:00
Felix
b509ab772d Add subVolume and delay 2024-11-16 13:07:39 +01:00
Cedric Beck
d0be65323e added rotation compability to map.mdga 2024-11-15 22:47:23 +01:00
Cedric Beck
81facb869f added playerMap for location playerAssets 2024-11-15 21:26:23 +01:00
Felix
b317bb957a Add sound 2024-11-15 16:52:40 +01:00
Felix
202cd7c0e6 Add music credits 2024-11-15 14:57:36 +01:00
Felix
e345edc38e Add game_3 music 2024-11-15 14:42:52 +01:00
Felix
133bffbd6b Add game_6 music 2024-11-15 14:42:41 +01:00
Felix
2287fdc88f Add game_5 music 2024-11-15 14:42:27 +01:00
Felix
976002ddd0 Add game_2 music 2024-11-15 14:42:10 +01:00
Felix
205cb654c7 Add game_1 music 2024-11-15 14:41:52 +01:00
Felix
d8544cc042 Add game_4 music 2024-11-15 14:41:29 +01:00
Felix
0aa7e83d62 Add main menu music 2024-11-15 14:40:59 +01:00
Felix
289c285adf Add lobby music 2024-11-15 14:40:34 +01:00
Felix
a4ac52b591 Add ceremony music 2024-11-15 14:40:09 +01:00
Felix
0bb4706fda Add GameMusic 2024-11-15 14:39:10 +01:00
Felix
a3c5af58d7 Remove grid extend limits 2024-11-14 23:24:12 +01:00
Felix
28960e8961 Activate assertions 2024-11-14 23:10:36 +01:00
Felix
bb7baf44bd Add circle_map.mdga 2024-11-14 22:47:22 +01:00
Felix
206c0d543e Merge commit 2024-11-14 22:14:19 +01:00
Felix
a68ad80402 Remove state classes 2024-11-14 22:13:57 +01:00
Cedric Beck
1cca5a9c6b added MapLoader and map for map view 2024-11-14 21:21:01 +01:00
Hanno Fleischer
ee59807395 Replaced in the notifications Card with BonusCard 2024-11-14 19:58:26 +01:00
Hanno Fleischer
37511d6334 Merge branch 'dev/client_koppe' into 'development'
Dev/client_koppe

See merge request progproj/gruppen-ht24/Gruppe-01!1
2024-11-14 18:45:24 +00:00
Felix
c83baac763 Fix error 2024-11-14 19:36:53 +01:00
Felix
6c7b58b415 Add notification constructors 2024-11-14 19:33:03 +01:00
Benjamin Feyer
33dbbdbe5c initial test commit,
added all testclasses except Playertest, Viewtest, Cameratest, SettingsTest, SoundTest, ReactionTest and ClientStateTest. And filled all created testclasses with empty testmethods, except ServerStateTest.
2024-11-14 18:07:36 +01:00
Felix Koppe
5693817f9b Add notifications 2024-11-14 17:56:43 +01:00
Felix Koppe
94ee786dc8 Minor work 2024-11-14 17:13:56 +01:00
Felix Koppe
92941f903c Merge commit 2024-11-14 16:51:22 +01:00
Cedric Beck
499da6a7ad added new jmonkey version 2024-11-14 16:25:14 +01:00
Hanno Fleischer
9bafd749b6 removed card and fixed codes style
removed card because it was unnecessary and reworked all classes containing it to implement the change
2024-11-14 15:49:22 +01:00
Cedric Beck
b71449b7b4 Merge branch 'view_assets' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into view_assets 2024-11-14 15:44:31 +01:00
Cedric Beck
dfcfe3351e asset 2024-11-14 15:37:25 +01:00
Hanno Fleischer
c7b65d949a added java docs to model/game and wrote the remaining getter and setter 2024-11-14 15:32:27 +01:00
Felix
921933722a Minor work 2024-11-14 15:23:59 +01:00
Felix
7fa45f39c6 Merge remote-tracking branch 'origin/dev_client' into dev_client
# Conflicts:
#	Projekte/mdga/client/src/main/java/pp/mdga/client/Animation/Animation.java
#	Projekte/mdga/client/src/main/java/pp/mdga/client/Animation/AnimationHandler.java
2024-11-14 15:04:41 +01:00
Felix
6849a0a023 Minor work on animation 2024-11-14 14:58:54 +01:00
Daniel Grigencha
e96cd40302 improved code style 2024-11-14 14:51:29 +01:00
Felix
d9a827697d First steps 2024-11-13 19:52:29 +01:00
Felix
0f39ea0dcc Add files 2024-11-13 17:57:14 +01:00
Felix
6e844287dd Delete garbarge 2024-11-13 17:23:07 +01:00
Felix
3465cdaa19 Merge branch 'view_assets' into dev_client
# Conflicts:
#	Projekte/mdga/client/build.gradle
2024-11-13 17:21:24 +01:00
Felix
60adc39c8b Add run config 2024-11-13 17:12:02 +01:00
Felix
8502b97a95 Merge main 2024-11-13 17:10:14 +01:00
Felix
0e90041209 Add .gitattributes and move .gitignore 2024-11-13 17:09:05 +01:00
Felix
f3f63a3e2c Merge main 2024-11-13 17:02:38 +01:00
Cedric Beck
8d02a144eb added screenshot and resources 2024-11-13 14:55:05 +01:00
Felix Koppe
af4caad6be Add .editorconfig 2024-11-13 11:58:07 +01:00
Felix Koppe
d1a343aaa9 Add MdgaApp.java and run config 2024-11-13 11:55:09 +01:00
Cedric Beck
80d70e9a45 added structure for client View 2024-11-12 17:52:39 +01:00
Cedric Beck
516c7ca303 fixed gradle build 2024-11-12 17:41:20 +01:00
Cedric Beck
a684405891 added init for mdga with all states and messages 2024-11-12 17:26:10 +01:00
Daniel Grigencha
ef16a3f92b Revert main branch 2024-10-02 13:30:55 +02:00
Felix Koppe
3a2f20e45c Fix ShipMap.remove 2024-10-02 08:21:32 +02:00
536 changed files with 915843 additions and 44555 deletions

14
.editorconfig Normal file
View File

@@ -0,0 +1,14 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.java]
indent_style = space
indent_size = 4
[*.txt]
indent_style = tab

59
.gitattributes vendored Normal file
View File

@@ -0,0 +1,59 @@
# Git configuration files
.gitattributes text
.gitignore text
.gitconfig text
.gitmodules text
# Documentation
*.md text
*.txt text
AUTHORS text
CHANGELOG text
CHANGES text
CONTRIBUTING text
COPYING text
INSTALL text
LICENSE text
NEWS text
TODO text
# Java sources
*.java text diff=java
*.kt text diff=kotlin
*.groovy text diff=java
*.scala text diff=java
*.gradle text diff=java
*.gradle.kts text diff=kotlin
# Normalize text files (Convert crlf => lf)
*.css text diff=css
*.scss text diff=css
*.sass text
*.df text
*.htm text diff=html
*.html text diff=html
*.js text
*.mjs text
*.cjs text
*.jsp text
*.jspf text
*.jspx text
*.properties text
*.tld text
*.tag text
*.tagx text
*.xml text
# Binary files
# (binary is a macro for -text -diff)
*.class binary
*.dll binary
*.ear binary
*.jar binary
*.so binary
*.war binary
*.jks binary
# Build tool wrappers
mvnw text eol=lf
gradlew text eol=lf

53
.gitignore vendored
View File

@@ -1,26 +1,45 @@
# Gradle
.run/
.gradle
build
build/
#!gradle/wrapper/gradle-wrapper.jar
#!**/src/main/**/build/
#!**/src/test/**/build/
# VSC
bin
# IntelliJ
*.iml
### IntelliJ IDEA ###
.idea
out
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
#!**/src/main/**/out/
#!**/src/test/**/out/
# Eclipse
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
#!**/src/main/**/bin/
#!**/src/test/**/bin/
# Libraries
*.so
*.dylib
*.dll
*.jar
*.class
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
!Projekte/gradle/wrapper/gradle-wrapper.jar

View File

@@ -1,3 +0,0 @@
*.bat text eol=crlf
gradlew text eol=lf

View File

@@ -1,18 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="BattleshipApp (Mac)" type="Application" factoryName="Application"
singleton="false">
<option name="MAIN_CLASS_NAME" value="pp.battleship.client.BattleshipApp"/>
<module name="Projekte.battleship.client.main"/>
<option name="VM_PARAMETERS" value="-XstartOnFirstThread"/>
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$"/>
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.battleship.client.*"/>
<option name="ENABLED" value="true"/>
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true"/>
</method>
</configuration>
</component>

View File

@@ -1,18 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="BattleshipApp" type="Application" factoryName="Application" singleton="false"
nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="pp.battleship.client.BattleshipApp"/>
<module name="Projekte.battleship.client.main"/>
<option name="VM_PARAMETERS" value="-Djava.util.logging.config.file=logging.properties"/>
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$"/>
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.battleship.client.*"/>
<option name="ENABLED" value="true"/>
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true"/>
</method>
</configuration>
</component>

View File

@@ -1,17 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="BattleshipServer" type="Application" factoryName="Application"
nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="pp.battleship.server.BattleshipServer"/>
<module name="Projekte.battleship.server.main"/>
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$"/>
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.battleship.server.*"/>
<option name="ENABLED" value="true"/>
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true"/>
</method>
</configuration>
</component>

View File

@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="MdgaApp" type="Application" factoryName="Application" singleton="false" nameIsGenerated="true">
<option name="ALTERNATIVE_JRE_PATH" value="temurin-20" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="MAIN_CLASS_NAME" value="pp.mdga.client.MdgaApp" />
<module name="Projekte.mdga.client.main" />
<option name="VM_PARAMETERS" value="-Djava.util.logging.config.file=logging.properties -ea" />
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.mdga.client.board.outline.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Projekte [test]" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--continue" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="test" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>

View File

@@ -1,189 +0,0 @@
# Beispielprogramme des Programmierprojekts
Hier ist der Quellcode für das in der Einarbeitungsphase genutzte Spiel
_Battleships_ zu finden. Die Quellen bestehen aus den folgenden
Gradle-Unterprojekten:
* _:battleship:server_
* _:battleship:client_
* _:battleship:model_
* _:battleship:converter_
* _:common_
* _:jme-common_
_Battleships_ ist ein netzwerkbasiertes Spiel und besteht aus einem Server- und
einem Clientanteil, die in den Unterprojekten _:battleship:server_ und
_:battleship:client_ realisiert sind. Beide nutzen das Unterprojekt
_:battleship:model_, das den gemeinsamen Modellanteil enthält.
Die Unterprojekte _:common_ und _:jme-common_ enthalten Hilfsklassen.
Das Unterprojekt _:battleship:converter_ wird für _Battleships_ selbst nicht
benötigt, sondern enthält lediglich den Code, um ein im Spiel verwendetes
3d-Modell eines Schlachtschiffs in eine _J3O_-Datei umzuwandeln, die von jME
einfacher geladen werden kann.
## 1 Vorbereitung
Für das Programmierprojekt empfehlen wir die Verwendung von Java 20. Unter Linux
sollte [_Eclipse Temurin_](https://adoptium.net/temurin/releases/?version=20)
als JDK verwendet werden, andere JDKs können unter Linux Probleme verursachen.
Auf anderen Betriebssystemen empfehlen wir aber ebenfalls Temurin. Im Folgenden
ist beschrieben, wie Sie Temurin installieren und die Umgebungsvariable
**JAVA_HOME** richtig setzen, damit Sie Gradle (siehe unten) verwenden können.
### 1.1 Installation von Temurin
Laden Sie [_Eclipse Temurin_](https://adoptium.net/temurin/releases/?version=20)
entsprechend Ihrem Betriebssystem und Ihrer Prozessorarchitektur herunter und
entpacken Sie das Archiv in einem Verzeichnis Ihrer Wahl auf Ihrem Rechner.
### 1.2 Setzen von JAVA_HOME
Zur Verwendung mit Gradle muss die Umgebungsvariable **JAVA_HOME** richtig
gesetzt werden. Folgen Sie dazu den nachfolgenden Anweisungen entsprechend Ihrem
Betriebssystem:
* **Windows:**
Öffnen Sie ihre Powershell (Core) bzw. ihr Windows Terminal mit Powershell
(Core). Überprüfen Sie, ob die Umgebungsvariable korrekt gesetzt ist:
`Get-ChildItem -Path Env:JAVA_HOME`
Falls kein oder ein falscher Pfad gesetzt ist, setzen Sie diesen mit dem
folgenden Kommando (in einer Zeile):
`[System.Environment]::SetEnvironmentVariable('JAVA_HOME','<Pfad zum SDK>',[System.EnvironmentVariableTarget]::User)`
Alternativ können Sie die GUI verwenden. Unter Windows 10 klicken Sie die
Windows-Taste und dann das Zahnrad um die Einstellungen zu öffnen. Dort wählen
Sie "System", dann "Info" (links unten) und nun
"Erweiterte Systemeinstellungen" (rechts) um den Dialog "Systemeigenschaften"
zu starten. Im Reiter "Erweitert" klicken Sie
"Umgebungsvariablen..." und klicken dann unter "Benutzervariablen" den Knopf
"Neu..." um JAVA_HOME anzulegen oder "Bearbeiten" um ihn zu ändern. Geben Sie
als Name `JAVA_HOME` und als Wert den Pfad ein. Schließen Sie mit "OK".
> **(!) Beachten Sie, dass Sie die jeweilige Applikation neu starten müssen**,
> um von der gesetzten Umgebungsvariablen Notiz zu nehmen.
> Dies betrifft auch die Shell, die Sie gerade verwenden.
* **UNIX (Linux/MacOS):**
Öffnen oder erstellen Sie die Datei `~/.profile` (wenn Sie die Bash verwenden;
bei anderen Shells sind es andere Dateien) und ergänzen Sie am Ende der Datei
die Zeile:
`export JAVA_HOME="<Pfad zum entpackten Archiv>"`
Ersetzen Sie dabei `<Pfad zum entpackten Archiv>` mit dem entsprechenden Pfad.
Zum Beispiel:
`export JAVA_HOME="/home/user/jdk-20.0.2"`
Fügen Sie dann die folgende Zeile hinzu:
`export PATH="$JAVA_HOME/bin:$PATH"`
## 2 Programmstart
Grundsätzlich kann man das gesamte Projekt einfach in IntelliJ öffnen. Details
dazu sind im Aufgabenblatt zur Einarbeitungsaufgabe zu finden. Im Folgenden ist
beschrieben, wie die _Batttleships_ unmittelbar von der Kommandozeile gestartet
werden können.
Um _Battleships_ spielen zu können, muss man zuerst das Server-Programm auf
einem Rechner und dann zweimal das Client-Programm auf beliebigen Rechnern
starten, die TCP/IP-Verbindungen zum Server erlauben. Natürlich ist es auch
möglich, alle drei Programme auf demselben Rechner zu starten.
Es empfiehlt sich der Start von der Kommandozeile. Will man alle drei Programme
auf demselben Rechner starten, sollte man dazu drei Shell-Instanzen öffnen und
in jeder eines der Programme starten. Auf diese Weise können die
Logging-Ausgaben der drei Programme voneinander unterschieden werden.
Das Server-Programm startet man unmittelbar mit Gradle mit
`./gradlew :battleship:server:run`
Unter Windows kann es je nach Shell (Eingabeaufforderung cmd) erforderlich sein,
`/` jeweils durch `\ ` zu ersetzen.
Im Verzeichnis `battleship/server` befindet sich die Datei `config.propeties`,
worüber sich der Server konfigurieren lässt. Mit der Zeile `port=1234` lässt
sich der verwendete Server-Port (hier 1234) einstellen. Außerdem befindet sich
dort die Datei `logging.properties`, womit das Logging des Servers konfiguriert
wird.
Das Client-Programm startet man unmittelbar mit Gradle mit
`./gradlew :battleship:client:run`
Die Datei `logging.properties` im Verzeichnis `battleship/client` konfiguriert
das Logging des Clients.
Alternativ kann man auch die Start-Skripte
* `./battleship/server/build/install/battleship-server/bin/battleship-server`
* `./battleship/client/build/install/battleship/bin/battleship`
direkt in der Kommandozeile starten. Allerdings müssen sie zuvor mittels
`./gradlew installDist`
erzeugt worden sein. Beachten Sie aber, dass nur im **aktuellen
Arbeitsverzeichnis** nach den Dateien `config.properties` und
`logging.properties` gesucht wird und diese geladen werden. Das heißt, dass die
vordefinierten Dateien in den Verzeichnissen `battleship/server` und
`battleship/client` nur dann gelesen werden, wenn Sie diese Verzeichnisse als
aktuelle Arbeitsverzeichnisse nutzen. Wie üblich müssen Sie dazu in der
Kommandozeile
`cd battleship/server`
bzw.
`cd battleship/client`
eingeben.
## 3 Hinweise zu _Battleships_
Der _Battleships_-Client hat ein Menü, in das man immer mit der
Esc-Taste kommt. Aus dem Menü heraus lässt sich das Programm auch schließen.
Beachte, dass sich beim Laden und Speichern eines Spiels kein Dateidialog
öffnet. Vielmehr muss man den Dateipfad in das Dialogfeld eingeben. Da
JSON-Dateien geschrieben werden, empfiehlt sich das Datei-Suffix _.json_.
## 4 Allgemeine Gradle-Tasks:
- `./gradlew clean`
Entfernt alle `build`-Verzeichnisse und alle erzeugten Dateien.
- `./gradlew classes`
Übersetzt den Quellcode und legt unter build den Bytecode sowie
Ressourcen ab.
- `./gradlew javadoc`
Erzeugt die Dokumentation aus den JavaDoc-Kommentaren im Verzeichnis
`build/docs/javadoc` des jeweiligen Unterprojekts.
- `./gradlew test`
Führt die JUnit-Tests durch. Ergebnisse sind im Verzeichnis
`build/reports/tests` des jeweiligen Unterprojekts zu finden.
- `./gradlew build`
Führt die JUnit-Tests durch und erstellt in `build/distributions`
gepackte Distributionsdateien
- `./gradlew installDist`
Erstellt unter `battleship/client/build/install` und
`battleship/server/build/install` Verzeichnisse, die jeweils eine ausführbare
Distribution samt Start-Skripten enthält (siehe oben).
---
Juli 2024

View File

@@ -1,22 +0,0 @@
plugins {
id 'buildlogic.jme-application-conventions'
}
description = 'Battleship Client'
dependencies {
implementation project(":jme-common")
implementation project(":battleship:model")
implementation libs.jme3.desktop
runtimeOnly libs.jme3.awt.dialogs
runtimeOnly libs.jme3.plugins
runtimeOnly libs.jme3.jogg
runtimeOnly libs.jme3.testdata
}
application {
mainClass = 'pp.battleship.client.BattleshipApp'
applicationName = 'battleship'
}

View File

@@ -1,73 +0,0 @@
########################################
## Programming project code
## UniBw M, 2022, 2023, 2024
## www.unibw.de/inf2
## (c) Mark Minas (mark.minas@unibw.de)
########################################
#
# Battleship client configuration
#
# Specifies the map used by the opponent in single mode.
# Single mode is activated if this property is set.
#map.opponent=maps/map2.json
#
# Specifies the map used by the player in single mode.
# The player must define their own map if this property is not set.
map.own=maps/map1.json
#
# Coordinates of the shots fired by the RobotClient in the order listed.
# Example:
# 2, 0,\
# 2, 1,\
# 2, 2,\
# 2, 3
# defines four shots, namely at the coordinates
# (x=2, y=0), (x=2, y=1), (x=2, y=2), and (x=2, y=3)
robot.targets=2, 0,\
2, 1,\
2, 2,\
2, 3
#
# Delay in milliseconds between each shot fired by the RobotClient.
robot.delay=500
#
# The dimensions of the game map used in single mode.
# 'map.width' defines the number of columns, and 'map.height' defines the number of rows.
map.width=10
map.height=10
#
# The number of ships of each length available in single mode.
# The value is a comma-separated list where each element corresponds to the number of ships
# with a specific length. For example:
# ship.nums=4, 3, 2, 1
# This configuration means:
# - 4 ships of length 1
# - 3 ships of length 2
# - 2 ships of length 3
# - 1 ship of length 4
ship.nums=4, 3, 2, 1
#
# Screen settings
#
# Color of the text displayed at the top of the overlay.
# The format is (red, green, blue, alpha) where each value ranges from 0 to 1.
overlay.top.color=1, 1, 1, 1
#
# Application settings configuration
# Determines whether the settings window is shown at startup.
settings.show=false
#
# Specifies the width of the application window in pixels.
settings.resolution.width=1200
#
# Specifies the height of the application window in pixels.
settings.resolution.height=800
#
# Determines whether the application runs in full-screen mode.
settings.full-screen=false
#
# Enables or disables gamma correction to improve color accuracy.
settings.use-gamma-correction=true
#
# Indicates whether the statistics window is displayed during gameplay.
statistics.show=false

View File

@@ -1,8 +0,0 @@
handlers=java.util.logging.ConsoleHandler
.level=INFO
pp.level=FINE
com.jme3.network.level=INFO
;com.jme3.util.TangentBinormalGenerator.level=SEVERE
java.util.logging.ConsoleHandler.level=FINER
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
;java.util.logging.SimpleFormatter.format=[%4$s %2$s] %5$s%n

View File

@@ -1,66 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 4,
"x": 2,
"y": 8,
"rot": "RIGHT"
},
{
"length": 3,
"x": 2,
"y": 5,
"rot": "DOWN"
},
{
"length": 3,
"x": 5,
"y": 6,
"rot": "RIGHT"
},
{
"length": 2,
"x": 4,
"y": 4,
"rot": "RIGHT"
},
{
"length": 2,
"x": 7,
"y": 4,
"rot": "RIGHT"
},
{
"length": 2,
"x": 4,
"y": 2,
"rot": "DOWN"
},
{
"length": 1,
"x": 6,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 6,
"y": 0,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 0,
"rot": "RIGHT"
}
]
}

View File

@@ -1,66 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 4,
"x": 0,
"y": 5,
"rot": "DOWN"
},
{
"length": 3,
"x": 0,
"y": 9,
"rot": "DOWN"
},
{
"length": 3,
"x": 2,
"y": 6,
"rot": "RIGHT"
},
{
"length": 2,
"x": 4,
"y": 8,
"rot": "RIGHT"
},
{
"length": 2,
"x": 2,
"y": 4,
"rot": "DOWN"
},
{
"length": 2,
"x": 2,
"y": 1,
"rot": "DOWN"
},
{
"length": 1,
"x": 6,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 6,
"y": 0,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 0,
"rot": "RIGHT"
}
]
}

View File

@@ -1,429 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client;
import com.jme3.app.DebugKeysAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.system.AppSettings;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.style.BaseStyles;
import pp.battleship.client.gui.BattleAppState;
import pp.battleship.client.gui.EditorAppState;
import pp.battleship.client.gui.SeaAppState;
import pp.battleship.game.client.BattleshipClient;
import pp.battleship.game.client.ClientGameLogic;
import pp.battleship.game.client.ServerConnection;
import pp.battleship.game.singlemode.BattleshipClientConfig;
import pp.battleship.game.singlemode.ServerConnectionMockup;
import pp.battleship.notification.ClientStateEvent;
import pp.battleship.notification.GameEventListener;
import pp.battleship.notification.InfoTextEvent;
import pp.dialog.DialogBuilder;
import pp.dialog.DialogManager;
import pp.graphics.Draw;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.LogManager;
import static pp.battleship.Resources.lookup;
/**
* The main class for the Battleship client application.
* It manages the initialization, input setup, GUI setup, and game states for the client.
*/
public class BattleshipApp extends SimpleApplication implements BattleshipClient, GameEventListener {
/**
* Logger for logging messages within the application.
*/
private static final Logger LOGGER = System.getLogger(BattleshipApp.class.getName());
/**
* Path to the styles script for GUI elements.
*/
private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; //NON-NLS
/**
* Path to the font resource used in the GUI.
*/
private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS
/**
* Path to the client configuration file, if one exists.
*/
private static final File CONFIG_FILE = new File("client.properties");
/**
* Input mapping name for mouse clicks.
*/
public static final String CLICK = "CLICK";
/**
* Input mapping name for the Escape key.
*/
private static final String ESC = "ESC";
/**
* Manager for handling dialogs within the application.
*/
private final DialogManager dialogManager = new DialogManager(this);
/**
* The server connection instance, used for communicating with the game server.
*/
private final ServerConnection serverConnection;
/**
* Instance of the {@link Draw} class for rendering graphics.
*/
private Draw draw;
/**
* Text display at the top of the GUI for showing information to the user.
*/
private BitmapText topText;
/**
* Executor service for handling asynchronous tasks within the application.
*/
private ExecutorService executor;
/**
* Handler for managing the client's game logic.
*/
private final ClientGameLogic logic;
/**
* Configuration settings for the Battleship client application.
*/
private final BattleshipAppConfig config;
/**
* Listener for handling actions triggered by the Escape key.
*/
private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
static {
// Configure logging
LogManager manager = LogManager.getLogManager();
try {
manager.readConfiguration(new FileInputStream("logging.properties"));
LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS
}
catch (IOException e) {
LOGGER.log(Level.INFO, e.getMessage());
}
}
/**
* Starts the Battleship application.
*
* @param args Command-line arguments for launching the application.
*/
public static void main(String[] args) {
new BattleshipApp().start();
}
/**
* Constructs a new {@code BattleshipApp} instance.
* Initializes the configuration, server connection, and game logic listeners.
*/
private BattleshipApp() {
config = new BattleshipAppConfig();
config.readFromIfExists(CONFIG_FILE);
serverConnection = makeServerConnection();
logic = new ClientGameLogic(serverConnection);
logic.addListener(this);
setShowSettings(config.getShowSettings());
setSettings(makeSettings());
}
/**
* Creates and configures application settings from the client configuration.
*
* @return A configured {@link AppSettings} object.
*/
private AppSettings makeSettings() {
final AppSettings settings = new AppSettings(true);
settings.setTitle(lookup("battleship.name"));
settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
settings.setFullscreen(config.fullScreen());
settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer());
settings.setGammaCorrection(config.useGammaCorrection());
return settings;
}
/**
* Factory method for creating a server connection based on the current
* client configuration.
*
* @return A {@link ServerConnection} instance, which could be a real or mock server.
*/
private ServerConnection makeServerConnection() {
if (config.isSingleMode())
return new ServerConnectionMockup(this);
return new NetworkSupport(this);
}
/**
* Returns the dialog manager responsible for managing in-game dialogs.
*
* @return The {@link DialogManager} instance.
*/
DialogManager getDialogManager() {
return dialogManager;
}
/**
* Returns the game logic handler for the client.
*
* @return The {@link ClientGameLogic} instance.
*/
@Override
public ClientGameLogic getGameLogic() {
return logic;
}
/**
* Returns the current configuration settings for the Battleship client.
*
* @return The {@link BattleshipClientConfig} instance.
*/
@Override
public BattleshipAppConfig getConfig() {
return config;
}
/**
* Initializes the application.
* Sets up input mappings, GUI, game states, and connects to the server.
*/
@Override
public void simpleInitApp() {
setPauseOnLostFocus(false);
draw = new Draw(assetManager);
setupInput();
setupStates();
setupGui();
serverConnection.connect();
}
/**
* Sets up the graphical user interface (GUI) for the application.
*/
private void setupGui() {
GuiGlobals.initialize(this);
BaseStyles.loadStyleResources(STYLES_SCRIPT);
GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS
final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
topText = new BitmapText(normalFont);
final int height = context.getSettings().getHeight();
topText.setLocalTranslation(10f, height - 10f, 0f);
topText.setColor(config.getTopColor());
guiNode.attachChild(topText);
}
/**
* Configures input mappings and sets up listeners for user interactions.
*/
private void setupInput() {
inputManager.deleteMapping(INPUT_MAPPING_EXIT);
inputManager.setCursorVisible(false);
inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(escapeListener, ESC);
}
/**
* Initializes and attaches the necessary application states for the game.
*/
private void setupStates() {
if (config.getShowStatistics()) {
final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
final StatsAppState stats = new StatsAppState(guiNode, normalFont);
stateManager.attach(stats);
}
flyCam.setEnabled(false);
stateManager.detach(stateManager.getState(StatsAppState.class));
stateManager.detach(stateManager.getState(DebugKeysAppState.class));
attachGameSound();
stateManager.attachAll(new EditorAppState(), new BattleAppState(), new SeaAppState());
}
/**
* Attaches the game sound state and sets its initial enabled state.
*/
private void attachGameSound() {
final GameSound gameSound = new GameSound();
logic.addListener(gameSound);
gameSound.setEnabled(GameSound.enabledInPreferences());
stateManager.attach(gameSound);
}
/**
* Updates the application state every frame.
* This method is called once per frame during the game loop.
*
* @param tpf Time per frame in seconds.
*/
@Override
public void simpleUpdate(float tpf) {
super.simpleUpdate(tpf);
dialogManager.update(tpf);
logic.update(tpf);
}
/**
* Handles the Escape key action to either close the top dialog or show the main menu.
*
* @param isPressed Indicates whether the Escape key is pressed.
*/
private void escape(boolean isPressed) {
if (!isPressed) return;
if (dialogManager.showsDialog())
dialogManager.escape();
else
new Menu(this).open();
}
/**
* Returns the {@link Draw} instance used for rendering graphical elements in the game.
*
* @return The {@link Draw} instance.
*/
public Draw getDraw() {
return draw;
}
/**
* Handles a request to close the application.
* If the request is initiated by pressing ESC, this parameter is true.
*
* @param esc If true, the request is due to the ESC key being pressed.
*/
@Override
public void requestClose(boolean esc) { /* do nothing */ }
/**
* Closes the application, displaying a confirmation dialog if the client is connected to a server.
*/
public void closeApp() {
if (serverConnection.isConnected())
confirmDialog(lookup("confirm.leaving"), this::close);
else
close();
}
/**
* Closes the application, disconnecting from the server and stopping the application.
*/
private void close() {
serverConnection.disconnect();
stop();
}
/**
* Updates the informational text displayed in the GUI.
*
* @param text The information text to display.
*/
void setInfoText(String text) {
LOGGER.log(Level.DEBUG, "setInfoText {0}", text); //NON-NLS
topText.setText(text);
}
/**
* Updates the informational text in the GUI based on the key received in an {@link InfoTextEvent}.
*
* @param event The {@link InfoTextEvent} containing the key for the text to display.
*/
@Override
public void receivedEvent(InfoTextEvent event) {
LOGGER.log(Level.DEBUG, "received info text {0}", event.key()); //NON-NLS
setInfoText(lookup(event.key()));
}
/**
* Handles client state events to update the game states accordingly.
*
* @param event The {@link ClientStateEvent} representing the state change.
*/
@Override
public void receivedEvent(ClientStateEvent event) {
stateManager.getState(EditorAppState.class).setEnabled(logic.showEditor());
stateManager.getState(BattleAppState.class).setEnabled(logic.showBattle());
stateManager.getState(SeaAppState.class).setEnabled(logic.showBattle());
}
/**
* Returns the executor service used for handling multithreaded tasks.
*
* @return The {@link ExecutorService} instance.
*/
public ExecutorService getExecutor() {
if (executor == null)
executor = Executors.newCachedThreadPool();
return executor;
}
/**
* Stops the application, shutting down the executor service and halting execution.
*
* @param waitFor If true, waits for the application to stop before returning.
*/
@Override
public void stop(boolean waitFor) {
if (executor != null) executor.shutdownNow();
super.stop(waitFor);
}
/**
* Displays a confirmation dialog with a specified question and action for the "Yes" button.
*
* @param question The question to display in the dialog.
* @param yesAction The action to perform if "Yes" is selected.
*/
void confirmDialog(String question, Runnable yesAction) {
DialogBuilder.simple(dialogManager)
.setTitle(lookup("dialog.question"))
.setText(question)
.setOkButton(lookup("button.yes"), yesAction)
.setNoButton(lookup("button.no"))
.build()
.open();
}
/**
* Displays an error dialog with the specified error message.
*
* @param errorMessage The error message to display in the dialog.
*/
void errorDialog(String errorMessage) {
DialogBuilder.simple(dialogManager)
.setTitle(lookup("dialog.error"))
.setText(errorMessage)
.setOkButton(lookup("button.ok"))
.build()
.open();
}
}

View File

@@ -1,196 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client;
import com.jme3.math.ColorRGBA;
import pp.battleship.game.singlemode.BattleshipClientConfig;
/**
* Provides access to the Battleship application configuration.
* Extends {@link BattleshipClientConfig} to include additional properties specific to the client,
* particularly those related to screen settings and visual customization.
* <p>
* <b>Note:</b> Attributes of this class should not be marked as {@code final}
* to ensure proper functionality when reading from a properties file.
* </p>
*/
public class BattleshipAppConfig extends BattleshipClientConfig {
/**
* Converts a string value found in the properties file into an object of the specified type.
* Extends the superclass method to support conversion to {@link ColorRGBA}.
*
* @param value the string value to be converted
* @param targetType the target type into which the value string is converted
* @return the converted object of the specified type
*/
@Override
protected Object convertToType(String value, Class<?> targetType) {
if (targetType == ColorRGBA.class)
return makeColorRGBA(value);
return super.convertToType(value, targetType);
}
/**
* Converts the specified string value to a corresponding {@link ColorRGBA} object.
*
* @param value the color in the format "red, green, blue, alpha" with all values in the range [0..1]
* @return a {@link ColorRGBA} object representing the color
* @throws IllegalArgumentException if the input string is not in the expected format
*/
private static ColorRGBA makeColorRGBA(String value) {
String[] split = value.split(",", -1);
try {
if (split.length == 4)
return new ColorRGBA(Float.parseFloat(split[0]),
Float.parseFloat(split[1]),
Float.parseFloat(split[2]),
Float.parseFloat(split[3]));
}
catch (NumberFormatException e) {
// deliberately left empty
}
throw new IllegalArgumentException(value + " should consist of exactly 4 numbers");
}
/**
* The width of the game view resolution in pixels.
*/
@Property("settings.resolution.width") //NON-NLS
private int resolutionWidth = 1200;
/**
* The height of the game view resolution in pixels.
*/
@Property("settings.resolution.height") //NON-NLS
private int resolutionHeight = 800;
/**
* Specifies whether the game should start in full-screen mode.
*/
@Property("settings.full-screen") //NON-NLS
private boolean fullScreen = false;
/**
* Specifies whether gamma correction should be enabled.
* If enabled, the main framebuffer is configured for sRGB colors,
* and sRGB images are linearized.
* <p>
* Requires a GPU that supports GL_ARB_framebuffer_sRGB; otherwise, this setting will be ignored.
* </p>
*/
@Property("settings.use-gamma-correction") //NON-NLS
private boolean useGammaCorrection = true;
/**
* Specifies whether full resolution framebuffers should be used on Retina displays.
* This setting is ignored on non-Retina platforms.
*/
@Property("settings.use-retina-framebuffer") //NON-NLS
private boolean useRetinaFrameBuffer = false;
/**
* Specifies whether the settings window should be shown for configuring the game.
*/
@Property("settings.show") //NON-NLS
private boolean showSettings = false;
/**
* Specifies whether the JME statistics window should be shown in the lower left corner of the screen.
*/
@Property("statistics.show") //NON-NLS
private boolean showStatistics = false;
/**
* The color of the top text during gameplay, represented as a {@link ColorRGBA} object.
*/
@Property("overlay.top.color") //NON-NLS
private ColorRGBA topColor = ColorRGBA.White;
/**
* Creates a default {@code BattleshipAppConfig} with predefined values.
*/
public BattleshipAppConfig() {
// Default constructor
}
/**
* Returns the width of the game view resolution in pixels.
*
* @return the width of the game view resolution in pixels
*/
public int getResolutionWidth() {
return resolutionWidth;
}
/**
* Returns the height of the game view resolution in pixels.
*
* @return the height of the game view resolution in pixels
*/
public int getResolutionHeight() {
return resolutionHeight;
}
/**
* Returns whether the game should start in full-screen mode.
*
* @return {@code true} if the game should start in full-screen mode; {@code false} otherwise
*/
public boolean fullScreen() {
return fullScreen;
}
/**
* Returns whether gamma correction is enabled.
* If enabled, the main framebuffer is configured for sRGB colors,
* and sRGB images are linearized.
*
* @return {@code true} if gamma correction is enabled; {@code false} otherwise
*/
public boolean useGammaCorrection() {
return useGammaCorrection;
}
/**
* Returns whether full resolution framebuffers should be used on Retina displays.
* This setting is ignored on non-Retina platforms.
*
* @return {@code true} if full resolution framebuffers should be used on Retina displays; {@code false} otherwise
*/
public boolean useRetinaFrameBuffer() {
return useRetinaFrameBuffer;
}
/**
* Returns whether the settings window should be shown for configuring the game.
*
* @return {@code true} if the settings window should be shown; {@code false} otherwise
*/
public boolean getShowSettings() {
return showSettings;
}
/**
* Returns whether the JME statistics window should be shown in the lower left corner of the screen.
*
* @return {@code true} if the statistics window should be shown; {@code false} otherwise
*/
public boolean getShowStatistics() {
return showStatistics;
}
/**
* Returns the color of the top text during gameplay as a {@link ColorRGBA} object.
*
* @return the color of the top text during gameplay
*/
public ColorRGBA getTopColor() {
return topColor;
}
}

View File

@@ -1,102 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import pp.battleship.game.client.ClientGameLogic;
/**
* Abstract class representing a state in the Battleship game.
* Extends the AbstractAppState from jMonkeyEngine to manage state behavior.
*/
public abstract class BattleshipAppState extends AbstractAppState {
private BattleshipApp app;
/**
* Creates a new BattleshipAppState that is initially disabled.
*
* @see #setEnabled(boolean)
*/
protected BattleshipAppState() {
setEnabled(false);
}
/**
* Initializes the state manager and application.
*
* @param stateManager The state manager
* @param application The application instance
*/
@Override
public void initialize(AppStateManager stateManager, Application application) {
super.initialize(stateManager, application);
this.app = (BattleshipApp) application;
if (isEnabled()) enableState();
}
/**
* Returns the BattleshipApp instance associated with this BattleshipAppState.
*
* @return The BattleshipApp instance.
*/
public BattleshipApp getApp() {
return app;
}
/**
* Returns the client game logic handler.
*
* @return the client game logic handler
*/
public ClientGameLogic getGameLogic() {
return app.getGameLogic();
}
/**
* Checks if any dialog is currently displayed.
*
* @return true if any dialog is currently shown, false otherwise
*/
public boolean showsDialog() {
return app.getDialogManager().showsDialog();
}
/**
* Sets the enabled state of the BattleshipAppState.
* If the new state is the same as the current state, the method returns.
*
* @param enabled The new enabled state.
*/
@Override
public void setEnabled(boolean enabled) {
if (isEnabled() == enabled) return;
super.setEnabled(enabled);
if (app != null) {
if (enabled)
enableState();
else
disableState();
}
}
/**
* This method is called when the state is enabled.
* It is meant to be overridden by subclasses to perform
* specific actions when the state is enabled.
*/
protected abstract void enableState();
/**
* This method is called when the state is disabled.
* It is meant to be overridden by subclasses to perform
* specific actions when the state is disabled.
*/
protected abstract void disableState();
}

View File

@@ -1,135 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetLoadException;
import com.jme3.asset.AssetNotFoundException;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode;
import pp.battleship.notification.GameEventListener;
import pp.battleship.notification.SoundEvent;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.prefs.Preferences;
import static pp.util.PreferencesUtils.getPreferences;
/**
* An application state that plays sounds.
*/
public class GameSound extends AbstractAppState implements GameEventListener {
private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
private static final Preferences PREFERENCES = getPreferences(GameSound.class);
private static final String ENABLED_PREF = "enabled"; //NON-NLS
private AudioNode splashSound;
private AudioNode shipDestroyedSound;
private AudioNode explosionSound;
/**
* Checks if sound is enabled in the preferences.
*
* @return {@code true} if sound is enabled, {@code false} otherwise.
*/
public static boolean enabledInPreferences() {
return PREFERENCES.getBoolean(ENABLED_PREF, true);
}
/**
* Toggles the game sound on or off.
*/
public void toggleSound() {
setEnabled(!isEnabled());
}
/**
* Sets the enabled state of this AppState.
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
*
* @param enabled {@code true} to enable the AppState, {@code false} to disable it.
*/
@Override
public void setEnabled(boolean enabled) {
if (isEnabled() == enabled) return;
super.setEnabled(enabled);
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS
PREFERENCES.putBoolean(ENABLED_PREF, enabled);
}
/**
* Initializes the sound effects for the game.
* Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
*
* @param stateManager The state manager
* @param app The application
*/
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
shipDestroyedSound = loadSound(app, "Sound/Effects/sunken.wav"); //NON-NLS
splashSound = loadSound(app, "Sound/Effects/splash.wav"); //NON-NLS
explosionSound = loadSound(app, "Sound/Effects/explosion.wav"); //NON-NLS
}
/**
* Loads a sound from the specified file.
*
* @param app The application
* @param name The name of the sound file.
* @return The loaded AudioNode.
*/
private AudioNode loadSound(Application app, String name) {
try {
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
sound.setLooping(false);
sound.setPositional(false);
return sound;
}
catch (AssetLoadException | AssetNotFoundException ex) {
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
}
return null;
}
/**
* Plays the splash sound effect.
*/
public void splash() {
if (isEnabled() && splashSound != null)
splashSound.playInstance();
}
/**
* Plays the explosion sound effect.
*/
public void explosion() {
if (isEnabled() && explosionSound != null)
explosionSound.playInstance();
}
/**
* Plays sound effect when a ship has been destroyed.
*/
public void shipDestroyed() {
if (isEnabled() && shipDestroyedSound != null)
shipDestroyedSound.playInstance();
}
@Override
public void receivedEvent(SoundEvent event) {
switch (event.sound()) {
case EXPLOSION -> explosion();
case SPLASH -> splash();
case DESTROYED_SHIP -> shipDestroyed();
}
}
}

View File

@@ -1,143 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel;
import pp.dialog.TextInputDialog;
import java.io.File;
import java.io.IOException;
import java.util.prefs.Preferences;
import static pp.battleship.Resources.lookup;
import static pp.util.PreferencesUtils.getPreferences;
/**
* The Menu class represents the main menu in the Battleship game application.
* It extends the Dialog class and provides functionalities for loading, saving,
* returning to the game, and quitting the application.
*/
class Menu extends Dialog {
private static final Preferences PREFERENCES = getPreferences(Menu.class);
private static final String LAST_PATH = "last.file.path";
private final BattleshipApp app;
private final Button loadButton = new Button(lookup("menu.map.load"));
private final Button saveButton = new Button(lookup("menu.map.save"));
/**
* Constructs the Menu dialog for the Battleship application.
*
* @param app the BattleshipApp instance
*/
public Menu(BattleshipApp app) {
super(app.getDialogManager());
this.app = app;
addChild(new Label(lookup("battleship.name"), new ElementId("header"))); //NON-NLS
addChild(new Checkbox(lookup("menu.sound-enabled"),
new StateCheckboxModel(app, GameSound.class)));
addChild(loadButton)
.addClickCommands(s -> ifTopDialog(this::loadDialog));
addChild(saveButton)
.addClickCommands(s -> ifTopDialog(this::saveDialog));
addChild(new Button(lookup("menu.return-to-game")))
.addClickCommands(s -> ifTopDialog(this::close));
addChild(new Button(lookup("menu.quit")))
.addClickCommands(s -> ifTopDialog(app::closeApp));
update();
}
/**
* Updates the state of the load and save buttons based on the game logic.
*/
@Override
public void update() {
loadButton.setEnabled(app.getGameLogic().mayLoadMap());
saveButton.setEnabled(app.getGameLogic().maySaveMap());
}
/**
* As an escape action, this method closes the menu if it is the top dialog.
*/
@Override
public void escape() {
close();
}
/**
* Functional interface for file actions.
*/
@FunctionalInterface
private interface FileAction {
/**
* Executes a file action.
*
* @param file the file to be processed
* @throws IOException if an I/O error occurs
*/
void run(File file) throws IOException;
}
/**
* Handles the file action for the provided dialog.
*
* @param fileAction the file action to be executed
* @param dialog the dialog providing the file input
*/
private void handle(FileAction fileAction, TextInputDialog dialog) {
try {
final String path = dialog.getInput().getText();
PREFERENCES.put(LAST_PATH, path);
fileAction.run(new File(path));
dialog.close();
}
catch (IOException e) {
app.errorDialog(e.getLocalizedMessage());
}
}
/**
* Shows a file dialog for loading or saving files.
*
* @param fileAction the action to perform with the selected file
* @param label the label for the dialog
*/
private void fileDialog(FileAction fileAction, String label) {
final TextInputDialog dialog =
TextInputDialog.builder(app.getDialogManager())
.setLabel(lookup("label.file"))
.setFocus(TextInputDialog::getInput)
.setTitle(label)
.setOkButton(lookup("button.ok"), d -> handle(fileAction, d))
.setNoButton(lookup("button.cancel"))
.setOkClose(false)
.build();
final String path = PREFERENCES.get(LAST_PATH, null);
if (path != null)
dialog.getInput().setText(path.trim());
dialog.open();
}
/**
* Shows the load dialog for loading maps.
*/
private void loadDialog() {
fileDialog(app.getGameLogic()::loadMap, lookup("menu.map.load"));
}
/**
* Shows the save dialog for saving maps.
*/
private void saveDialog() {
fileDialog(app.getGameLogic()::saveMap, lookup("menu.map.save"));
}
}

View File

@@ -1,153 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.dialog.Dialog;
import pp.dialog.DialogBuilder;
import pp.dialog.SimpleDialog;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static pp.battleship.Resources.lookup;
/**
* Represents a dialog for setting up a network connection in the Battleship game.
* Allows users to specify the host and port for connecting to a game server.
*/
class NetworkDialog extends SimpleDialog {
private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName());
private static final String LOCALHOST = "localhost"; //NON-NLS
private static final String DEFAULT_PORT = "1234"; //NON-NLS
private final NetworkSupport network;
private final TextField host = new TextField(LOCALHOST);
private final TextField port = new TextField(DEFAULT_PORT);
private String hostname;
private int portNumber;
private Future<Object> connectionFuture;
private Dialog progressDialog;
/**
* Constructs a new NetworkDialog.
*
* @param network The NetworkSupport instance to be used for network operations.
*/
NetworkDialog(NetworkSupport network) {
super(network.getApp().getDialogManager());
this.network = network;
host.setSingleLine(true);
host.setPreferredWidth(400f);
port.setSingleLine(true);
final BattleshipApp app = network.getApp();
final Container input = new Container(new SpringGridLayout());
input.addChild(new Label(lookup("host.name") + ": "));
input.addChild(host, 1);
input.addChild(new Label(lookup("port.number") + ": "));
input.addChild(port, 1);
DialogBuilder.simple(app.getDialogManager())
.setTitle(lookup("server.dialog"))
.setExtension(d -> d.addChild(input))
.setOkButton(lookup("button.connect"), d -> connect())
.setNoButton(lookup("button.cancel"), app::closeApp)
.setOkClose(false)
.setNoClose(false)
.build(this);
}
/**
* Handles the action for the connect button in the connection dialog.
* Tries to parse the port number and initiate connection to the server.
*/
private void connect() {
LOGGER.log(Level.INFO, "connect to host={0}, port={1}", host, port); //NON-NLS
try {
hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText();
portNumber = Integer.parseInt(port.getText());
openProgressDialog();
connectionFuture = network.getApp().getExecutor().submit(this::initNetwork);
}
catch (NumberFormatException e) {
network.getApp().errorDialog(lookup("port.must.be.integer"));
}
}
/**
* Creates a dialog indicating that the connection is in progress.
*/
private void openProgressDialog() {
progressDialog = DialogBuilder.simple(network.getApp().getDialogManager())
.setText(lookup("label.connecting"))
.build();
progressDialog.open();
}
/**
* Tries to initialize the network connection.
*
* @throws RuntimeException If an error occurs when creating the client.
*/
private Object initNetwork() {
try {
network.initNetwork(hostname, portNumber);
return null;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* This method is called by {@linkplain pp.dialog.DialogManager#update(float)} for periodically
* updating this dialog. T
*/
@Override
public void update(float delta) {
if (connectionFuture != null && connectionFuture.isDone())
try {
connectionFuture.get();
success();
}
catch (ExecutionException e) {
failure(e.getCause());
}
catch (InterruptedException e) {
LOGGER.log(Level.WARNING, "Interrupted!", e); //NON-NLS
Thread.currentThread().interrupt();
}
}
/**
* Handles a successful connection to the game server.
*/
private void success() {
connectionFuture = null;
progressDialog.close();
this.close();
network.getApp().setInfoText(lookup("wait.for.an.opponent"));
}
/**
* Handles a failed connection attempt.
*
* @param e The cause of the failure.
*/
private void failure(Throwable e) {
connectionFuture = null;
progressDialog.close();
network.getApp().errorDialog(lookup("server.connection.failed"));
network.getApp().setInfoText(e.getLocalizedMessage());
}
}

View File

@@ -1,152 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client;
import com.jme3.network.Client;
import com.jme3.network.ClientStateListener;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import pp.battleship.game.client.ServerConnection;
import pp.battleship.message.client.ClientMessage;
import pp.battleship.message.server.ServerMessage;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import static pp.battleship.Resources.lookup;
/**
* Manages the network connection for the Battleship application.
* Handles connecting to and disconnecting from the server, and sending messages.
*/
class NetworkSupport implements MessageListener<Client>, ClientStateListener, ServerConnection {
private static final Logger LOGGER = System.getLogger(NetworkSupport.class.getName());
private final BattleshipApp app;
private Client client;
/**
* Constructs a NetworkSupport instance for the given Battleship application.
*
* @param app The Battleship application instance.
*/
public NetworkSupport(BattleshipApp app) {
this.app = app;
}
/**
* Returns the Battleship application instance.
*
* @return Battleship application instance
*/
BattleshipApp getApp() {
return app;
}
/**
* Checks if there is a connection to the game server.
*
* @return true if there is a connection to the game server, false otherwise.
*/
@Override
public boolean isConnected() {
return client != null && client.isConnected();
}
/**
* Attempts to join the game if there is no connection yet.
* Opens a dialog for the user to enter the host and port information.
*/
@Override
public void connect() {
if (client == null)
new NetworkDialog(this).open();
}
/**
* Closes the client connection.
*/
@Override
public void disconnect() {
if (client == null) return;
client.close();
client = null;
LOGGER.log(Level.INFO, "client closed"); //NON-NLS
}
/**
* Initializes the network connection.
*
* @param host The server's address.
* @param port The server's port.
* @throws IOException If an I/O error occurs when creating the client.
*/
void initNetwork(String host, int port) throws IOException {
if (client != null)
throw new IllegalStateException("trying to join a game again");
client = Network.connectToServer(host, port);
client.start();
client.addMessageListener(this);
client.addClientStateListener(this);
}
/**
* Called when a message is received from the server.
*
* @param client The client instance that received the message.
* @param message The message received from the server.
*/
@Override
public void messageReceived(Client client, Message message) {
LOGGER.log(Level.INFO, "message received from server: {0}", message); //NON-NLS
if (message instanceof ServerMessage serverMessage)
app.enqueue(() -> serverMessage.accept(app.getGameLogic()));
}
/**
* Called when the client has successfully connected to the server.
*
* @param client The client that connected to the server.
*/
@Override
public void clientConnected(Client client) {
LOGGER.log(Level.INFO, "Client connected: {0}", client); //NON-NLS
}
/**
* Called when the client is disconnected from the server.
*
* @param client The client that was disconnected.
* @param disconnectInfo Information about the disconnection.
*/
@Override
public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) {
LOGGER.log(Level.INFO, "Client {0} disconnected: {1}", client, disconnectInfo); //NON-NLS
if (this.client != client)
throw new IllegalArgumentException("parameter value must be client");
LOGGER.log(Level.INFO, "client still connected: {0}", client.isConnected()); //NON-NLS
this.client = null;
disconnect();
app.enqueue(() -> app.setInfoText(lookup("lost.connection.to.server")));
}
/**
* Sends the specified message to the server.
*
* @param message The message to be sent to the server.
*/
@Override
public void send(ClientMessage message) {
LOGGER.log(Level.INFO, "sending {0}", message); //NON-NLS
if (client == null)
app.errorDialog(lookup("lost.connection.to.server"));
else
client.send(message);
}
}

View File

@@ -1,122 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.input.controls.ActionListener;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import pp.battleship.client.BattleshipAppState;
import pp.battleship.model.IntPoint;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import static pp.battleship.client.BattleshipApp.CLICK;
/**
* Represents the state responsible for managing the battle interface within the Battleship game.
* This state handles the display and interaction of the battle map, including the opponent's map.
* It manages GUI components, input events, and the layout of the interface when this state is enabled.
*/
public class BattleAppState extends BattleshipAppState {
private static final Logger LOGGER = System.getLogger(BattleAppState.class.getName());
private static final float DEPTH = 0f;
private static final float GAP = 20f;
/**
* A listener for handling click events in the battle interface.
* When a click is detected, it triggers the corresponding actions on the opponent's map.
*/
private final ActionListener clickListener = (name, isPressed, tpf) -> click(isPressed);
/**
* The root node for all GUI components in the battle state.
*/
private final Node battleNode = new Node("Battle"); //NON-NLS
/**
* A view representing the opponent's map in the GUI.
*/
private MapView opponentMapView;
/**
* Enables the battle state by initializing, laying out, and adding GUI components.
* Attaches the components to the GUI node and registers input listeners.
*/
@Override
protected void enableState() {
battleNode.detachAllChildren();
initializeGuiComponents();
layoutGuiComponents();
addGuiComponents();
getApp().getGuiNode().attachChild(battleNode);
getApp().getInputManager().addListener(clickListener, CLICK);
}
/**
* Disables the battle state by removing GUI components and unregistering input listeners.
* Also handles cleanup of resources, such as the opponent's map view.
*/
@Override
protected void disableState() {
getApp().getGuiNode().detachChild(battleNode);
getApp().getInputManager().removeListener(clickListener);
if (opponentMapView != null) {
opponentMapView.unregister();
opponentMapView = null;
}
}
/**
* Initializes the GUI components used in the battle state.
* Creates the opponent's map view and adds a grid overlay to it.
*/
private void initializeGuiComponents() {
opponentMapView = new MapView(getGameLogic().getOpponentMap(), getApp());
opponentMapView.addGrid();
}
/**
* Adds the initialized GUI components to the battle node.
* Currently, it attaches the opponent's map view to the node.
*/
private void addGuiComponents() {
battleNode.attachChild(opponentMapView.getNode());
}
/**
* Lays out the GUI components within the window, positioning them appropriately.
* The opponent's map view is positioned based on the window's dimensions and a specified gap.
*/
private void layoutGuiComponents() {
final AppSettings s = getApp().getContext().getSettings();
final float mapWidth = opponentMapView.getWidth();
final float mapHeight = opponentMapView.getHeight();
final float windowWidth = s.getWidth();
final float windowHeight = s.getHeight();
opponentMapView.getNode().setLocalTranslation(windowWidth - mapWidth - GAP,
windowHeight - mapHeight - GAP,
DEPTH);
}
/**
* Handles click events in the battle interface. If the event indicates a click (not a release),
* it translates the cursor position to the model's coordinate system and triggers the game logic
* for interacting with the opponent's map.
*
* @param isPressed whether the mouse button is currently pressed (true) or released (false)
*/
private void click(boolean isPressed) {
if (!isPressed || showsDialog())
return;
final IntPoint cursorPos = opponentMapView.mouseToModel(getApp().getInputManager().getCursorPosition());
LOGGER.log(Level.DEBUG, "click: {0}", cursorPos); //NON-NLS
getGameLogic().clickOpponentMap(cursorPos);
}
}

View File

@@ -1,173 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.input.controls.ActionListener;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import pp.battleship.client.BattleshipAppState;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import static pp.battleship.Resources.lookup;
import static pp.battleship.client.BattleshipApp.CLICK;
/**
* EditorState manages the editor mode in the Battleship game,
* allowing players to place and rotate ships.
*/
public class EditorAppState extends BattleshipAppState {
private static final Logger LOGGER = System.getLogger(EditorAppState.class.getName());
private static final float DEPTH = 0f;
private static final float GAP = 20f;
private final ActionListener clickListener = (name, isPressed, tpf) -> click(isPressed);
private final Node editorNode = new Node("Editor"); //NON-NLS
private Container buttonContainer;
private Button rotateButton;
private Button readyButton;
private MapView ownMapView;
private MapView harborView;
private Vector2f oldCursorPosition;
/**
* Enables the editor state by attaching necessary nodes and listeners.
*/
@Override
protected void enableState() {
editorNode.detachAllChildren();
initializeGuiComponents();
addGuiComponents();
layoutGuiComponents();
getApp().getGuiNode().attachChild(editorNode);
getApp().getInputManager().addListener(clickListener, CLICK);
}
/**
* Disables the editor state by detaching nodes and removing listeners.
*/
@Override
protected void disableState() {
getApp().getGuiNode().detachChild(editorNode);
getApp().getInputManager().removeListener(clickListener);
if (ownMapView != null) {
ownMapView.unregister();
ownMapView = null;
}
if (harborView != null) {
harborView.unregister();
harborView = null;
}
}
/**
* Updates the editor state, handling cursor movement and enabling buttons.
*
* @param tpf Time per frame
*/
@Override
public void update(float tpf) {
super.update(tpf);
cursorMovement();
enableButtons();
}
/**
* Enables or disables buttons based on the logic state.
*/
private void enableButtons() {
readyButton.setEnabled(getGameLogic().isMapComplete());
rotateButton.setEnabled(getGameLogic().movingShip());
}
/**
* Handles cursor movement for previewing ship placement.
*/
private void cursorMovement() {
if (!getGameLogic().movingShip() || ownMapView == null || showsDialog())
return;
final Vector2f cursorPosition = getApp().getInputManager().getCursorPosition();
if (!cursorPosition.equals(oldCursorPosition)) {
oldCursorPosition = new Vector2f(cursorPosition);
getGameLogic().movePreview(ownMapView.mouseToModel(cursorPosition));
}
}
/**
* Initializes the GUI components for the editor.
*/
private void initializeGuiComponents() {
ownMapView = new MapView(getGameLogic().getOwnMap(), getApp());
harborView = new MapView(getGameLogic().getHarbor(), getApp());
ownMapView.addGrid();
rotateButton = new Button(lookup("button.rotate"));
readyButton = new Button(lookup("button.ready"));
rotateButton.addClickCommands(e -> {
if (!showsDialog())
getGameLogic().rotateShip();
});
readyButton.addClickCommands(e -> {
if (!showsDialog())
getGameLogic().mapFinished();
});
buttonContainer = new Container();
}
/**
* Adds the GUI components to the editor node.
*/
private void addGuiComponents() {
buttonContainer.addChild(rotateButton, 0, 0);
buttonContainer.addChild(readyButton, 0, 1);
editorNode.attachChild(ownMapView.getNode());
editorNode.attachChild(harborView.getNode());
editorNode.attachChild(buttonContainer);
}
/**
* Lays out the GUI components on the screen.
*/
private void layoutGuiComponents() {
final AppSettings s = getApp().getContext().getSettings();
final float harborWidth = harborView.getWidth();
final float harborHeight = harborView.getHeight();
final float ownMapWidth = ownMapView.getWidth();
final float ownMapHeight = ownMapView.getHeight();
final float windowWidth = s.getWidth();
final float windowHeight = s.getHeight();
ownMapView.getNode()
.setLocalTranslation(0.5f * (windowWidth - harborWidth - ownMapWidth - GAP),
0.5f * (windowHeight - ownMapHeight),
DEPTH);
harborView.getNode()
.setLocalTranslation(0.5f * (windowWidth - harborWidth + ownMapWidth + GAP),
0.5f * (windowHeight - harborHeight),
DEPTH);
buttonContainer.setLocalTranslation(0.5f * (windowWidth - harborWidth - ownMapWidth - GAP),
0.5f * (windowHeight - ownMapHeight - GAP),
DEPTH);
}
/**
* Handles click events to place or rotate ships on the maps.
*/
private void click(boolean isPressed) {
if (!isPressed || showsDialog()) return;
final Vector2f cursorPos = getApp().getInputManager().getCursorPosition();
LOGGER.log(Level.DEBUG, "click: {0}", cursorPos); //NON-NLS
getGameLogic().clickHarbor(harborView.mouseToModel(cursorPos));
getGameLogic().clickOwnMap(ownMapView.mouseToModel(cursorPos));
}
}

View File

@@ -1,191 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.scene.shape.Quad;
import pp.battleship.client.BattleshipApp;
import pp.battleship.model.IntPoint;
import pp.battleship.model.ShipMap;
import pp.util.FloatPoint;
import pp.util.Position;
/**
* Represents the visual view of a {@link ShipMap}, used to display the map structure such as the player's map, harbor,
* and opponent's map. This class handles the graphical representation of the map, including background setup, grid lines,
* and interaction between the model and the view.
*/
class MapView {
private static final float FIELD_SIZE = 40f;
private static final float GRID_LINE_WIDTH = 2f;
private static final float BACKGROUND_DEPTH = -4f;
private static final float GRID_DEPTH = -1f;
private static final ColorRGBA BACKGROUND_COLOR = new ColorRGBA(0, 0.05f, 0.05f, 0.5f);
private static final ColorRGBA GRID_COLOR = ColorRGBA.Green;
// Reference to the main application and the ship map being visualized
private final BattleshipApp app;
private final Node mapNode = new Node("map"); // NON-NLS
private final ShipMap map;
private final MapViewSynchronizer synchronizer;
/**
* Constructs a new MapView for a given {@link ShipMap} and {@link BattleshipApp}.
* Initializes the view by setting up the background and registering a synchronizer to listen to changes in the map.
*
* @param map the ship map to visualize
* @param app the main application instance
*/
MapView(ShipMap map, BattleshipApp app) {
this.map = map;
this.app = app;
this.synchronizer = new MapViewSynchronizer(this);
setupBackground();
app.getGameLogic().addListener(synchronizer);
}
/**
* Unregisters the {@link MapViewSynchronizer} from the listener list of the ClientGameLogic,
* stopping the view from receiving updates when the underlying {@link ShipMap} changes.
* After calling this method, this MapView instance should no longer be used.
*/
void unregister() {
app.getGameLogic().removeListener(synchronizer);
}
/**
* Gets the {@link ShipMap} associated with this view.
*
* @return the ship map
*/
public ShipMap getMap() {
return map;
}
/**
* Gets the {@link BattleshipApp} instance associated with this view.
*
* @return the main application instance
*/
public BattleshipApp getApp() {
return app;
}
/**
* Sets up the background of the map view using a quad geometry.
* The background is configured with a semi-transparent color and placed at a specific depth.
*/
private void setupBackground() {
final Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); // NON-NLS
mat.setColor("Color", BACKGROUND_COLOR); // NON-NLS
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
final Position corner = modelToView(map.getWidth(), map.getHeight());
final Geometry background = new Geometry("MapBackground", new Quad(corner.getX(), corner.getY()));
background.setMaterial(mat);
background.setLocalTranslation(0f, 0f, BACKGROUND_DEPTH);
background.setCullHint(CullHint.Never);
mapNode.attachChild(background);
}
/**
* Adds grid lines to the map view to visually separate the fields within the map.
* The grid lines are drawn based on the dimensions of the ship map.
*/
public void addGrid() {
for (int x = 0; x <= map.getWidth(); x++) {
final Position f = modelToView(x, 0);
final Position t = modelToView(x, map.getHeight());
mapNode.attachChild(gridLine(f, t));
}
for (int y = 0; y <= map.getHeight(); y++) {
final Position f = modelToView(0, y);
final Position t = modelToView(map.getWidth(), y);
mapNode.attachChild(gridLine(f, t));
}
}
/**
* Gets the root node containing all visual elements in this map view.
*
* @return the root node for the map view
*/
public Node getNode() {
return mapNode;
}
/**
* Gets the total width of the map in view coordinates.
*
* @return the width of the map in view coordinates
*/
public float getWidth() {
return FIELD_SIZE * map.getWidth();
}
/**
* Gets the total height of the map in view coordinates.
*
* @return the height of the map in view coordinates
*/
public float getHeight() {
return FIELD_SIZE * map.getHeight();
}
/**
* Converts coordinates from view coordinates to model coordinates.
*
* @param x the x-coordinate in view space
* @param y the y-coordinate in view space
* @return the corresponding model coordinates as an {@link IntPoint}
*/
public IntPoint viewToModel(float x, float y) {
return new IntPoint((int) Math.floor(x / FIELD_SIZE), (int) Math.floor(y / FIELD_SIZE));
}
/**
* Converts coordinates from model coordinates to view coordinates.
*
* @param x the x-coordinate in model space
* @param y the y-coordinate in model space
* @return the corresponding view coordinates as a {@link Position}
*/
public Position modelToView(float x, float y) {
return new FloatPoint(x * FIELD_SIZE, y * FIELD_SIZE);
}
/**
* Converts the mouse position to model coordinates.
* This method takes into account the map's transformation in the 3D scene.
*
* @param pos the 2D vector representing the mouse position in the view
* @return the corresponding model coordinates as an {@link IntPoint}
*/
public IntPoint mouseToModel(Vector2f pos) {
final Vector3f world = new Vector3f(pos.getX(), pos.getY(), 0f);
final Vector3f view = mapNode.getWorldTransform().transformInverseVector(world, null);
return viewToModel(view.getX(), view.getY());
}
/**
* Creates a visual representation of a grid line between two positions.
*
* @param p1 the start position of the grid line
* @param p2 the end position of the grid line
* @return a {@link Geometry} representing the grid line
*/
private Geometry gridLine(Position p1, Position p2) {
return app.getDraw().makeFatLine(p1, p2, GRID_DEPTH, GRID_COLOR, GRID_LINE_WIDTH);
}
}

View File

@@ -1,125 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import pp.battleship.model.Battleship;
import pp.battleship.model.Shot;
import pp.util.Position;
/**
* Synchronizes the visual representation of the ship map with the game model.
* It handles the rendering of ships and shots on the map view, updating the view
* whenever changes occur in the model.
*/
class MapViewSynchronizer extends ShipMapSynchronizer {
// Constants for rendering properties
private static final float SHIP_LINE_WIDTH = 6f;
private static final float SHOT_DEPTH = -2f;
private static final float SHIP_DEPTH = 0f;
private static final float INDENT = 4f;
// Colors used for different visual elements
private static final ColorRGBA HIT_COLOR = ColorRGBA.Red;
private static final ColorRGBA MISS_COLOR = ColorRGBA.Blue;
private static final ColorRGBA SHIP_BORDER_COLOR = ColorRGBA.White;
private static final ColorRGBA PREVIEW_COLOR = ColorRGBA.Gray;
private static final ColorRGBA ERROR_COLOR = ColorRGBA.Red;
// The MapView associated with this synchronizer
private final MapView view;
/**
* Constructs a new MapViewSynchronizer for the given MapView.
* Initializes the synchronizer and adds existing elements from the model to the view.
*
* @param view the MapView to synchronize with the game model
*/
public MapViewSynchronizer(MapView view) {
super(view.getMap(), view.getNode());
this.view = view;
addExisting();
}
/**
* Creates a visual representation of a shot on the map.
* A hit shot is represented in red, while a miss is represented in blue.
*
* @param shot the Shot object representing the shot in the model
* @return a Spatial representing the shot on the map
*/
@Override
public Spatial visit(Shot shot) {
// Convert the shot's model coordinates to view coordinates
final Position p1 = view.modelToView(shot.getX(), shot.getY());
final Position p2 = view.modelToView(shot.getX() + 1, shot.getY() + 1);
final ColorRGBA color = shot.isHit() ? HIT_COLOR : MISS_COLOR;
// Create and return a rectangle representing the shot
return view.getApp().getDraw().makeRectangle(p1.getX(), p1.getY(),
SHOT_DEPTH,
p2.getX() - p1.getX(), p2.getY() - p1.getY(),
color);
}
/**
* Creates a visual representation of a battleship on the map.
* The ship's border color depends on its status: normal, valid preview, or invalid preview.
*
* @param ship the Battleship object representing the ship in the model
* @return a Spatial representing the ship on the map
*/
@Override
public Spatial visit(Battleship ship) {
// Create a node to represent the ship
final Node shipNode = new Node("ship"); //NON-NLS
// Convert the ship's model coordinates to view coordinates
final Position p1 = view.modelToView(ship.getMinX(), ship.getMinY());
final Position p2 = view.modelToView(ship.getMaxX() + 1, ship.getMaxY() + 1);
// Calculate the coordinates for the ship's bounding box
final float x1 = p1.getX() + INDENT;
final float y1 = p1.getY() + INDENT;
final float x2 = p2.getX() - INDENT;
final float y2 = p2.getY() - INDENT;
// Determine the color based on the ship's status
final ColorRGBA color = switch (ship.getStatus()) {
case NORMAL -> SHIP_BORDER_COLOR;
case VALID_PREVIEW -> PREVIEW_COLOR;
case INVALID_PREVIEW -> ERROR_COLOR;
};
// Add the ship's borders to the node
shipNode.attachChild(shipLine(x1, y1, x2, y1, color));
shipNode.attachChild(shipLine(x1, y2, x2, y2, color));
shipNode.attachChild(shipLine(x1, y1, x1, y2, color));
shipNode.attachChild(shipLine(x2, y1, x2, y2, color));
// Return the complete ship representation
return shipNode;
}
/**
* Creates a line geometry representing part of the ship's border.
*
* @param x1 the starting x-coordinate of the line
* @param y1 the starting y-coordinate of the line
* @param x2 the ending x-coordinate of the line
* @param y2 the ending y-coordinate of the line
* @param color the color of the line
* @return a Geometry representing the line
*/
private Geometry shipLine(float x1, float y1, float x2, float y2, ColorRGBA color) {
return view.getApp().getDraw().makeFatLine(x1, y1, x2, y2, SHIP_DEPTH, color, SHIP_LINE_WIDTH);
}
}

View File

@@ -1,203 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.app.Application;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.texture.Texture;
import com.jme3.util.SkyFactory;
import com.jme3.util.TangentBinormalGenerator;
import pp.battleship.client.BattleshipAppState;
import pp.battleship.model.ShipMap;
import pp.util.FloatMath;
import static pp.util.FloatMath.TWO_PI;
import static pp.util.FloatMath.cos;
import static pp.util.FloatMath.sin;
import static pp.util.FloatMath.sqrt;
/**
* Manages the rendering and visual aspects of the sea and sky in the Battleship game.
* This state is responsible for setting up and updating the sea, sky, and lighting
* conditions, and controls the camera to create a dynamic view of the game environment.
*/
public class SeaAppState extends BattleshipAppState {
/**
* The path to the sea texture material.
*/
private static final String SEA_TEXTURE = "Textures/Terrain/Water/Water.j3m"; //NON-NLS
private static final float ABOVE_SEA_LEVEL = 4f;
private static final float INCLINATION = 2.5f;
/**
* The root node for all visual elements in this state.
*/
private final Node viewNode = new Node("view"); //NON-NLS
/**
* The node containing the scene elements, such as the sea surface.
*/
private final Node sceneNode = new Node("scene"); //NON-NLS
/**
* Synchronizes the sea's visual representation with the game logic.
*/
private SeaSynchronizer synchronizer;
/**
* The current angle of the camera around the center of the map.
*/
private float cameraAngle;
/**
* Initializes the state by setting up the sky, lights, and other visual components.
* This method is called when the state is first attached to the state manager.
*
* @param stateManager the state manager
* @param application the application
*/
@Override
public void initialize(AppStateManager stateManager, Application application) {
super.initialize(stateManager, application);
viewNode.attachChild(sceneNode);
setupLights();
setupSky();
}
/**
* Enables the sea and sky state, setting up the scene and registering any necessary listeners.
* This method is called when the state is set to active.
*/
@Override
protected void enableState() {
sceneNode.detachAllChildren();
setupScene();
if (synchronizer == null) {
synchronizer = new SeaSynchronizer(getApp(), sceneNode, getGameLogic().getOwnMap());
getGameLogic().addListener(synchronizer);
}
getApp().getRootNode().attachChild(viewNode);
}
/**
* Disables the sea and sky state, removing visual elements from the scene and unregistering listeners.
* This method is called when the state is set to inactive.
*/
@Override
protected void disableState() {
getApp().getRootNode().detachChild(viewNode);
if (synchronizer != null) {
getGameLogic().removeListener(synchronizer);
synchronizer = null;
}
}
/**
* Updates the state each frame, moving the camera to simulate it circling around the map.
*
* @param tpf the time per frame (seconds)
*/
@Override
public void update(float tpf) {
super.update(tpf);
cameraAngle += TWO_PI * 0.05f * tpf;
adjustCamera();
}
/**
* Sets up the lighting for the scene, including directional and ambient lights.
* Also configures shadows to enhance the visual depth of the scene.
*/
private void setupLights() {
final AssetManager assetManager = getApp().getAssetManager();
final DirectionalLightShadowRenderer shRend = new DirectionalLightShadowRenderer(assetManager, 2048, 3);
shRend.setLambda(0.55f);
shRend.setShadowIntensity(0.6f);
shRend.setEdgeFilteringMode(EdgeFilteringMode.Bilinear);
getApp().getViewPort().addProcessor(shRend);
final DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-1f, -0.7f, -1f).normalizeLocal());
viewNode.addLight(sun);
shRend.setLight(sun);
final AmbientLight ambientLight = new AmbientLight(new ColorRGBA(0.3f, 0.3f, 0.3f, 0f));
viewNode.addLight(ambientLight);
}
/**
* Sets up the sky in the scene using a skybox with textures for all six directions.
* This creates a realistic and immersive environment for the sea.
*/
private void setupSky() {
final AssetManager assetManager = getApp().getAssetManager();
final Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); //NON-NLS
final Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); //NON-NLS
final Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); //NON-NLS
final Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); //NON-NLS
final Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); //NON-NLS
final Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); //NON-NLS
final Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down);
sky.rotate(0f, FloatMath.PI, 0f);
viewNode.attachChild(sky);
}
/**
* Sets up the sea surface in the scene. This includes creating the sea mesh,
* applying textures, and enabling shadows.
*/
private void setupScene() {
final ShipMap ownMap = getGameLogic().getOwnMap();
final float x = 0.5f * ownMap.getWidth();
final float y = 0.5f * ownMap.getHeight();
final Box seaMesh = new Box(y + 0.5f, 0.1f, x + 0.5f);
final Geometry seaGeo = new Geometry("sea", seaMesh); //NON-NLS
seaGeo.setLocalTranslation(new Vector3f(y, -0.1f, x));
seaMesh.scaleTextureCoordinates(new Vector2f(4f, 4f));
final Material seaMat = getApp().getAssetManager().loadMaterial(SEA_TEXTURE);
seaGeo.setMaterial(seaMat);
seaGeo.setShadowMode(ShadowMode.CastAndReceive);
TangentBinormalGenerator.generate(seaGeo);
sceneNode.attachChild(seaGeo);
}
/**
* Adjusts the camera position and orientation to create a circular motion around
* the center of the map. This provides a dynamic view of the sea and surrounding environment.
*/
private void adjustCamera() {
final ShipMap ownMap = getGameLogic().getOwnMap();
final float mx = 0.5f * ownMap.getWidth();
final float my = 0.5f * ownMap.getHeight();
final float radius = 2f * sqrt(mx * mx + my + my);
final float cos = radius * cos(cameraAngle);
final float sin = radius * sin(cameraAngle);
final float x = mx - cos;
final float y = my - sin;
final Camera camera = getApp().getCamera();
camera.setLocation(new Vector3f(y, ABOVE_SEA_LEVEL, x));
camera.getRotation().lookAt(new Vector3f(sin, -INCLINATION, cos),
Vector3f.UNIT_Y);
camera.update();
}
}

View File

@@ -1,213 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Cylinder;
import pp.battleship.client.BattleshipApp;
import pp.battleship.model.Battleship;
import pp.battleship.model.Rotation;
import pp.battleship.model.ShipMap;
import pp.battleship.model.Shot;
import static java.util.Objects.requireNonNull;
import static pp.util.FloatMath.HALF_PI;
import static pp.util.FloatMath.PI;
/**
* The {@code SeaSynchronizer} class is responsible for synchronizing the graphical
* representation of the ships and shots on the sea map with the underlying data model.
* It extends the {@link ShipMapSynchronizer} to provide specific synchronization
* logic for the sea map.
*/
class SeaSynchronizer extends ShipMapSynchronizer {
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
private static final String KING_GEORGE_V_MODEL = "Models/KingGeorgeV/KingGeorgeV.j3o"; //NON-NLS
private static final String COLOR = "Color"; //NON-NLS
private static final String SHIP = "ship"; //NON-NLS
private static final String SHOT = "shot"; //NON-NLS
private static final ColorRGBA BOX_COLOR = ColorRGBA.Gray;
private static final ColorRGBA SPLASH_COLOR = new ColorRGBA(0f, 0f, 1f, 0.4f);
private static final ColorRGBA HIT_COLOR = new ColorRGBA(1f, 0f, 0f, 0.4f);
private final ShipMap map;
private final BattleshipApp app;
/**
* Constructs a {@code SeaSynchronizer} object with the specified application, root node, and ship map.
*
* @param app the Battleship application
* @param root the root node to which graphical elements will be attached
* @param map the ship map containing the ships and shots
*/
public SeaSynchronizer(BattleshipApp app, Node root, ShipMap map) {
super(app.getGameLogic().getOwnMap(), root);
this.app = app;
this.map = map;
addExisting();
}
/**
* Visits a {@link Shot} and creates a graphical representation of it.
* If the shot is a hit, it attaches the representation to the ship node.
*
* @param shot the shot to be represented
* @return the graphical representation of the shot, or null if the shot is a hit
* and the representation has been attached to the ship node
*/
@Override
public Spatial visit(Shot shot) {
return shot.isHit() ? handleHit(shot) : createCylinder(shot);
}
/**
* Handles a hit by attaching its representation to the node that
* contains the ship model as a child so that it moves with the ship.
*
* @param shot a hit
* @return always null to prevent the representation from being attached
* to the items node as well
*/
private Spatial handleHit(Shot shot) {
final Battleship ship = requireNonNull(map.findShipAt(shot), "Missing ship");
final Node shipNode = requireNonNull((Node) getSpatial(ship), "Missing ship node");
final Geometry representation = createCylinder(shot);
representation.getLocalTranslation().subtractLocal(shipNode.getLocalTranslation());
shipNode.attachChild(representation);
return null;
}
/**
* Creates a cylinder geometry representing the specified shot.
* The appearance of the cylinder depends on whether the shot is a hit or a miss.
*
* @param shot the shot to be represented
* @return the geometry representing the shot
*/
private Geometry createCylinder(Shot shot) {
final ColorRGBA color = shot.isHit() ? HIT_COLOR : SPLASH_COLOR;
final float height = shot.isHit() ? 1.2f : 0.1f;
final Cylinder cylinder = new Cylinder(2, 20, 0.45f, height, true);
final Geometry geometry = new Geometry(SHOT, cylinder);
geometry.setMaterial(createColoredMaterial(color));
geometry.rotate(HALF_PI, 0f, 0f);
// compute the center of the shot in world coordinates
geometry.setLocalTranslation(shot.getY() + 0.5f, 0f, shot.getX() + 0.5f);
return geometry;
}
/**
* Visits a {@link Battleship} and creates a graphical representation of it.
* The representation is either a 3D model or a simple box depending on the
* type of battleship.
*
* @param ship the battleship to be represented
* @return the node containing the graphical representation of the battleship
*/
@Override
public Spatial visit(Battleship ship) {
final Node node = new Node(SHIP);
node.attachChild(createShip(ship));
// compute the center of the ship in world coordinates
final float x = 0.5f * (ship.getMinY() + ship.getMaxY() + 1f);
final float z = 0.5f * (ship.getMinX() + ship.getMaxX() + 1f);
node.setLocalTranslation(x, 0f, z);
node.addControl(new ShipControl(ship));
return node;
}
/**
* Creates the appropriate graphical representation of the specified battleship.
* The representation is either a detailed model or a simple box based on the length of the ship.
*
* @param ship the battleship to be represented
* @return the spatial representing the battleship
*/
private Spatial createShip(Battleship ship) {
return ship.getLength() == 4 ? createBattleship(ship) : createBox(ship);
}
/**
* Creates a simple box to represent a battleship that is not of the "King George V" type.
*
* @param ship the battleship to be represented
* @return the geometry representing the battleship as a box
*/
private Spatial createBox(Battleship ship) {
final Box box = new Box(0.5f * (ship.getMaxY() - ship.getMinY()) + 0.3f,
0.3f,
0.5f * (ship.getMaxX() - ship.getMinX()) + 0.3f);
final Geometry geometry = new Geometry(SHIP, box);
geometry.setMaterial(createColoredMaterial(BOX_COLOR));
geometry.setShadowMode(ShadowMode.CastAndReceive);
return geometry;
}
/**
* Creates a new {@link Material} with the specified color.
* If the color includes transparency (i.e., alpha value less than 1),
* the material's render state is set to use alpha blending, allowing for
* semi-transparent rendering.
*
* @param color the {@link ColorRGBA} to be applied to the material. If the alpha value
* of the color is less than 1, the material will support transparency.
* @return a {@link Material} instance configured with the specified color and,
* if necessary, alpha blending enabled.
*/
private Material createColoredMaterial(ColorRGBA color) {
final Material material = new Material(app.getAssetManager(), UNSHADED);
if (color.getAlpha() < 1f)
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
material.setColor(COLOR, color);
return material;
}
/**
* Creates a detailed 3D model to represent a "King George V" battleship.
*
* @param ship the battleship to be represented
* @return the spatial representing the "King George V" battleship
*/
private Spatial createBattleship(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(KING_GEORGE_V_MODEL);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(1.48f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
/**
* Calculates the rotation angle for the specified rotation.
*
* @param rot the rotation of the battleship
* @return the rotation angle in radians
*/
private static float calculateRotationAngle(Rotation rot) {
return switch (rot) {
case RIGHT -> HALF_PI;
case DOWN -> 0f;
case LEFT -> -HALF_PI;
case UP -> PI;
};
}
}

View File

@@ -1,106 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import pp.battleship.model.Battleship;
import static pp.util.FloatMath.DEG_TO_RAD;
import static pp.util.FloatMath.TWO_PI;
import static pp.util.FloatMath.sin;
/**
* Controls the oscillating pitch motion of a battleship model in the game.
* The ship oscillates to simulate a realistic movement on water, based on its orientation and length.
*/
class ShipControl extends AbstractControl {
/**
* The axis of rotation for the ship's pitch (tilting forward and backward).
*/
private final Vector3f axis;
/**
* The duration of one complete oscillation cycle in seconds.
*/
private final float cycle;
/**
* The amplitude of the pitch oscillation in radians, determining how much the ship tilts.
*/
private final float amplitude;
/**
* A quaternion representing the ship's current pitch rotation.
*/
private final Quaternion pitch = new Quaternion();
/**
* The current time within the oscillation cycle, used to calculate the ship's pitch angle.
*/
private float time;
/**
* Constructs a new ShipControl instance for the specified Battleship.
* The ship's orientation determines the axis of rotation, while its length influences
* the cycle duration and amplitude of the oscillation.
*
* @param ship the Battleship object to control
*/
public ShipControl(Battleship ship) {
// Determine the axis of rotation based on the ship's orientation
axis = switch (ship.getRot()) {
case LEFT, RIGHT -> Vector3f.UNIT_X;
case UP, DOWN -> Vector3f.UNIT_Z;
};
// Set the cycle duration and amplitude based on the ship's length
cycle = ship.getLength() * 2f;
amplitude = 5f * DEG_TO_RAD / ship.getLength();
}
/**
* Updates the ship's pitch oscillation each frame. The ship's pitch is adjusted
* to create a continuous tilting motion, simulating the effect of waves.
*
* @param tpf time per frame (in seconds), used to calculate the new pitch angle
*/
@Override
protected void controlUpdate(float tpf) {
// If spatial is null, do nothing
if (spatial == null) return;
// Update the time within the oscillation cycle
time = (time + tpf) % cycle;
// Calculate the current angle of the oscillation
final float angle = amplitude * sin(time * TWO_PI / cycle);
// Update the pitch Quaternion with the new angle
pitch.fromAngleAxis(angle, axis);
// Apply the pitch rotation to the spatial
spatial.setLocalRotation(pitch);
}
/**
* This method is called during the rendering phase, but it does not perform any
* operations in this implementation as the control only influences the spatial's
* transformation, not its rendering process.
*
* @param rm the RenderManager rendering the controlled Spatial (not null)
* @param vp the ViewPort being rendered (not null)
*/
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
// No rendering logic is needed for this control
}
}

View File

@@ -1,89 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.client.gui;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import pp.battleship.model.Item;
import pp.battleship.model.ShipMap;
import pp.battleship.model.Visitor;
import pp.battleship.notification.GameEventListener;
import pp.battleship.notification.ItemAddedEvent;
import pp.battleship.notification.ItemRemovedEvent;
import pp.view.ModelViewSynchronizer;
/**
* Abstract base class for synchronizing the visual representation of a {@link ShipMap} with its model state.
* This class handles the addition and removal of items from the ship map, ensuring that changes in the model
* are accurately reflected in the view.
* <p>
* Subclasses are responsible for providing the specific implementation of how each item in the map
* is represented visually by implementing the {@link Visitor} interface.
* </p>
*/
abstract class ShipMapSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
// The ship map that this synchronizer is responsible for
private final ShipMap shipMap;
/**
* Constructs a new ShipMapSynchronizer.
* Initializes the synchronizer with the provided ship map and the root node for attaching view representations.
*
* @param map the ship map to be synchronized
* @param root the root node to which the view representations of the ship map items are attached
*/
protected ShipMapSynchronizer(ShipMap map, Node root) {
super(root);
this.shipMap = map;
}
/**
* Translates a model item into its corresponding visual representation.
* The specific visual representation is determined by the concrete implementation of the {@link Visitor} interface.
*
* @param item the item from the model to be translated
* @return the visual representation of the item as a {@link Spatial}
*/
@Override
protected Spatial translate(Item item) {
return item.accept(this);
}
/**
* Adds the existing items from the ship map to the view.
* This method should be called during initialization to ensure that all current items in the ship map
* are visually represented.
*/
protected void addExisting() {
shipMap.getItems().forEach(this::add);
}
/**
* Handles the event when an item is removed from the ship map.
* Removes the visual representation of the item from the view if it belongs to the synchronized ship map.
*
* @param event the event indicating that an item has been removed from the ship map
*/
@Override
public void receivedEvent(ItemRemovedEvent event) {
if (shipMap == event.map())
delete(event.item());
}
/**
* Handles the event when an item is added to the ship map.
* Adds the visual representation of the new item to the view if it belongs to the synchronized ship map.
*
* @param event the event indicating that an item has been added to the ship map
*/
@Override
public void receivedEvent(ItemAddedEvent event) {
if (shipMap == event.map())
add(event.item());
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -1,3 +0,0 @@
based on:
https://free3d.com/3d-model/wwii-ship-uk-king-george-v-class-battleship-v1--185381.html
License: Free Personal Use Only

View File

@@ -1,4 +0,0 @@
based on:
water 002
by Katsukagi on 29/11/2018
https://3dtextures.me/2018/11/29/water-002/

View File

@@ -1,14 +0,0 @@
Material Water : Common/MatDefs/Light/Lighting.j3md {
MaterialParameters {
Shininess : 64
DiffuseMap : Repeat Textures/Terrain/Water/Water_002_COLOR.jpg
NormalMap : Repeat Textures/Terrain/Water/Water_002_NORM.jpg
SpecularMap : Repeat Textures/Terrain/Water/Water_002_ROUGH.jpg
ParallaxMap : Repeat Textures/Terrain/Water/Water_002_DISP.png
// PackedNormalParallax : true
// UseMaterialColors : true
Ambient : 0.5 0.5 0.5 1.0
Diffuse : 1.0 1.0 1.0 1.0
Specular : 1.0 1.0 1.0 1.0
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -1,16 +0,0 @@
plugins {
id 'buildlogic.jme-application-conventions'
}
description = 'Battleship converter for resources'
dependencies {
implementation libs.jme3.core
runtimeOnly libs.jme3.desktop
runtimeOnly libs.jme3.plugins
}
application {
mainClass = 'pp.battleship.exporter.ModelExporter'
}

View File

@@ -1,69 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.exporter;
import com.jme3.app.SimpleApplication;
import com.jme3.export.JmeExporter;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.scene.Spatial;
import com.jme3.system.JmeContext;
import com.jme3.util.TangentBinormalGenerator;
import java.io.File;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
/**
* This class transforms models into j3o format.
*/
public class ModelExporter extends SimpleApplication {
private static final Logger LOGGER = System.getLogger(ModelExporter.class.getName());
/**
* The main method of the converter
*
* @param args input args
*/
public static void main(String[] args) {
ModelExporter application = new ModelExporter();
application.start(JmeContext.Type.Headless);
}
/**
* Overrides {@link com.jme3.app.SimpleApplication#simpleInitApp()}.
* It initializes a simple app by exporting robots and rocks.
*/
@Override
public void simpleInitApp() {
export("Models/KingGeorgeV/King_George_V.obj", "KingGeorgeV.j3o"); //NON-NLS
stop();
}
/**
* Exports spatial into a file
*
* @param fileName the file name of the model
* @param exportFileName the name of the file where the .j3o file is going to be stored
*/
private void export(String fileName, String exportFileName) {
final File file = new File(exportFileName);
JmeExporter exporter = BinaryExporter.getInstance();
try {
final Spatial model = getAssetManager().loadModel(fileName);
TangentBinormalGenerator.generate(model);
exporter.save(model, file);
}
catch (IOException exception) {
LOGGER.log(Level.ERROR, "write to {0} failed", file); //NON-NLS
throw new RuntimeException(exception);
}
LOGGER.log(Level.INFO, "wrote file {0}", file); //NON-NLS
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

View File

@@ -1,18 +0,0 @@
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 16.03.2012 14:15:53
newmtl _King_George_V
Ns 60.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.4500 0.4500 0.4500
Ke 0.0000 0.0000 0.0000
map_Ka King_George_V.jpg
map_Kd King_George_V.jpg
map_bump King_George_V_bump.jpg
bump King_George_V_bump.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -1,3 +0,0 @@
based on:
https://free3d.com/3d-model/wwii-ship-uk-king-george-v-class-battleship-v1--185381.html
License: Free Personal Use Only

View File

@@ -1,103 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship;
import pp.util.config.Config;
import java.util.Map;
import java.util.TreeMap;
import static java.lang.Math.max;
/**
* Provides access to the configuration settings for the Battleship game.
* <p>
* This class allows for loading configuration settings from a properties file,
* including the server port, map dimensions, and the number of ships of various lengths.
* </p>
* <p>
* <b>Note:</b> Attributes of this class are not marked as {@code final} to allow
* for proper initialization when reading from a properties file.
* </p>
*/
public class BattleshipConfig extends Config {
/**
* The default port number for the Battleship server.
*/
@Property("port")
private int port = 1234;
/**
* The width of the game map in terms of grid units.
*/
@Property("map.width")
private int mapWidth = 10;
/**
* The height of the game map in terms of grid units.
*/
@Property("map.height")
private int mapHeight = 10;
/**
* An array representing the number of ships available for each length.
* The index corresponds to the ship length minus one, and the value at each index
* is the number of ships of that length.
*/
@Property("ship.nums")
private int[] shipNums = {4, 3, 2, 1};
/**
* Creates an instance of {@code BattleshipConfig} with default settings.
*/
public BattleshipConfig() {
// Default constructor
}
/**
* Returns the port number configured for the Battleship server.
*
* @return the port number
*/
public int getPort() {
return port;
}
/**
* Returns the width of the game map. The width is guaranteed to be at least 2 units.
*
* @return the width of the game map
*/
public int getMapWidth() {
return max(mapWidth, 2);
}
/**
* Returns the height of the game map. The height is guaranteed to be at least 2 units.
*
* @return the height of the game map
*/
public int getMapHeight() {
return max(mapHeight, 2);
}
/**
* Returns a map representing the number of ships for each length.
* The keys are ship lengths, and the values are the corresponding number of ships.
*
* @return a map of ship lengths to the number of ships
*/
public Map<Integer, Integer> getShipNums() {
final TreeMap<Integer, Integer> ships = new TreeMap<>();
for (int i = 0; i < shipNums.length; i++)
if (shipNums[i] > 0)
ships.put(i + 1, shipNums[i]);
return ships;
}
}

View File

@@ -1,40 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship;
import java.util.ResourceBundle;
/**
* Provides access to the resource bundle of the game.
*
* @see #BUNDLE
*/
public class Resources {
/**
* The resource bundle for the Battleship game.
*/
public static final ResourceBundle BUNDLE = ResourceBundle.getBundle("battleship"); //NON-NLS
/**
* Gets a string for the given key from the resource bundle in {@linkplain #BUNDLE}.
*
* @param key the key for the desired string
* @return the string for the given key
* @throws NullPointerException if {@code key} is {@code null}
* @throws java.util.MissingResourceException if no object for the given key can be found
* @throws ClassCastException if the object found for the given key is not a string
*/
public static String lookup(String key) {
return BUNDLE.getString(key);
}
/**
* Private constructor to prevent instantiation.
*/
private Resources() { /* do not instantiate */ }
}

View File

@@ -1,102 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.message.client.ShootMessage;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.model.IntPoint;
import pp.battleship.model.ShipMap;
import pp.battleship.notification.Sound;
import java.lang.System.Logger.Level;
/**
* Represents the state of the client where players take turns to attack each other's ships.
*/
class BattleState extends ClientState {
private boolean myTurn;
/**
* Constructs a new instance of {@link BattleState}.
*
* @param logic the game logic
* @param myTurn true if it is my turn
*/
public BattleState(ClientGameLogic logic, boolean myTurn) {
super(logic);
this.myTurn = myTurn;
}
@Override
public boolean showBattle() {
return true;
}
@Override
public void clickOpponentMap(IntPoint pos) {
if (!myTurn)
logic.setInfoText("wait.its.not.your.turn");
else if (logic.getOpponentMap().isValid(pos))
logic.send(new ShootMessage(pos));
}
/**
* Reports the effect of a shot based on the server message.
*
* @param msg the message containing the effect of the shot
*/
@Override
public void receivedEffect(EffectMessage msg) {
ClientGameLogic.LOGGER.log(Level.INFO, "report effect: {0}", msg); //NON-NLS
playSound(msg);
myTurn = msg.isMyTurn();
logic.setInfoText(msg.getInfoTextKey());
affectedMap(msg).add(msg.getShot());
if (destroyedOpponentShip(msg))
logic.getOpponentMap().add(msg.getDestroyedShip());
if (msg.isGameOver()) {
msg.getRemainingOpponentShips().forEach(logic.getOwnMap()::add);
logic.setState(new GameOverState(logic));
}
}
/**
* Determines which map (own or opponent's) should be affected by the shot based on the message.
*
* @param msg the effect message received from the server
* @return the map (either the opponent's or player's own map) that is affected by the shot
*/
private ShipMap affectedMap(EffectMessage msg) {
return msg.isOwnShot() ? logic.getOpponentMap() : logic.getOwnMap();
}
/**
* Checks if the opponent's ship was destroyed by the player's shot.
*
* @param msg the effect message received from the server
* @return true if the shot destroyed an opponent's ship, false otherwise
*/
private boolean destroyedOpponentShip(EffectMessage msg) {
return msg.getDestroyedShip() != null && msg.isOwnShot();
}
/**
* Plays a sound based on the outcome of the shot. Different sounds are played for a miss, hit,
* or destruction of a ship.
*
* @param msg the effect message containing the result of the shot
*/
private void playSound(EffectMessage msg) {
if (!msg.getShot().isHit())
logic.playSound(Sound.SPLASH);
else if (msg.getDestroyedShip() == null)
logic.playSound(Sound.EXPLOSION);
else
logic.playSound(Sound.DESTROYED_SHIP);
}
}

View File

@@ -1,38 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.game.singlemode.BattleshipClientConfig;
/**
* Interface representing a Battleship client.
* Provides methods to access game logic, configuration, and to enqueue tasks.
*/
public interface BattleshipClient {
/**
* Returns the game logic associated with this client.
*
* @return the ClientGameLogic instance
*/
ClientGameLogic getGameLogic();
/**
* Returns the configuration associated with this client.
*
* @return the BattleshipConfig instance
*/
BattleshipClientConfig getConfig();
/**
* Enqueues a task to be executed by the client.
*
* @param runnable the task to be executed
*/
void enqueue(Runnable runnable);
}

View File

@@ -1,355 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.message.client.ClientMessage;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.ServerInterpreter;
import pp.battleship.message.server.StartBattleMessage;
import pp.battleship.model.IntPoint;
import pp.battleship.model.ShipMap;
import pp.battleship.model.dto.ShipMapDTO;
import pp.battleship.notification.ClientStateEvent;
import pp.battleship.notification.GameEvent;
import pp.battleship.notification.GameEventBroker;
import pp.battleship.notification.GameEventListener;
import pp.battleship.notification.InfoTextEvent;
import pp.battleship.notification.Sound;
import pp.battleship.notification.SoundEvent;
import java.io.File;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.List;
import static java.lang.Math.max;
/**
* Controls the client-side game logic for Battleship.
* Manages the player's ship placement, interactions with the map, and response to server messages.
*/
public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
static final Logger LOGGER = System.getLogger(ClientGameLogic.class.getName());
private final ClientSender clientSender;
private final List<GameEventListener> listeners = new ArrayList<>();
private GameDetails details;
private ShipMap ownMap;
private ShipMap harbor;
private ShipMap opponentMap;
private ClientState state = new InitialState(this);
/**
* Constructs a ClientGameLogic with the specified sender object.
*
* @param clientSender the object used to send messages to the server
*/
public ClientGameLogic(ClientSender clientSender) {
this.clientSender = clientSender;
}
/**
* Returns the current state of the game logic.
*/
ClientState getState() {
return state;
}
/**
* Sets the current state of the game logic.
*
* @param newState the new state to be set
*/
void setState(ClientState newState) {
LOGGER.log(Level.DEBUG, "state transition {0} --> {1}", state.getName(), newState.getName()); //NON-NLS
state = newState;
notifyListeners(new ClientStateEvent());
state.entry();
}
/**
* Returns the game details.
*
* @return the game details
*/
GameDetails getDetails() {
return details;
}
/**
* Returns the player's own map.
*
* @return the player's own map
*/
public ShipMap getOwnMap() {
return ownMap;
}
/**
* Returns the opponent's map.
*
* @return the opponent's map
*/
public ShipMap getOpponentMap() {
return opponentMap;
}
/**
* Returns the harbor map.
*
* @return the harbor map
*/
public ShipMap getHarbor() {
return harbor;
}
/**
* Checks if the editor should be shown.
*
* @return true if the editor should be shown, false otherwise
*/
public boolean showEditor() {
return state.showEditor();
}
/**
* Checks if the battle state should be shown.
*
* @return true if the battle state should be shown, false otherwise
*/
public boolean showBattle() {
return state.showBattle();
}
/**
* Sets the game details provided by the server.
*
* @param details the game details including map size and ships
*/
@Override
public void received(GameDetails details) {
state.receivedGameDetails(details);
}
/**
* Moves the preview ship to the specified position.
*
* @param pos the new position for the preview ship
*/
public void movePreview(IntPoint pos) {
state.movePreview(pos);
}
/**
* Handles a click on the player's own map.
*
* @param pos the position where the click occurred
*/
public void clickOwnMap(IntPoint pos) {
state.clickOwnMap(pos);
}
/**
* Handles a click on the harbor map.
*
* @param pos the position where the click occurred
*/
public void clickHarbor(IntPoint pos) {
state.clickHarbor(pos);
}
/**
* Handles a click on the opponent's map.
*
* @param pos the position where the click occurred
*/
public void clickOpponentMap(IntPoint pos) {
state.clickOpponentMap(pos);
}
/**
* Rotates the preview ship.
*/
public void rotateShip() {
state.rotateShip();
}
/**
* Marks the player's map as finished.
*/
public void mapFinished() {
state.mapFinished();
}
/**
* Checks if the player's map is complete (i.e., all ships are placed).
*
* @return true if all ships are placed, false otherwise
*/
public boolean isMapComplete() {
return state.isMapComplete();
}
/**
* Checks if there is currently a preview ship.
*
* @return true if there is currently a preview ship, false otherwise
*/
public boolean movingShip() {
return state.movingShip();
}
/**
* Starts the battle based on the server message.
*
* @param msg the message indicating whose turn it is to shoot
*/
@Override
public void received(StartBattleMessage msg) {
state.receivedStartBattle(msg);
}
/**
* Reports the effect of a shot based on the server message.
*
* @param msg the message containing the effect of the shot
*/
@Override
public void received(EffectMessage msg) {
state.receivedEffect(msg);
}
/**
* Initializes the player's own map, opponent's map, and harbor based on the game details.
*
* @param details the game details including map size and ships
*/
void initializeMaps(GameDetails details) {
this.details = details;
final int numShips = details.getShipNums().values().stream().mapToInt(Integer::intValue).sum();
final int maxLength = details.getShipNums().keySet().stream().mapToInt(Integer::intValue).max().orElse(2);
ownMap = new ShipMap(details.getWidth(), details.getHeight(), this);
opponentMap = new ShipMap(details.getWidth(), details.getHeight(), this);
harbor = new ShipMap(max(maxLength, 2), max(numShips, details.getHeight()), this);
}
/**
* Sets the informational text to be displayed to the player.
*
* @param key the key for the info text
*/
void setInfoText(String key) {
notifyListeners(new InfoTextEvent(key));
}
/**
* Emits an event to play the specified sound.
*
* @param sound the sound to be played.
*/
public void playSound(Sound sound) {
notifyListeners(new SoundEvent(sound));
}
/**
* Loads a map from the specified file.
*
* @param file the file to load the map from
* @throws IOException if an I/O error occurs
*/
public void loadMap(File file) throws IOException {
state.loadMap(file);
}
/**
* Checks if the player's own map may be loaded from a file.
*
* @return true if the own map may be loaded from file, false otherwise
*/
public boolean mayLoadMap() {
return state.mayLoadMap();
}
/**
* Checks if the player's own map may be saved to a file.
*
* @return true if the own map may be saved to file, false otherwise
*/
public boolean maySaveMap() {
return state.maySaveMap();
}
/**
* Saves the player's own map to the specified file.
*
* @param file the file to save the map to
* @throws IOException if the map cannot be saved in the current state
*/
public void saveMap(File file) throws IOException {
if (ownMap != null && maySaveMap())
new ShipMapDTO(ownMap).saveTo(file);
else
throw new IOException("You are not allowed to save the map in this state of the game");
}
/**
* Sends a message to the server.
*
* @param msg the message to be sent
*/
void send(ClientMessage msg) {
if (clientSender == null)
LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS
else
clientSender.send(msg);
}
/**
* Adds a listener to receive game events.
*
* @param listener the listener to add
*/
public synchronized void addListener(GameEventListener listener) {
listeners.add(listener);
}
/**
* Removes a listener from receiving game events.
*
* @param listener the listener to remove
*/
public synchronized void removeListener(GameEventListener listener) {
listeners.remove(listener);
}
/**
* Notifies all listeners of a game event.
*
* @param event the game event to notify listeners of
*/
@Override
public void notifyListeners(GameEvent event) {
final List<GameEventListener> copy;
synchronized (this) {
copy = new ArrayList<>(listeners);
}
for (GameEventListener listener : copy)
event.notifyListener(listener);
}
/**
* Called once per frame by the update loop.
*
* @param delta time in seconds since the last update call
*/
public void update(float delta) {
state.update(delta);
}
}

View File

@@ -1,22 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.message.client.ClientMessage;
/**
* Interface for sending messages to the server.
*/
public interface ClientSender {
/**
* Send the specified message to the server.
*
* @param message the message
*/
void send(ClientMessage message);
}

View File

@@ -1,202 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.StartBattleMessage;
import pp.battleship.model.IntPoint;
import java.io.File;
import java.io.IOException;
import java.lang.System.Logger.Level;
/**
* Defines the behavior and state transitions for the client-side game logic.
* Different states of the game logic implement this interface to handle various game events and actions.
*/
abstract class ClientState {
/**
* The game logic object.
*/
final ClientGameLogic logic;
/**
* Constructs a client state of the specified game logic.
*
* @param logic the game logic
*/
ClientState(ClientGameLogic logic) {
this.logic = logic;
}
/**
* Method to be overridden by subclasses for post-transition initialization.
* By default, it does nothing, but it can be overridden in derived states.
*/
void entry() {
// Default implementation does nothing
}
/**
* Returns the name of the current state.
*
* @return the name of the current state
*/
String getName() {
return getClass().getSimpleName();
}
/**
* Checks if the editor should be shown.
*
* @return true if the editor should be shown, false otherwise
*/
boolean showEditor() {
return false;
}
/**
* Checks if the battle state should be shown.
*
* @return true if the battle state should be shown, false otherwise
*/
boolean showBattle() {
return false;
}
/**
* Checks if the player's map is complete (i.e., all ships are placed).
*
* @return true if all ships are placed, false otherwise
*/
boolean isMapComplete() {
return false;
}
/**
* Checks if there is currently a preview ship.
*
* @return true if there is currently a preview ship, false otherwise
*/
boolean movingShip() {
return false;
}
/**
* Handles a click on the player's own map.
*
* @param pos the position where the click occurred
*/
void clickOwnMap(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "clickOwnMap has no effect in {0}", getName()); //NON-NLS
}
/**
* Handles a click on the harbor map.
*
* @param pos the position where the click occurred
*/
void clickHarbor(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "clickHarbor has no effect in {0}", getName()); //NON-NLS
}
/**
* Handles a click on the opponent's map.
*
* @param pos the position where the click occurred
*/
void clickOpponentMap(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "clickOpponentMap has no effect in {0}", getName()); //NON-NLS
}
/**
* Moves the preview ship to the specified position.
*
* @param pos the new position for the preview ship
*/
void movePreview(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "movePreview has no effect in {0}", getName()); //NON-NLS
}
/**
* Rotates the preview ship.
*/
void rotateShip() {
ClientGameLogic.LOGGER.log(Level.DEBUG, "rotateShip has no effect in {0}", getName()); //NON-NLS
}
/**
* The user has marked the map as finished.
*/
void mapFinished() {
ClientGameLogic.LOGGER.log(Level.ERROR, "mapFinished not allowed in {0}", getName()); //NON-NLS
}
/**
* Sets the game details provided by the server.
*
* @param details the game details including map size and ships
*/
void receivedGameDetails(GameDetails details) {
ClientGameLogic.LOGGER.log(Level.ERROR, "receivedGameDetails not allowed in {0}", getName()); //NON-NLS
}
/**
* Starts the battle based on the server message.
*
* @param msg the message indicating whose turn it is to shoot
*/
void receivedStartBattle(StartBattleMessage msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "receivedStartBattle not allowed in {0}", getName()); //NON-NLS
}
/**
* Reports the effect of a shot based on the server message.
*
* @param msg the message containing the effect of the shot
*/
void receivedEffect(EffectMessage msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "receivedEffect not allowed in {0}", getName()); //NON-NLS
}
/**
* Loads a map from the specified file.
*
* @param file the file to load the map from
* @throws IOException if the map cannot be loaded in the current state
*/
void loadMap(File file) throws IOException {
throw new IOException("You are not allowed to load a map in this state of the game");
}
/**
* Checks if the own map may be loaded from file.
*
* @return true if the own map may be loaded from file, false otherwise
*/
boolean mayLoadMap() {
return false;
}
/**
* Checks if the own map may be saved to file.
*
* @return true if the own map may be saved to file, false otherwise
*/
boolean maySaveMap() {
return true;
}
/**
* Called once per frame by the update loop if this state is active.
*
* @param delta time in seconds since the last update call
*/
void update(float delta) { /* do nothing by default */ }
}

View File

@@ -1,267 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.message.client.MapMessage;
import pp.battleship.model.Battleship;
import pp.battleship.model.IntPoint;
import pp.battleship.model.ShipMap;
import pp.battleship.model.dto.ShipMapDTO;
import java.io.File;
import java.io.IOException;
import java.lang.System.Logger.Level;
import static pp.battleship.Resources.lookup;
import static pp.battleship.model.Battleship.Status.INVALID_PREVIEW;
import static pp.battleship.model.Battleship.Status.NORMAL;
import static pp.battleship.model.Battleship.Status.VALID_PREVIEW;
import static pp.battleship.model.Rotation.RIGHT;
/**
* Represents the state of the client setting up the ship map.
*/
class EditorState extends ClientState {
private Battleship preview;
private Battleship selectedInHarbor;
/**
* Constructs a new EditorState with the specified ClientGameLogic.
*
* @param logic the ClientGameLogic associated with this state
*/
public EditorState(ClientGameLogic logic) {
super(logic);
}
/**
* Returns true to indicate that the editor should be shown.
*
* @return true if the editor should be shown
*/
@Override
public boolean showEditor() {
return true;
}
/**
* Moves the preview ship to the specified position.
*
* @param pos the new position for the preview ship
*/
@Override
public void movePreview(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "move preview to {0}", pos); //NON-NLS
if (preview == null || !ownMap().isValid(pos)) return;
preview.moveTo(pos);
setPreviewStatus(preview);
ownMap().remove(preview);
ownMap().add(preview);
}
/**
* Handles a click on the player's own map.
*
* @param pos the position where the click occurred
*/
@Override
public void clickOwnMap(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "click at {0} in own map", pos); //NON-NLS
if (!ownMap().isValid(pos)) return;
if (preview == null)
modifyShip(pos);
else
placeShip(pos);
}
/**
* Modifies a ship on the map at the specified position.
*
* @param cursor the position of the ship to modify
*/
private void modifyShip(IntPoint cursor) {
preview = ownMap().findShipAt(cursor);
if (preview == null)
return;
preview.moveTo(cursor);
setPreviewStatus(preview);
ownMap().remove(preview);
ownMap().add(preview);
selectedInHarbor = new Battleship(preview.getLength(), 0, freeY(), RIGHT);
selectedInHarbor.setStatus(VALID_PREVIEW);
harbor().add(selectedInHarbor);
}
/**
* Places the preview ship at the specified position.
*
* @param cursor the position to place the ship
*/
private void placeShip(IntPoint cursor) {
ownMap().remove(preview);
preview.moveTo(cursor);
if (ownMap().isValid(preview)) {
preview.setStatus(NORMAL);
ownMap().add(preview);
harbor().remove(selectedInHarbor);
preview = null;
selectedInHarbor = null;
}
else {
preview.setStatus(INVALID_PREVIEW);
ownMap().add(preview);
}
}
/**
* Handles a click on the harbor map.
*
* @param pos the position where the click occurred
*/
@Override
public void clickHarbor(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "click at {0} in harbor", pos); //NON-NLS
if (!harbor().isValid(pos)) return;
final Battleship shipAtCursor = harbor().findShipAt(pos);
if (preview != null) {
ownMap().remove(preview);
selectedInHarbor.setStatus(NORMAL);
harbor().remove(selectedInHarbor);
harbor().add(selectedInHarbor);
preview = null;
selectedInHarbor = null;
}
else if (shipAtCursor != null) {
selectedInHarbor = shipAtCursor;
selectedInHarbor.setStatus(VALID_PREVIEW);
harbor().remove(selectedInHarbor);
harbor().add(selectedInHarbor);
preview = new Battleship(selectedInHarbor.getLength(), 0, 0, RIGHT);
setPreviewStatus(preview);
ownMap().add(preview);
}
}
/**
* Rotates the preview ship.
*/
@Override
public void rotateShip() {
ClientGameLogic.LOGGER.log(Level.DEBUG, "pushed rotate"); //NON-NLS
if (preview == null) return;
preview.rotated();
ownMap().remove(preview);
ownMap().add(preview);
}
/**
* Finds a free position in the harbor to place a ship.
*
* @return the y coordinate of a free position in the harbor
*/
private int freeY() {
for (int i = 0; i < harbor().getHeight(); i++)
if (harbor().findShipAt(0, i) == null)
return i;
throw new RuntimeException("Cannot find a free slot in harbor");
}
/**
* Updates the status of the specified ship based on its validity.
*/
private void setPreviewStatus(Battleship ship) {
ship.setStatus(ownMap().isValid(ship) ? VALID_PREVIEW : INVALID_PREVIEW);
}
/**
* The user has marked the map as finished.
*/
@Override
public void mapFinished() {
if (!harbor().getItems().isEmpty()) return;
logic.send(new MapMessage(ownMap().getRemainingShips()));
logic.setInfoText("wait.for.opponent");
logic.setState(new WaitState(logic));
}
/**
* Checks if the player's map is complete (i.e., all ships are placed).
*
* @return true if all ships are placed, false otherwise
*/
@Override
public boolean isMapComplete() {
return harbor().getItems().isEmpty();
}
/**
* Checks if there is currently a preview ship.
*
* @return true if there is currently a preview ship, false otherwise
*/
@Override
public boolean movingShip() {
return preview != null;
}
/**
* Returns the player's own map.
*
* @return the player's own map
*/
private ShipMap ownMap() {
return logic.getOwnMap();
}
/**
* Returns the harbor map.
*
* @return the harbor map
*/
private ShipMap harbor() {
return logic.getHarbor();
}
/**
* Loads a map from the specified file.
*
* @param file the file to load the map from
* @throws IOException if the map cannot be loaded
*/
@Override
public void loadMap(File file) throws IOException {
final ShipMapDTO dto = ShipMapDTO.loadFrom(file);
if (!dto.fits(logic.getDetails()))
throw new IOException(lookup("map.doesnt.fit"));
ownMap().clear();
dto.getShips().forEach(ownMap()::add);
harbor().clear();
preview = null;
selectedInHarbor = null;
}
/**
* Checks if the player's own map may be loaded from a file.
*
* @return true if the own map may be loaded from file, false otherwise
*/
@Override
public boolean mayLoadMap() {
return true;
}
/**
* Checks if the player's own map may be saved to a file.
*
* @return true if the own map may be saved to file, false otherwise
*/
@Override
public boolean maySaveMap() {
return harbor().getItems().isEmpty();
}
}

View File

@@ -1,32 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
/**
* Represents the state of the client when the game is over.
*/
class GameOverState extends ClientState {
/**
* Constructs a new instance of GameOverState.
*
* @param logic the client game logic
*/
GameOverState(ClientGameLogic logic) {
super(logic);
}
/**
* Returns true to indicate that the battle state should be shown.
*
* @return true if the battle state should be shown
*/
@Override
public boolean showBattle() {
return true;
}
}

View File

@@ -1,65 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.message.server.GameDetails;
import pp.battleship.model.Battleship;
import pp.battleship.model.Rotation;
import java.util.Map.Entry;
/**
* Represents the state of the client waiting for the
* {@linkplain pp.battleship.message.server.GameDetails}
* from the server.
*/
class InitialState extends ClientState {
/**
* Creates a new initial state.
*
* @param logic the game logic
*/
public InitialState(ClientGameLogic logic) {
super(logic);
}
/**
* Sets the game details provided by the server.
*
* @param details the game details including map size and ships
*/
@Override
public void receivedGameDetails(GameDetails details) {
logic.initializeMaps(details);
fillHarbor(details);
logic.setInfoText(details.getInfoTextKey());
logic.setState(new EditorState(logic));
}
/**
* Fills the harbor with ships as specified by the game details.
*
* @param details the game details including map size and ships
*/
private void fillHarbor(GameDetails details) {
int y = 0;
for (Entry<Integer, Integer> entry : details.getShipNums().entrySet()) {
final int len = entry.getKey();
final int num = entry.getValue();
for (int i = 0; i < num; i++) {
final Battleship ship = new Battleship(len, 0, y++, Rotation.RIGHT);
logic.getHarbor().add(ship);
}
}
}
@Override
public boolean maySaveMap() {
return false;
}
}

View File

@@ -1,32 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
/**
* Interface representing a connection to the server.
* Extends ClientSender to allow sending messages to the server.
*/
public interface ServerConnection extends ClientSender {
/**
* Checks if the client is currently connected to the server.
*
* @return true if connected, false otherwise.
*/
boolean isConnected();
/**
* Establishes a connection to the server.
*/
void connect();
/**
* Disconnects from the server.
*/
void disconnect();
}

View File

@@ -1,41 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.client;
import pp.battleship.message.server.StartBattleMessage;
import java.lang.System.Logger.Level;
class WaitState extends ClientState {
/**
* Creates a new instance of {@link WaitState}.
*
* @param logic the game logic
*/
public WaitState(ClientGameLogic logic) {
super(logic);
}
@Override
public boolean showEditor() {
return true;
}
/**
* Starts the battle based on the server message.
*
* @param msg the message indicating whose turn it is to shoot
*/
@Override
public void receivedStartBattle(StartBattleMessage msg) {
ClientGameLogic.LOGGER.log(Level.INFO, "start battle, {0} turn", msg.isMyTurn() ? "my" : "other's"); //NON-NLS
logic.setInfoText(msg.getInfoTextKey());
logic.setState(new BattleState(logic, msg.isMyTurn()));
}
}

View File

@@ -1,54 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.server;
import pp.battleship.BattleshipConfig;
import pp.battleship.model.ShipMap;
/**
* Class representing a player
*/
public class Player {
private final ShipMap map;
private final String name;
private final int id;
/**
* Creates new Player
*
* @param id the id of the connection to the client represented by this player
* @param name the human-readable name of this player
* @param config model holding the player
*/
Player(int id, String name, BattleshipConfig config) {
this.id = id;
this.name = name;
map = new ShipMap(config.getMapWidth(), config.getMapHeight(), null);
}
/**
* Returns the id of the connection to the client represented by this player.
*
* @return the id
*/
public int getId() {
return id;
}
@Override
public String toString() {
return String.format("Player(%s,%s)", name, id); //NON-NLS
}
/**
* @return map containing own ships and shots
*/
public ShipMap getMap() {
return map;
}
}

View File

@@ -1,220 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.server;
import pp.battleship.BattleshipConfig;
import pp.battleship.message.client.ClientInterpreter;
import pp.battleship.message.client.MapMessage;
import pp.battleship.message.client.ShootMessage;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.ServerMessage;
import pp.battleship.message.server.StartBattleMessage;
import pp.battleship.model.Battleship;
import pp.battleship.model.IntPoint;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Controls the server-side game logic for Battleship.
* Manages game states, player interactions, and message handling.
*/
public class ServerGameLogic implements ClientInterpreter {
private static final Logger LOGGER = System.getLogger(ServerGameLogic.class.getName());
private final BattleshipConfig config;
private final List<Player> players = new ArrayList<>(2);
private final Set<Player> readyPlayers = new HashSet<>();
private final ServerSender serverSender;
private Player activePlayer;
private ServerState state = ServerState.WAIT;
/**
* Constructs a ServerGameLogic with the specified sender and configuration.
*
* @param serverSender the sender used to send messages to clients
* @param config the game configuration
*/
public ServerGameLogic(ServerSender serverSender, BattleshipConfig config) {
this.serverSender = serverSender;
this.config = config;
}
/**
* Returns the state of the game.
*/
ServerState getState() {
return state;
}
/**
* Sets the new state of the game and logs the state transition.
*
* @param newState the new state to set
*/
void setState(ServerState newState) {
LOGGER.log(Level.DEBUG, "state transition {0} --> {1}", state, newState); //NON-NLS
state = newState;
}
/**
* Returns the opponent of the specified player.
*
* @param p the player
* @return the opponent of the player
*/
Player getOpponent(Player p) {
if (players.size() != 2)
throw new RuntimeException("trying to find opponent without having 2 players");
final int index = players.indexOf(p);
if (index < 0)
throw new RuntimeException("Nonexistent player " + p);
return players.get(1 - index);
}
/**
* Returns the player representing the client with the specified connection ID.
*
* @param id the ID of the client
* @return the player associated with the client ID, or null if not found
*/
public Player getPlayerById(int id) {
for (Player player : players)
if (player.getId() == id)
return player;
LOGGER.log(Level.ERROR, "no player found with connection {0}", id); //NON-NLS
return null;
}
/**
* Sends a message to the specified player.
*
* @param player the player to send the message to
* @param msg the message to send
*/
void send(Player player, ServerMessage msg) {
LOGGER.log(Level.INFO, "sending to {0}: {1}", player, msg); //NON-NLS
serverSender.send(player.getId(), msg);
}
/**
* Adds a new player to the game if there are less than two players.
* Transitions the state to SET_UP if two players are present.
*
* @param id the connection ID of the new player
* @return the player added to the game, or null if the game is not in the right state
*/
public Player addPlayer(int id) {
if (state != ServerState.WAIT) {
LOGGER.log(Level.ERROR, "addPlayer not allowed in {0}", state); //NON-NLS
return null;
}
final int n = players.size() + 1;
final Player player = new Player(id, "player " + n, config); //NON-NLS
LOGGER.log(Level.INFO, "adding {0}", player); //NON-NLS
players.add(player);
if (players.size() == 2) {
activePlayer = players.get(0);
for (Player p : players)
send(p, new GameDetails(config));
setState(ServerState.SET_UP);
}
return player;
}
/**
* Handles the reception of a MapMessage.
*
* @param msg the received MapMessage
* @param from the ID of the sender client
*/
@Override
public void received(MapMessage msg, int from) {
if (state != ServerState.SET_UP)
LOGGER.log(Level.ERROR, "playerReady not allowed in {0}", state); //NON-NLS
else
playerReady(getPlayerById(from), msg.getShips());
}
/**
* Handles the reception of a ShootMessage.
*
* @param msg the received ShootMessage
* @param from the ID of the sender client
*/
@Override
public void received(ShootMessage msg, int from) {
if (state != ServerState.BATTLE)
LOGGER.log(Level.ERROR, "shoot not allowed in {0}", state); //NON-NLS
else
shoot(getPlayerById(from), msg.getPosition());
}
/**
* Marks the player as ready and sets their ships.
* Transitions the state to PLAY if both players are ready.
*
* @param player the player who is ready
* @param ships the list of ships placed by the player
*/
void playerReady(Player player, List<Battleship> ships) {
if (!readyPlayers.add(player)) {
LOGGER.log(Level.ERROR, "{0} was already ready", player); //NON-NLS
return;
}
ships.forEach(player.getMap()::add);
if (readyPlayers.size() == 2) {
for (Player p : players)
send(p, new StartBattleMessage(p == activePlayer));
setState(ServerState.BATTLE);
}
}
/**
* Handles the shooting action by the player.
*
* @param p the player who shot
* @param pos the position of the shot
*/
void shoot(Player p, IntPoint pos) {
if (p != activePlayer) return;
final Player otherPlayer = getOpponent(activePlayer);
final Battleship selectedShip = otherPlayer.getMap().findShipAt(pos);
if (selectedShip == null) {
// shot missed
send(activePlayer, EffectMessage.miss(true, pos));
send(otherPlayer, EffectMessage.miss(false, pos));
activePlayer = otherPlayer;
}
else {
// shot hit a ship
selectedShip.hit(pos);
if (otherPlayer.getMap().getRemainingShips().isEmpty()) {
// game is over
send(activePlayer, EffectMessage.won(pos, selectedShip));
send(otherPlayer, EffectMessage.lost(pos, selectedShip, activePlayer.getMap().getRemainingShips()));
setState(ServerState.GAME_OVER);
}
else if (selectedShip.isDestroyed()) {
// ship has been destroyed, but game is not yet over
send(activePlayer, EffectMessage.shipDestroyed(true, pos, selectedShip));
send(otherPlayer, EffectMessage.shipDestroyed(false, pos, selectedShip));
}
else {
// ship has been hit, but it hasn't been destroyed
send(activePlayer, EffectMessage.hit(true, pos));
send(otherPlayer, EffectMessage.hit(false, pos));
}
}
}
}

View File

@@ -1,23 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.server;
import pp.battleship.message.server.ServerMessage;
/**
* Interface for sending messages to a client.
*/
public interface ServerSender {
/**
* Send the specified message to the client.
*
* @param id the id of the client that shall receive the message
* @param message the message
*/
void send(int id, ServerMessage message);
}

View File

@@ -1,33 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.server;
/**
* Represents the different states of the Battleship server during the game lifecycle.
*/
enum ServerState {
/**
* The server is waiting for clients to connect.
*/
WAIT,
/**
* The server is waiting for clients to set up their maps.
*/
SET_UP,
/**
* The battle of the game where players take turns to attack each other's ships.
*/
BATTLE,
/**
* The game has ended because all the ships of one player have been destroyed.
*/
GAME_OVER
}

View File

@@ -1,114 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.singlemode;
import pp.battleship.BattleshipConfig;
import pp.battleship.model.IntPoint;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Class providing access to the Battleship client configuration.
* Extends {@link BattleshipConfig} to include additional properties specific to the client.
* This class manages configuration settings related to the RobotClient's behavior
* and the game maps used in single mode.
* <p>
* <b>Note:</b> Attributes of this class should not be marked as {@code final}
* to ensure proper functionality when reading from a properties file.
* </p>
*/
public class BattleshipClientConfig extends BattleshipConfig {
/**
* Array representing the predefined shooting locations for the RobotClient.
* The array stores coordinates in pairs, where even indices represent x-coordinates
* and odd indices represent y-coordinates.
*/
@Property("robot.targets")
private int[] robotTargets = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
/**
* The delay (in milliseconds) between shots fired by the RobotClient.
*/
@Property("robot.delay")
private int delay = 750;
/**
* Path to the file representing the opponent's map.
*/
@Property("map.opponent")
private String opponentMap;
/**
* Path to the file representing the player's own map.
*/
@Property("map.own")
private String ownMap;
/**
* Creates a default {@code BattleshipClientConfig} with predefined values.
*/
public BattleshipClientConfig() {
// Default constructor
}
/**
* Returns an iterator of {@link IntPoint} objects representing the predefined
* shooting locations for the RobotClient.
*
* @return an iterator of {@code IntPoint} representing the shooting locations.
*/
public Iterator<IntPoint> getRobotTargets() {
List<IntPoint> targets = new ArrayList<>();
for (int i = 0; i < robotTargets.length; i += 2) {
int x = robotTargets[i];
int y = robotTargets[i + 1];
targets.add(new IntPoint(x, y));
}
return targets.iterator();
}
/**
* Returns the delay (in milliseconds) between shots by the RobotClient.
*
* @return the delay in milliseconds.
*/
public int getDelay() {
return delay;
}
/**
* Returns the file representing the opponent's map.
*
* @return the opponent's map file, or {@code null} if not set.
*/
public File getOpponentMap() {
return opponentMap == null ? null : new File(opponentMap);
}
/**
* Returns the file representing the player's own map.
*
* @return the player's own map file, or {@code null} if not set.
*/
public File getOwnMap() {
return ownMap == null ? null : new File(ownMap);
}
/**
* Determines if the game is in single mode based on the presence of an opponent map.
*
* @return {@code true} if the opponent map is set, indicating single mode; {@code false} otherwise.
*/
public boolean isSingleMode() {
return opponentMap != null;
}
}

View File

@@ -1,75 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.singlemode;
import pp.battleship.message.client.ClientInterpreter;
import pp.battleship.message.client.ClientMessage;
import pp.battleship.message.client.MapMessage;
import pp.battleship.message.client.ShootMessage;
import pp.battleship.model.Battleship;
/**
* The {@code Copycat} class is a utility that creates a copy of a {@link ClientMessage}.
* It implements the {@link ClientInterpreter} interface to interpret and process
* different types of messages.
*/
class Copycat implements ClientInterpreter {
private ClientMessage copiedMessage;
/**
* Creates a copy of the provided {@link ClientMessage}.
*
* @param msg the message to be copied
* @return a copy of the provided message
*/
static ClientMessage copy(ClientMessage msg) {
final Copycat copycat = new Copycat();
msg.accept(copycat, 0);
return copycat.copiedMessage;
}
/**
* Private constructor to prevent direct instantiation of {@code Copycat}.
*/
private Copycat() { /* do nothing */ }
/**
* Handles the reception of a {@link ShootMessage}.
* Since a {@code ShootMessage} does not need to be copied, it is directly assigned.
*
* @param msg the received {@code ShootMessage}
* @param from the identifier of the sender
*/
@Override
public void received(ShootMessage msg, int from) {
// copying is not necessary
copiedMessage = msg;
}
/**
* Handles the reception of a {@link MapMessage}.
* Creates a deep copy of the {@code MapMessage} by copying each {@link Battleship} in the message.
*
* @param msg the received {@code MapMessage}
* @param from the identifier of the sender
*/
@Override
public void received(MapMessage msg, int from) {
copiedMessage = new MapMessage(msg.getShips().stream().map(Copycat::copy).toList());
}
/**
* Creates a copy of the provided {@link Battleship}.
*
* @param ship the battleship to be copied
* @return a copy of the provided battleship
*/
private static Battleship copy(Battleship ship) {
return new Battleship(ship.getLength(), ship.getX(), ship.getY(), ship.getRot());
}
}

View File

@@ -1,93 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.singlemode;
import pp.battleship.game.client.BattleshipClient;
import pp.battleship.game.client.ClientGameLogic;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.ServerInterpreter;
import pp.battleship.message.server.ServerMessage;
import pp.battleship.message.server.StartBattleMessage;
import java.io.IOException;
/**
* A proxy class that interprets messages from the server and forwards them to the BattleshipClient.
* Implements the ServerInterpreter interface to handle specific server messages.
*/
class InterpreterProxy implements ServerInterpreter {
private final BattleshipClient playerClient;
/**
* Constructs an InterpreterProxy with the specified BattleshipClient.
*
* @param playerClient the client to which the server messages are forwarded
*/
InterpreterProxy(BattleshipClient playerClient) {
this.playerClient = playerClient;
}
/**
* Handles the received GameDetails message by accepting it with the client's game logic.
* If the client's own map option is set, it also loads the map.
*
* @param msg the GameDetails message received from the server
*/
@Override
public void received(GameDetails msg) {
msg.accept(playerClient.getGameLogic());
if (playerClient.getConfig().getOwnMap() != null)
playerClient.enqueue(this::loadMap);
}
/**
* Loads the map specified in the client's options and notifies the game logic that the map is finished.
*
* @throws RuntimeException if the map fails to load.
*/
private void loadMap() {
final ClientGameLogic clientGameLogic = playerClient.getGameLogic();
try {
clientGameLogic.loadMap(playerClient.getConfig().getOwnMap());
}
catch (IOException e) {
throw new RuntimeException("Failed to load PlayerClient map", e);
}
clientGameLogic.mapFinished();
}
/**
* Forwards the received StartBattleMessage to the client's game logic.
*
* @param msg the StartBattleMessage received from the server
*/
@Override
public void received(StartBattleMessage msg) {
forward(msg);
}
/**
* Forwards the received EffectMessage to the client's game logic.
*
* @param msg the EffectMessage received from the server
*/
@Override
public void received(EffectMessage msg) {
forward(msg);
}
/**
* Forwards the specified ServerMessage to the client's game logic by enqueuing the message acceptance.
*
* @param msg the ServerMessage to forward
*/
private void forward(ServerMessage msg) {
playerClient.enqueue(() -> msg.accept(playerClient.getGameLogic()));
}
}

View File

@@ -1,127 +0,0 @@
package pp.battleship.game.singlemode;
import pp.battleship.game.client.BattleshipClient;
import pp.battleship.message.client.MapMessage;
import pp.battleship.message.client.ShootMessage;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.ServerInterpreter;
import pp.battleship.message.server.StartBattleMessage;
import pp.battleship.model.IntPoint;
import pp.battleship.model.dto.ShipMapDTO;
import pp.util.RandomPositionIterator;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import static pp.battleship.Resources.lookup;
/**
* RobotClient simulates a client in the Battleship game.
* It handles its own shooting targets and acts as a sender of client messages.
* The RobotClient can shoot at predefined targets or generate random targets if predefined ones are exhausted.
*/
class RobotClient implements ServerInterpreter {
private static final Logger LOGGER = System.getLogger(RobotClient.class.getName());
private final BattleshipClient app;
private final ServerConnectionMockup connection;
private final BattleshipClientConfig config;
private final ShipMapDTO dto;
private final Iterator<IntPoint> targetIterator;
private final Iterator<IntPoint> randomPositionIterator;
private final Set<IntPoint> shotTargets = new HashSet<>();
private final Timer timer = new Timer(true);
/**
* Constructs a RobotClient instance with the given connection and configuration.
* Initializes the shooting targets from the configuration.
*
* @param app The BattleshipApp instance, used to enqueue actions on the main thread
* @param connection The ServerConnectionMockup instance
* @param config The BattleshipClientConfig instance
* @param dto The ShipMap dto specified at app start
*/
RobotClient(BattleshipClient app, ServerConnectionMockup connection, BattleshipClientConfig config, ShipMapDTO dto) {
this.app = app;
this.connection = connection;
this.config = config;
this.dto = dto;
this.targetIterator = config.getRobotTargets();
this.randomPositionIterator = new RandomPositionIterator<>(IntPoint::new, config.getMapWidth(), config.getMapHeight());
}
/**
* Schedules the RobotClient to take a shot after the specified delay.
*/
private void shoot() {
timer.schedule(new TimerTask() {
@Override
public void run() {
app.enqueue(RobotClient.this::robotShot);
}
}, config.getDelay());
}
/**
* Makes the RobotClient take a shot by sending a ShootMessage with the target position.
*/
private void robotShot() {
connection.sendRobotMessage(new ShootMessage(getShotPosition()));
}
/**
* Determines the next shot position. If predefined targets are available, uses the next target.
* Otherwise, generates a random target that has not been shot at before.
*
* @return the next shot position as IntPosition
*/
private IntPoint getShotPosition() {
while (true) {
final IntPoint target = targetIterator.hasNext() ? targetIterator.next() : randomPositionIterator.next();
if (shotTargets.add(target)) return target;
}
}
/**
* Receives GameDetails, creates and sends the ShipMap to the mock server.
*
* @param details The game details
*/
@Override
public void received(GameDetails details) {
if (!dto.fits(details))
throw new RuntimeException(lookup("map.doesnt.fit"));
app.enqueue(() -> connection.sendRobotMessage(new MapMessage(dto.getShips())));
}
/**
* Receives the StartBattleMessage and updates the turn status.
* If it is RobotClient's turn to shoot, schedules a shot using shoot();
*
* @param msg The start battle message
*/
@Override
public void received(StartBattleMessage msg) {
LOGGER.log(Level.INFO, "Received StartBattleMessage: {0}", msg); //NON-NLS
if (msg.isMyTurn())
shoot();
}
/**
* Receives an effect message, logs it, and updates the turn status.
* If it is RobotClient's turn to shoot, schedules a shot using shoot();
*
* @param msg The effect message
*/
@Override
public void received(EffectMessage msg) {
LOGGER.log(Level.INFO, "Received EffectMessage: {0}", msg); //NON-NLS
if (msg.isMyTurn())
shoot();
}
}

View File

@@ -1,145 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.game.singlemode;
import pp.battleship.game.client.BattleshipClient;
import pp.battleship.game.client.ServerConnection;
import pp.battleship.game.server.ServerGameLogic;
import pp.battleship.game.server.ServerSender;
import pp.battleship.message.client.ClientMessage;
import pp.battleship.message.server.ServerInterpreter;
import pp.battleship.message.server.ServerMessage;
import pp.battleship.model.dto.ShipMapDTO;
import java.io.IOException;
import static pp.battleship.game.singlemode.Copycat.copy;
/**
* A mock implementation of the ServerConnection interface for single mode.
* Simulates a server connection without actual network communication.
* Handles a mock player named RobotClient and schedules its shots when due.
*/
public class ServerConnectionMockup implements ServerConnection, ServerSender {
/**
* The id of the player client.
*/
private static final int PLAYER_CLIENT = 1;
/**
* The id of the robot client.
*/
private static final int ROBOT_CLIENT = 2;
private final BattleshipClient playerClient;
private final RobotClient robotClient;
private final InterpreterProxy playerProxy;
private final ServerGameLogic serverGameLogic;
/**
* Constructs a ServerConnectionMockup instance for the given Battleship application.
* Creates a RobotClient instance and an instance of ServerGameLogic.
*
* @param playerClient The Battleship client instance, e.g., a BattleshipApp instance.
*/
public ServerConnectionMockup(BattleshipClient playerClient) {
this.playerClient = playerClient;
robotClient = new RobotClient(playerClient, this, playerClient.getConfig(), getShipMapDTO());
serverGameLogic = new ServerGameLogic(this, playerClient.getConfig());
playerProxy = new InterpreterProxy(playerClient);
}
/**
* Always returns true as this is a mock connection.
*
* @return true, indicating the mock connection is always considered connected.
*/
@Override
public boolean isConnected() {
return true;
}
/**
* Simulates connecting to a server by adding the PlayerClient and the RobotClient to the serverGameLogic.
* Loads the map of the PlayerClient and triggers sending it to the serverGameLogic.
*/
@Override
public void connect() {
serverGameLogic.addPlayer(PLAYER_CLIENT);
serverGameLogic.addPlayer(ROBOT_CLIENT);
}
/**
* Does nothing upon shutdown of the app.
*/
@Override
public void disconnect() {
//do nothing
}
/**
* Forwards the specified message received from the player client to the server logic.
*
* @param message The message from the player client to be processed.
*/
@Override
public void send(ClientMessage message) { // from PlayerClient, as this is the PlayerClients 'serverConnection'
copy(message).accept(serverGameLogic, PLAYER_CLIENT);
}
/**
* Forwards the specified message received from the robot client to the server logic.
*
* @param message The message from the robot client to be processed.
*/
void sendRobotMessage(ClientMessage message) {
message.accept(serverGameLogic, ROBOT_CLIENT);
}
/**
* Forwards the specified message received from the server logic either to the player client or to the
* robot client, depending on the specified id.
*
* @param id The recipient id
* @param message The server message to be processed
* @see #PLAYER_CLIENT
* @see #ROBOT_CLIENT
*/
@Override
public void send(int id, ServerMessage message) {
message.accept(getInterpreter(id));
}
/**
* Retrieves the ServerInterpreter of the client with the specified id.
*
* @param clientId the id of the client whose ServerInterpreter shall be retrieved.
* @return the ServerInterpreter of the client
* @throws java.lang.IllegalArgumentException if there is no client with the specified id.
*/
private ServerInterpreter getInterpreter(int clientId) {
return switch (clientId) {
case PLAYER_CLIENT -> playerProxy;
case ROBOT_CLIENT -> robotClient;
default -> throw new IllegalArgumentException("Unexpected value: " + clientId);
};
}
/**
* Loads the ShipMapDTO from the opponent map file.
*
* @return the loaded ShipMapDTO.
*/
private ShipMapDTO getShipMapDTO() {
try {
return ShipMapDTO.loadFrom(playerClient.getConfig().getOpponentMap());
}
catch (IOException e) {
throw new RuntimeException("Failed to load RobotClient map", e);
}
}
}

View File

@@ -1,29 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.client;
/**
* Visitor interface for processing all client messages.
*/
public interface ClientInterpreter {
/**
* Processes a received ShootMessage.
*
* @param msg the ShootMessage to be processed
* @param from the connection ID from which the message was received
*/
void received(ShootMessage msg, int from);
/**
* Processes a received MapMessage.
*
* @param msg the MapMessage to be processed
* @param from the connection ID from which the message was received
*/
void received(MapMessage msg, int from);
}

View File

@@ -1,66 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.client;
import com.jme3.network.serializing.Serializable;
import pp.battleship.model.Battleship;
import java.util.ArrayList;
import java.util.List;
/**
* A message sent by the client containing the positions of the ships on the player's map.
*/
@Serializable
public class MapMessage extends ClientMessage {
private List<Battleship> ships;
/**
* Default constructor for serialization purposes.
*/
private MapMessage() { /* empty */ }
/**
* Constructs a MapMessage with the specified list of ships.
*
* @param ships the list of ships placed on the player's map
*/
public MapMessage(List<Battleship> ships) {
this.ships = new ArrayList<>(ships);
}
/**
* Returns the list of ships on the player's map.
*
* @return the list of ships
*/
public List<Battleship> getShips() {
return ships;
}
/**
* Returns a string representation of the MapMessage.
*
* @return a string representation of the MapMessage
*/
@Override
public String toString() {
return "MapMessage{ships=" + ships + '}'; //NON-NLS
}
/**
* Accepts a visitor to process this message.
*
* @param interpreter the visitor to process this message
* @param from the connection ID from which the message was received
*/
@Override
public void accept(ClientInterpreter interpreter, int from) {
interpreter.received(this, from);
}
}

View File

@@ -1,63 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.client;
import com.jme3.network.serializing.Serializable;
import pp.battleship.model.IntPoint;
/**
* A message sent by the client to indicate a shooting action in the game.
*/
@Serializable
public class ShootMessage extends ClientMessage {
private IntPoint position;
/**
* Default constructor for serialization purposes.
*/
private ShootMessage() { /* empty */ }
/**
* Constructs a ShootMessage with the specified position.
*
* @param position the position where the shot is fired
*/
public ShootMessage(IntPoint position) {
this.position = position;
}
/**
* Returns the position of the shot.
*
* @return the position of the shot
*/
public IntPoint getPosition() {
return position;
}
/**
* Returns a string representation of the ShootMessage.
*
* @return a string representation of the ShootMessage
*/
@Override
public String toString() {
return "ShootMessage{position=" + position + '}'; //NON-NLS
}
/**
* Accepts a visitor to process this message.
*
* @param interpreter the visitor to process this message
* @param from the connection ID from which the message was received
*/
@Override
public void accept(ClientInterpreter interpreter, int from) {
interpreter.received(this, from);
}
}

View File

@@ -1,211 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.server;
import com.jme3.network.serializing.Serializable;
import pp.battleship.model.Battleship;
import pp.battleship.model.IntPoint;
import pp.battleship.model.Shot;
import java.util.Collections;
import java.util.List;
import static pp.util.Util.copy;
/**
* A message sent by the server to inform clients about the effects of a shot in the Battleship game.
*/
@Serializable
public class EffectMessage extends ServerMessage {
private boolean ownShot;
private Shot shot;
private Battleship destroyedShip;
private List<Battleship> remainingOpponentShips;
/**
* Creates an EffectMessage indicating a hit.
*
* @param ownShot true if the shot was fired by the player, false if by the opponent
* @param pos the position of the shot
* @return an EffectMessage indicating a hit
*/
public static EffectMessage hit(boolean ownShot, IntPoint pos) {
return new EffectMessage(ownShot, new Shot(pos, true), null, null);
}
/**
* Creates an EffectMessage indicating a miss.
*
* @param ownShot true if the shot was fired by the player, false if by the opponent
* @param pos the position of the shot
* @return an EffectMessage indicating a miss
*/
public static EffectMessage miss(boolean ownShot, IntPoint pos) {
return new EffectMessage(ownShot, new Shot(pos, false), null, null);
}
/**
* Creates an EffectMessage indicating a ship was destroyed.
*
* @param ownShot true if the shot was fired by the player, false if by the opponent
* @param pos the position of the shot
* @param destroyedShip the ship that was destroyed
* @return an EffectMessage indicating a ship was destroyed
*/
public static EffectMessage shipDestroyed(boolean ownShot, IntPoint pos, Battleship destroyedShip) {
return new EffectMessage(ownShot, new Shot(pos, true), destroyedShip, null);
}
/**
* Creates an EffectMessage indicating the player has won the game.
*
* @param pos the position of the shot
* @param destroyedShip the ship that was destroyed
* @return an EffectMessage indicating the player has won
*/
public static EffectMessage won(IntPoint pos, Battleship destroyedShip) {
return new EffectMessage(true, new Shot(pos, true), destroyedShip, Collections.emptyList());
}
/**
* Creates an EffectMessage indicating the player has lost the game.
*
* @param pos the position of the shot
* @param destroyedShip the ship that was destroyed
* @param remainingOpponentShips the list of opponent's remaining ships
* @return an EffectMessage indicating the player has lost
*/
public static EffectMessage lost(IntPoint pos, Battleship destroyedShip, List<Battleship> remainingOpponentShips) {
return new EffectMessage(false, new Shot(pos, true), destroyedShip, remainingOpponentShips);
}
/**
* Default constructor for serialization purposes.
*/
private EffectMessage() { /* empty */ }
/**
* Constructs an EffectMessage with the specified parameters.
*
* @param ownShot true if the shot was fired by the player, false if by the opponent
* @param shot the shot fired
* @param destroyedShip the ship that was destroyed by the shot, null if no ship was destroyed
* @param remainingOpponentShips the list of opponent's remaining ships after the shot
*/
private EffectMessage(boolean ownShot, Shot shot, Battleship destroyedShip, List<Battleship> remainingOpponentShips) {
this.ownShot = ownShot;
this.shot = shot;
this.destroyedShip = destroyedShip;
this.remainingOpponentShips = copy(remainingOpponentShips);
}
/**
* Accepts a visitor to process this message.
*
* @param interpreter the visitor to process this message
*/
@Override
public void accept(ServerInterpreter interpreter) {
interpreter.received(this);
}
/**
* Checks if the shot was fired by the player.
*
* @return true if the shot was fired by the player, false otherwise
*/
public boolean isOwnShot() {
return ownShot;
}
/**
* Returns the shot fired.
*
* @return the shot fired
*/
public Shot getShot() {
return shot;
}
/**
* Returns the ship that was destroyed by the shot.
*
* @return the destroyed ship, null if no ship was destroyed
*/
public Battleship getDestroyedShip() {
return destroyedShip;
}
/**
* Returns the list of opponent's remaining ships after the shot.
*
* @return the list of opponent's remaining ships, null if the game is not yet over
*/
public List<Battleship> getRemainingOpponentShips() {
return remainingOpponentShips;
}
/**
* Checks if the game is over.
*
* @return true if the game is over, false otherwise
*/
public boolean isGameOver() {
return remainingOpponentShips != null;
}
/**
* Checks if the game is won by the player.
*
* @return true if the game is won by the player, false otherwise
*/
public boolean isGameWon() {
return isGameOver() && isOwnShot();
}
/**
* Checks if the game is lost by the player.
*
* @return true if the game is lost by the player, false otherwise
*/
public boolean isGameLost() {
return isGameOver() && !isOwnShot();
}
/**
* Checks if it's currently the player's turn.
*
* @return true if it's the player's turn, false otherwise
*/
public boolean isMyTurn() {
return isOwnShot() == shot.isHit();
}
/**
* Returns a string representation of the EffectMessage.
*
* @return a string representation of the EffectMessage
*/
@Override
public String toString() {
return "EffectMessage{ownShot=" + ownShot + ", shot=" + shot + ", destroyedShip=" + destroyedShip + //NON-NLS
", remainingOpponentShips=" + remainingOpponentShips + '}'; //NON-NLS
}
/**
* Returns the key for the informational text associated with this message.
*
* @return the key for the informational text
*/
@Override
public String getInfoTextKey() {
if (isGameOver())
return isGameWon() ? "you.won.the.game" : "you.lost.the.game";
return isMyTurn() ? "its.your.turn" : "wait.for.opponent";
}
}

View File

@@ -1,97 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.server;
import com.jme3.network.serializing.Serializable;
import pp.battleship.BattleshipConfig;
import java.util.Map;
/**
* A message sent by the server to provide details about the game configuration.
*/
@Serializable
public class GameDetails extends ServerMessage {
private Map<Integer, Integer> shipNums;
private int width;
private int height;
/**
* Default constructor for serialization purposes.
*/
private GameDetails() { /* empty */ }
/**
* Constructs a GameDetails message with the specified BattleshipConfig.
*
* @param config the BattleshipConfig containing game configuration details
*/
public GameDetails(BattleshipConfig config) {
this.shipNums = config.getShipNums();
this.width = config.getMapWidth();
this.height = config.getMapHeight();
}
/**
* Accepts a visitor to process this message.
*
* @param interpreter the visitor to process this message
*/
@Override
public void accept(ServerInterpreter interpreter) {
interpreter.received(this);
}
/**
* Returns a map where the keys represent ship lengths
* and the values represent the number of ships of that length.
*
* @return a map of ship lengths to the number of ships
*/
public Map<Integer, Integer> getShipNums() {
return shipNums;
}
/**
* Returns the width of the game map.
*
* @return the width of the game map
*/
public int getWidth() {
return width;
}
/**
* Returns the height of the game map.
*
* @return the height of the game map
*/
public int getHeight() {
return height;
}
/**
* Returns a string representation of the GameDetails message.
*
* @return a string representation of the GameDetails message
*/
@Override
public String toString() {
return "GameDetails{" + "ships=" + getShipNums() + ", width=" + width + ", height=" + height + '}'; //NON-NLS
}
/**
* Returns the key for the informational text associated with this message.
*
* @return the key for the informational text
*/
@Override
public String getInfoTextKey() {
return "place.ships.in.your.map";
}
}

View File

@@ -1,36 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.server;
/**
* An interface for processing server messages.
* Implementations of this interface can be used to handle different types of server messages.
*/
public interface ServerInterpreter {
/**
* Handles a GameDetails message received from the server.
*
* @param msg the GameDetails message received
*/
void received(GameDetails msg);
/**
* Handles a StartBattleMessage received from the server.
*
* @param msg the StartBattleMessage received
*/
void received(StartBattleMessage msg);
/**
* Handles an EffectMessage received from the server.
*
* @param msg the EffectMessage received
*/
void received(EffectMessage msg);
}

View File

@@ -1,39 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.server;
import com.jme3.network.AbstractMessage;
/**
* An abstract base class for server messages used in network transfer.
* It extends the AbstractMessage class provided by the jme3-network library.
*/
public abstract class ServerMessage extends AbstractMessage {
/**
* Constructs a new ServerMessage instance.
*/
protected ServerMessage() {
super(true);
}
/**
* Accepts a visitor for processing this message.
*
* @param interpreter the visitor to be used for processing
*/
public abstract void accept(ServerInterpreter interpreter);
/**
* Gets the bundle key of the informational text to be shown at the client.
* This key is used to retrieve the appropriate localized text for display.
*
* @return the bundle key of the informational text
*/
public abstract String getInfoTextKey();
}

View File

@@ -1,71 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.message.server;
import com.jme3.network.serializing.Serializable;
/**
* A message sent by the server to inform clients about the start of the battle.
*/
@Serializable
public class StartBattleMessage extends ServerMessage {
private boolean myTurn;
/**
* Default constructor for serialization purposes.
*/
private StartBattleMessage() { /* empty */ }
/**
* Constructs a StartBattleMessage with the specified turn indicator.
*
* @param myTurn true if it's the client's turn to shoot, false otherwise
*/
public StartBattleMessage(boolean myTurn) {
this.myTurn = myTurn;
}
/**
* Accepts a visitor to process this message.
*
* @param interpreter the visitor to process this message
*/
@Override
public void accept(ServerInterpreter interpreter) {
interpreter.received(this);
}
/**
* Checks if it's the client's turn to shoot.
*
* @return true if it's the client's turn, false otherwise
*/
public boolean isMyTurn() {
return myTurn;
}
/**
* Returns a string representation of the StartBattleMessage.
*
* @return a string representation of the StartBattleMessage
*/
@Override
public String toString() {
return "StartBattleMessage{myTurn=" + myTurn + '}'; //NON-NLS
}
/**
* Returns the key for the informational text associated with this message.
*
* @return the key for the informational text
*/
@Override
public String getInfoTextKey() {
return isMyTurn() ? "its.your.turn" : "wait.for.opponent";
}
}

View File

@@ -1,324 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
import com.jme3.network.serializing.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static java.lang.Math.max;
import static java.lang.Math.min;
/**
* Represents a battleship in the game. A battleship is characterized by its length, position,
* rotation, and status. It can be moved, rotated, and hit during the game. This class also
* provides methods to check for collisions with other ships and to determine whether the
* battleship has been destroyed.
*/
@Serializable
public class Battleship implements Item {
/**
* Enumeration representing the different statuses a battleship can have during the game.
*/
public enum Status {
/**
* The ship is in its normal state, not being previewed for placement.
*/
NORMAL,
/**
* The ship is being previewed in a valid position for placement.
*/
VALID_PREVIEW,
/**
* The ship is being previewed in an invalid position for placement.
*/
INVALID_PREVIEW
}
private final int length; // The length of the battleship
private int x; // The x-coordinate of the battleship's position
private int y; // The y-coordinate of the battleship's position
private Rotation rot; // The rotation of the battleship
private Status status; // The current status of the battleship
private final Set<IntPoint> damaged = new HashSet<>(); // The set of positions that have been hit on this ship
/**
* Default constructor for serialization. Initializes a battleship with length 0,
* at position (0, 0), with a default rotation of RIGHT.
*/
private Battleship() {
this(0, 0, 0, Rotation.RIGHT);
}
/**
* Constructs a new Battleship with the specified length, position, and rotation.
*
* @param length the length of the battleship
* @param x the x-coordinate of the battleship's initial position
* @param y the y-coordinate of the battleship's initial position
* @param rot the rotation of the battleship
*/
public Battleship(int length, int x, int y, Rotation rot) {
this.x = x;
this.y = y;
this.rot = rot;
this.length = length;
this.status = Status.NORMAL;
}
/**
* Returns the current x-coordinate of the battleship's position.
*
* @return the x-coordinate of the battleship
*/
public int getX() {
return x;
}
/**
* Returns the current y-coordinate of the battleship's position.
*
* @return the y-coordinate of the battleship
*/
public int getY() {
return y;
}
/**
* Moves the battleship to the specified coordinates.
*
* @param x the new x-coordinate of the battleship's position
* @param y the new y-coordinate of the battleship's position
*/
public void moveTo(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Moves the battleship to the specified position.
*
* @param pos the new position of the battleship
*/
public void moveTo(IntPosition pos) {
moveTo(pos.getX(), pos.getY());
}
/**
* Returns the current status of the battleship.
*
* @return the status of the battleship
*/
public Status getStatus() {
return status;
}
/**
* Sets the status of the battleship.
*
* @param status the new status to be set for the battleship
*/
public void setStatus(Status status) {
this.status = status;
}
/**
* Returns the length of the battleship.
*
* @return the length of the battleship
*/
public int getLength() {
return length;
}
/**
* Returns the minimum x-coordinate that the battleship occupies based on its current position and rotation.
*
* @return the minimum x-coordinate of the battleship
*/
public int getMinX() {
return x + min(0, (length - 1) * rot.dx());
}
/**
* Returns the maximum x-coordinate that the battleship occupies based on its current position and rotation.
*
* @return the maximum x-coordinate of the battleship
*/
public int getMaxX() {
return x + max(0, (length - 1) * rot.dx());
}
/**
* Returns the minimum y-coordinate that the battleship occupies based on its current position and rotation.
*
* @return the minimum y-coordinate of the battleship
*/
public int getMinY() {
return y + min(0, (length - 1) * rot.dy());
}
/**
* Returns the maximum y-coordinate that the battleship occupies based on its current position and rotation.
*
* @return the maximum y-coordinate of the battleship
*/
public int getMaxY() {
return y + max(0, (length - 1) * rot.dy());
}
/**
* Returns the current rotation of the battleship.
*
* @return the rotation of the battleship
*/
public Rotation getRot() {
return rot;
}
/**
* Sets the rotation of the battleship.
*
* @param rot the new rotation to be set for the battleship
*/
public void setRotation(Rotation rot) {
this.rot = rot;
}
/**
* Rotates the battleship by 90 degrees clockwise.
*/
public void rotated() {
setRotation(rot.rotate());
}
/**
* Attempts to hit the battleship at the specified position.
* If the position is part of the battleship, the hit is recorded.
*
* @param x the x-coordinate of the position to hit
* @param y the y-coordinate of the position to hit
* @return true if the position is part of the battleship, false otherwise
* @see #contains(int, int)
*/
public boolean hit(int x, int y) {
if (!contains(x, y))
return false;
damaged.add(new IntPoint(x, y));
return true;
}
/**
* Attempts to hit the battleship at the specified position.
* If the position is part of the battleship, the hit is recorded.
* This is a convenience method for {@linkplain #hit(int, int)}.
*
* @param position the position to hit
* @return true if the position is part of the battleship, false otherwise
*/
public boolean hit(IntPosition position) {
return hit(position.getX(), position.getY());
}
/**
* Returns the positions of this battleship that have been hit.
*
* @return a set of positions that have been hit
* @see #hit(int, int)
*/
public Set<IntPoint> getDamaged() {
return Collections.unmodifiableSet(damaged);
}
/**
* Checks whether the specified position is covered by the battleship. This method does
* not record a hit, only checks coverage.
* This is a convenience method for {@linkplain #contains(int, int)}.
*
* @param pos the position to check
* @return true if the position is covered by the battleship, false otherwise
*/
public boolean contains(IntPosition pos) {
return contains(pos.getX(), pos.getY());
}
/**
* Checks whether the specified position is covered by the battleship. This method does
* not record a hit, only checks coverage.
*
* @param x the x-coordinate of the position to check
* @param y the y-coordinate of the position to check
* @return true if the position is covered by the battleship, false otherwise
*/
public boolean contains(int x, int y) {
return getMinX() <= x && x <= getMaxX() &&
getMinY() <= y && y <= getMaxY();
}
/**
* Determines if the battleship has been completely destroyed. A battleship is considered
* destroyed if all of its positions have been hit.
*
* @return true if the battleship is destroyed, false otherwise
* @see #hit(int, int)
*/
public boolean isDestroyed() {
return damaged.size() == length;
}
/**
* Checks whether this battleship collides with another battleship. Two battleships collide
* if any of their occupied positions overlap.
*
* @param other the other battleship to check collision with
* @return true if the battleships collide, false otherwise
*/
public boolean collidesWith(Battleship other) {
return other.getMaxX() >= getMinX() && getMaxX() >= other.getMinX() &&
other.getMaxY() >= getMinY() && getMaxY() >= other.getMinY();
}
/**
* Returns a string representation of the battleship, including its length, position,
* and rotation.
*
* @return a string representation of the battleship
*/
@Override
public String toString() {
return "Ship{length=" + length + ", x=" + x + ", y=" + y + ", rot=" + rot + '}'; //NON-NLS
}
/**
* Accepts a visitor that returns a value of type {@code T}. This method is part of the
* Visitor design pattern.
*
* @param visitor the visitor to accept
* @param <T> the type of the value returned by the visitor
* @return the value returned by the visitor
*/
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
/**
* Accepts a visitor that does not return a value. This method is part of the
* Visitor design pattern.
*
* @param visitor the visitor to accept
*/
@Override
public void accept(VoidVisitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,94 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
import com.jme3.network.serializing.Serializable;
import java.util.Objects;
/**
* Represents a point in the two-dimensional plane with integer coordinates.
*/
@Serializable
public final class IntPoint implements IntPosition {
private int x;
private int y;
/**
* Default constructor for serialization purposes.
*/
private IntPoint() { /* do nothing */ }
/**
* Constructs a new IntPoint with the specified coordinates.
*
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
*/
public IntPoint(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Gets the x-coordinate of the point.
*
* @return the x-coordinate
*/
@Override
public int getX() {
return x;
}
/**
* Gets the y-coordinate of the point.
*
* @return the y-coordinate
*/
@Override
public int getY() {
return y;
}
/**
* Indicates whether some other object is "equal to" this one.
*
* @param obj the reference object with which to compare
* @return true if this object is the same as the obj argument; false otherwise
*/
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (IntPoint) obj;
return this.x == that.x &&
this.y == that.y;
}
/**
* Returns a hash code value for the IntPoint.
*
* @return a hash code value for this object
*/
@Override
public int hashCode() {
return Objects.hash(x, y);
}
/**
* Returns a string representation of the IntPoint.
*
* @return a string representation of the object
*/
@Override
public String toString() {
return "IntPoint[" + //NON-NLS
"x=" + x + ", " + //NON-NLS
"y=" + y + ']'; //NON-NLS
}
}

View File

@@ -1,28 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
/**
* Interface representing a position with X and Y coordinates.
*/
public interface IntPosition {
/**
* Returns the X coordinate of this position.
*
* @return the X coordinate.
*/
int getX();
/**
* Returns the Y coordinate of this position.
*
* @return the Y coordinate.
*/
int getY();
}

View File

@@ -1,31 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
/**
* An interface representing any item on a ship map.
* It extends the IntPosition interface to provide position information.
*/
public interface Item {
/**
* Accepts a visitor to perform operations on the item.
*
* @param visitor the visitor performing operations on the item
* @param <T> the type of result returned by the visitor
* @return the result of the visitor's operation on the item
*/
<T> T accept(Visitor<T> visitor);
/**
* Accepts a visitor to perform operations on the item without returning a result.
*
* @param visitor the visitor performing operations on the item
*/
void accept(VoidVisitor visitor);
}

View File

@@ -1,67 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
import java.io.Serializable;
/**
* Represents the rotation of a ship and provides functionality related to rotation.
*/
public enum Rotation implements Serializable {
/**
* Represents the ship facing upwards.
*/
UP,
/**
* Represents the ship facing rightwards.
*/
RIGHT,
/**
* Represents the ship facing downwards.
*/
DOWN,
/**
* Represents the ship facing leftwards.
*/
LEFT;
/**
* Gets the change in x-coordinate corresponding to this rotation.
*
* @return the change in x-coordinate
*/
public int dx() {
return switch (this) {
case UP, DOWN -> 0;
case RIGHT -> 1;
case LEFT -> -1;
};
}
/**
* Gets the change in y-coordinate corresponding to this rotation.
*
* @return the change in y-coordinate
*/
public int dy() {
return switch (this) {
case UP -> 1;
case LEFT, RIGHT -> 0;
case DOWN -> -1;
};
}
/**
* Rotates the orientation clockwise and returns the next rotation.
*
* @return the next rotation after rotating clockwise
*/
public Rotation rotate() {
return values()[(ordinal() + 1) % values().length];
}
}

View File

@@ -1,251 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
import pp.battleship.notification.GameEvent;
import pp.battleship.notification.GameEventBroker;
import pp.battleship.notification.ItemAddedEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
/**
* Represents a rectangular map that holds ships and registers shots fired.
* It also supports event notification for game state changes such as item addition or removal.
* Valid positions on this map have x-coordinates in the range of 0 to width-1 and y-coordinates
* in the range of 0 to height-1.
*
* @see #getWidth()
* @see #getHeight()
*/
public class ShipMap {
/**
* A list of items (ships, shots, etc.) placed on the map.
*/
private final List<Item> items = new ArrayList<>();
/**
* The broker responsible for notifying registered listeners of events
* (such as when an item is added or removed from the map).
* Can be null, in which case no notifications will be sent.
*/
private final GameEventBroker eventBroker;
private final int width;
private final int height;
/**
* Constructs an empty map with the given dimensions. The specified event broker
* will handle the notification of changes in the map state, such as adding or removing items.
* Passing null as the event broker is allowed, but in that case, no notifications will occur.
*
* @param width the number of columns (width) of the map
* @param height the number of rows (height) of the map
* @param eventBroker the event broker used for notifying listeners, or null if event distribution is not needed
*/
public ShipMap(int width, int height, GameEventBroker eventBroker) {
if (width < 1 || height < 1)
throw new IllegalArgumentException("Invalid map size");
this.width = width;
this.height = height;
this.eventBroker = eventBroker;
}
/**
* Adds an item (e.g., a ship or a shot) to the map and triggers the appropriate event.
*
* @param item the item to be added to the map
*/
private void addItem(Item item) {
items.add(item);
notifyListeners(new ItemAddedEvent(item, this));
}
/**
* Adds a battleship to the map and triggers an item addition event.
*
* @param ship the battleship to be added to the map
*/
public void add(Battleship ship) {
addItem(ship);
}
/**
* Registers a shot on the map, updates the state of the affected ship (if any),
* and triggers an item addition event.
*
* @param shot the shot to be registered on the map
*/
public void add(Shot shot) {
final Battleship ship = findShipAt(shot);
if (ship != null)
ship.hit(shot);
addItem(shot);
}
/**
* Removes an item from the map and triggers an item removal event.
*
* @param item the item to be removed from the map
*/
public void remove(Item item) {
items.remove(item);
notifyListeners(new ItemAddedEvent(item, this));
}
/**
* Removes all items from the map and triggers corresponding removal events for each.
*/
public void clear() {
new ArrayList<>(items).forEach(this::remove);
}
/**
* Returns a stream of items of a specified type (class).
*
* @param clazz the class type to filter items by
* @param <T> the type of items to return
* @return a stream of items matching the specified class type
*/
private <T extends Item> Stream<T> getItems(Class<T> clazz) {
return items.stream().filter(clazz::isInstance).map(clazz::cast);
}
/**
* Returns a stream of all battleships currently on the map.
*
* @return a stream of battleships
*/
public Stream<Battleship> getShips() {
return getItems(Battleship.class);
}
/**
* Returns a list of all remaining battleships that have not been destroyed.
*
* @return a list of remaining battleships
*/
public List<Battleship> getRemainingShips() {
return getShips().filter(s -> !s.isDestroyed()).toList();
}
/**
* Returns a stream of all shots fired on the map.
*
* @return a stream of shots
*/
public Stream<Shot> getShots() {
return getItems(Shot.class);
}
/**
* Returns an unmodifiable list of all items currently on the map.
*
* @return an unmodifiable list of all items
*/
public List<Item> getItems() {
return Collections.unmodifiableList(items);
}
/**
* Returns the width (number of columns) of the map.
*
* @return the width of the map
*/
public int getWidth() {
return width;
}
/**
* Returns the height (number of rows) of the map.
*
* @return the height of the map
*/
public int getHeight() {
return height;
}
/**
* Checks if the given ship is in a valid position (within the map bounds and non-colliding with other ships).
*
* @param ship the battleship to validate
* @return true if the ship's position is valid, false otherwise
*/
public boolean isValid(Battleship ship) {
return isValid(ship.getMinX(), ship.getMinY()) &&
isValid(ship.getMaxX(), ship.getMaxY()) &&
getShips().filter(s -> s != ship).noneMatch(ship::collidesWith);
}
/**
* Finds a battleship at the specified coordinates.
*
* @param x the x-coordinate of the position
* @param y the y-coordinate of the position
* @return the ship at the specified coordinates, or null if none is found
*/
public Battleship findShipAt(int x, int y) {
return getShips().filter(ship -> ship.contains(x, y))
.findAny()
.orElse(null);
}
/**
* Finds a battleship at the specified position. This is a convenience method.
*
* @param position the position within the map
* @return the ship at the specified position, or null if none is found
*/
public Battleship findShipAt(IntPosition position) {
return findShipAt(position.getX(), position.getY());
}
/**
* Validates whether the specified position is within the map boundaries.
*
* @param pos the position to validate
* @return true if the position is within the map, false otherwise
*/
public boolean isValid(IntPosition pos) {
return isValid(pos.getX(), pos.getY());
}
/**
* Checks if the specified coordinates are within the map boundaries.
*
* @param x the x-coordinate to validate
* @param y the y-coordinate to validate
* @return true if the coordinates are valid, false otherwise
*/
public boolean isValid(int x, int y) {
return x >= 0 && x < width &&
y >= 0 && y < height;
}
/**
* Returns a string representation of the ship map.
*
* @return a string representation of the ship map
*/
@Override
public String toString() {
return "ShipMap{" + items + '}'; //NON-NLS
}
/**
* Notifies all registered listeners about a game event if the event broker is available.
*
* @param event the event to be distributed to listeners
*/
private void notifyListeners(GameEvent event) {
if (eventBroker != null)
eventBroker.notifyListeners(event);
}
}

View File

@@ -1,140 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
import com.jme3.network.serializing.Serializable;
import java.util.Objects;
/**
* Represents a shot in the Battleship game.
* A shot is defined by its coordinates and whether it was a hit or miss.
*/
@Serializable
public final class Shot implements Item, IntPosition {
private int x;
private int y;
private boolean hit;
// Private no-arg constructor for serialization purposes
private Shot() {}
/**
* Creates a new shot.
*
* @param x the x-coordinate of the shot
* @param y the y-coordinate of the shot
* @param hit indicates whether the shot was a hit
*/
public Shot(int x, int y, boolean hit) {
this.x = x;
this.y = y;
this.hit = hit;
}
/**
* Creates a new shot.
*
* @param pos the position of the shot
* @param hit indicates whether the shot was a hit
*/
public Shot(IntPosition pos, boolean hit) {
this(pos.getX(), pos.getY(), hit);
}
/**
* Gets the x-coordinate of the shot.
*
* @return the x-coordinate of the shot
*/
@Override
public int getX() {
return x;
}
/**
* Gets the y-coordinate of the shot.
*
* @return the y-coordinate of the shot
*/
@Override
public int getY() {
return y;
}
/**
* Checks if the shot was a hit.
*
* @return true if the shot was a hit, false otherwise
*/
public boolean isHit() {
return hit;
}
/**
* Checks if this shot is equal to another object.
* Two shots are considered equal if they have the same coordinates and hit status.
*
* @param obj the object to compare with
* @return true if the objects are equal, false otherwise
*/
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (Shot) obj;
return this.x == that.x &&
this.y == that.y &&
this.hit == that.hit;
}
/**
* Computes the hash code of this shot.
*
* @return the hash code of this shot
*/
@Override
public int hashCode() {
return Objects.hash(x, y, hit);
}
/**
* Returns a string representation of the shot.
*
* @return a string representation of the shot
*/
@Override
public String toString() {
return "Shot[" + //NON-NLS
"x=" + x + ", " + //NON-NLS
"y=" + y + ", " + //NON-NLS
"hit=" + hit + ']'; //NON-NLS
}
/**
* Accepts a visitor with a return value.
*
* @param visitor the visitor to accept
* @param <T> the type of the return value
* @return the result of the visitor's visit method
*/
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
/**
* Accepts a visitor without a return value.
*
* @param visitor the visitor to accept
*/
@Override
public void accept(VoidVisitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,31 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
/**
* An interface for implementing the Visitor pattern for different types of elements in the Battleship model.
*
* @param <T> the type of result returned by the visit methods
*/
public interface Visitor<T> {
/**
* Visits a Shot element.
*
* @param shot the Shot element to visit
* @return the result of visiting the Shot element
*/
T visit(Shot shot);
/**
* Visits a Battleship element.
*
* @param ship the Battleship element to visit
* @return the result of visiting the Battleship element
*/
T visit(Battleship ship);
}

View File

@@ -1,28 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model;
/**
* An interface for implementing the Visitor pattern for different types of elements in the Battleship model
* without returning any result.
*/
public interface VoidVisitor {
/**
* Visits a Shot element.
*
* @param shot the Shot element to visit
*/
void visit(Shot shot);
/**
* Visits a Battleship element.
*
* @param ship the Battleship element to visit
*/
void visit(Battleship ship);
}

View File

@@ -1,51 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model.dto;
import pp.battleship.model.Battleship;
import pp.battleship.model.Rotation;
/**
* A class representing data transfer objects of battleships for JSON serialization and deserialization.
*/
class BattleshipDTO {
private final int length; // The length of the battleship
private final int x; // The x-coordinate of the battleship's position
private final int y; // The y-coordinate of the battleship's position
private final Rotation rot; // The rotation of the battleship
/**
* Constructs a BattleshipDTO object from a Battleship object.
*
* @param ship the Battleship object to be converted
*/
BattleshipDTO(Battleship ship) {
length = ship.getLength();
x = ship.getX();
y = ship.getY();
rot = ship.getRot();
}
/**
* Gets the length of the battleship.
*
* @return the length
*/
public int getLength() {
return length;
}
/**
* Converts this BattleshipDTO object to a Battleship object.
*
* @return the Battleship object
*/
Battleship toBattleship() {
return new Battleship(length, x, y, rot);
}
}

View File

@@ -1,117 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.model.dto;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import pp.battleship.message.server.GameDetails;
import pp.battleship.model.Battleship;
import pp.battleship.model.ShipMap;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.List;
/**
* A class representing data transfer objects of ship maps for JSON serialization and deserialization.
*/
public class ShipMapDTO {
// Logger instance for logging messages
static final Logger LOGGER = System.getLogger(ShipMapDTO.class.getName());
// Width of the ship map
private int width;
// Height of the ship map
private int height;
// List of ships in the map
private List<BattleshipDTO> ships;
/**
* Constructs a ShipMapDTO object from a ShipMap object.
*
* @param map the ShipMap object to be converted
*/
public ShipMapDTO(ShipMap map) {
this.width = map.getWidth();
this.height = map.getHeight();
this.ships = map.getShips().map(BattleshipDTO::new).toList();
}
/**
* Checks if the current ship map fits the game details provided.
*
* @param details the game details to be matched against
* @return true if the ship map fits the game details, false otherwise
*/
public boolean fits(GameDetails details) {
if (width != details.getWidth() || height != details.getHeight())
return false;
int numShips = details.getShipNums().values().stream().mapToInt(Integer::intValue).sum();
if (numShips != ships.size())
return false;
for (var e : details.getShipNums().entrySet()) {
final int shipLength = e.getKey();
final int requiredNum = e.getValue();
final int actualNum = (int) ships.stream()
.filter(s -> s.getLength() == shipLength)
.count();
if (requiredNum != actualNum)
return false;
}
return true;
}
/**
* Returns the ships stored in this DTO.
*
* @return the ships stored in this DTO
*/
public List<Battleship> getShips() {
return ships.stream().map(BattleshipDTO::toBattleship).toList();
}
/**
* Saves the current ShipMapDTO to a file in JSON format.
*
* @param file the file to which the ShipMapDTO will be saved
* @throws IOException if an I/O error occurs
*/
public void saveTo(File file) throws IOException {
try (FileWriter writer = new FileWriter(file)) {
final Gson gson = new GsonBuilder().setPrettyPrinting().create();
final String json = gson.toJson(this);
LOGGER.log(Level.DEBUG, "JSON of map: {0}", json); //NON-NLS
writer.write(json);
LOGGER.log(Level.INFO, "JSON written to {0}", file.getAbsolutePath()); //NON-NLS
}
}
/**
* Loads a ShipMapDTO from a file containing JSON data.
*
* @param file the file from which the ShipMapDTO will be loaded
* @return the loaded ShipMapDTO object
* @throws IOException if an I/O error occurs or if the JSON is invalid
*/
public static ShipMapDTO loadFrom(File file) throws IOException {
try (FileReader reader = new FileReader(file)) {
final Gson gson = new Gson();
return gson.fromJson(reader, ShipMapDTO.class);
}
catch (JsonParseException e) {
throw new IOException(e.getLocalizedMessage());
}
}
}

View File

@@ -1,23 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
/**
* Event when an item is added to a map.
*/
public record ClientStateEvent() implements GameEvent {
/**
* Notifies the game event listener of this event.
*
* @param listener the game event listener
*/
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}

View File

@@ -1,20 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
/**
* An interface used for all game events.
*/
public interface GameEvent {
/**
* Notifies the game event listener of the event.
*
* @param listener the game event listener to be notified
*/
void notifyListener(GameEventListener listener);
}

View File

@@ -1,20 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
/**
* Defines a broker for distributing game events to registered listeners.
*/
public interface GameEventBroker {
/**
* Notifies all registered listeners about the specified game event.
*
* @param event the game event to be broadcast to listeners
*/
void notifyListeners(GameEvent event);
}

View File

@@ -1,48 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
/**
* Listener interface for all events implemented by subclasses of {@linkplain pp.battleship.notification.GameEvent}.
*/
public interface GameEventListener {
/**
* Indicates that an item has been destroyed
*
* @param event the received event
*/
default void receivedEvent(ItemRemovedEvent event) { /* do nothing */ }
/**
* Indicates that an item has been added to a map.
*
* @param event the received event
*/
default void receivedEvent(ItemAddedEvent event) { /* do nothing */ }
/**
* Indicates that an info text shall be shown.
*
* @param event the received event
*/
default void receivedEvent(InfoTextEvent event) { /* do nothing */ }
/**
* Indicates that a sound shall be played.
*
* @param event the received event
*/
default void receivedEvent(SoundEvent event) { /* do nothing */ }
/**
* Indicates that the client's state has changed.
*
* @param event the received event
*/
default void receivedEvent(ClientStateEvent event) { /* do nothing */ }
}

View File

@@ -1,25 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
/**
* Event when an item is added to a map.
*
* @param key the bundle key for the message
*/
public record InfoTextEvent(String key) implements GameEvent {
/**
* Notifies the game event listener of this event.
*
* @param listener the game event listener
*/
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}

View File

@@ -1,29 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
import pp.battleship.model.Item;
import pp.battleship.model.ShipMap;
/**
* Event when an item is added to a map.
*
* @param item the added item
* @param map the map that got the additional item
*/
public record ItemAddedEvent(Item item, ShipMap map) implements GameEvent {
/**
* Notifies the game event listener of this event.
*
* @param listener the game event listener
*/
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}

View File

@@ -1,28 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
import pp.battleship.model.Item;
import pp.battleship.model.ShipMap;
/**
* Event when an item gets removed.
*
* @param item the destroyed item
*/
public record ItemRemovedEvent(Item item, ShipMap map) implements GameEvent {
/**
* Notifies the game event listener of this event.
*
* @param listener the game event listener
*/
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}

View File

@@ -1,26 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
/**
* Enumeration representing different types of sounds used in the game.
*/
public enum Sound {
/**
* Sound of an explosion.
*/
EXPLOSION,
/**
* Sound of a splash.
*/
SPLASH,
/**
* Sound of a ship being destroyed.
*/
DESTROYED_SHIP
}

View File

@@ -1,26 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.notification;
/**
* Event when an item is added to a map.
*
* @param sound the sound to be played
*/
public record SoundEvent(Sound sound) implements GameEvent {
/**
* Notifies the game event listener of this event.
*
* @param listener the game event listener
*/
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}

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