From 429e5bc90b1a6950eaa3603edf35515739d1954c Mon Sep 17 00:00:00 2001 From: Bas Antonius de Jong <49651652+BAFGdeJong@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:30:49 +0100 Subject: [PATCH] Demo 6 * Server update with new dev changes (#305) * merge widgets with development * readd previous game thread code * Revert "readd previous game thread code" This reverts commit d24feef73e0ba05357776d24e2a607d8be4aa849. * Revert "Merge remote-tracking branch 'origin/Development' into Development" This reverts commit 59d46cb73c3bf208ee359ce86f3ce4306d4e5964, reversing changes made to 38681c5db03e3e170c90ec3ec6795b6331b157df. * Revert "merge widgets with development" This reverts commit 38681c5db03e3e170c90ec3ec6795b6331b157df. * Merge 292 into development (#293) Applied template method pattern to abstract player * Added documentation to player classes and improved method names (#295) * mcts v1 * bitboard optimization * bitboard fix & mcts v2 & mcts v3. v3 still in progress and v4 coming soon * main * Hotfix for stuff * Logging and fixed user input getting stuck * Fixed merge mistakes (#307) * fast server connection * Fixed bugs and oversights * Renamed asset folder to resource, made resourceLoader more robust. Completed some TODO's, formatting * AppSettings now also get loaded into the assetmanager * start to reversi logic * legal moves now get highlighted in red * Moves flip dots. all tests pass. can play reversi local. * Working state. Split AudioManager into 3 different branches for easier testing and srp * Reworked to now use better defined generics and easier to use API. Added AudioResource to be used in changing volume * Made all of the updated classes more generic for better flexibility in unittesting * Added more flexible dependency injection to MusicManager for unittesting. Moved to event driven design for less complex code and lower runtime complexity. * Split SoundEffectManager from AudioManager. (#171) Clips no longer create a new clip instance each time they are played. A singular clip is made for each resource and is opened/closed when loaded/unloaded. When a clip is played that is already playing it'll stop playback and start again. Clip volume handling isn't done very well. * Unit tests for MusicManager.java * Hotfix for loading clip volume issue (#174) * Fixed AudioVolumemanager, all volumes calculations are now made in VolumeTypes enum * Added ability to remove a manager from VolumeTypes * Removed file no longer in use * Fixed grammer and spelling mistakes * Renamed VOLUME to MASTERVOLUME for better naming * Minor changes in API design * Renamed VolumeTypes to VolumeControl. Made it thread safe. Added docs to VolumeControl and co. removed .updateAllVolumes() in favor of auto updating inside enum instead * Added ErrorProne for potential bugs. Fixed potential bugs. * Small fixes. * Removed no more needed code. * Finished todo's * Moved restrictedAPI to future release * Finished todo's * Moved restrictedAPI to future release * Changed pom to be correct. Fixed SnowflakeGenerator not making unique ids. Changed naming for event implementation. Automated id getter for events. Added Error-Prone to all modules. Added parents to all modules. Added processors module. * SoundEffectManager now generic * Removed ResourceManager from AudioManagers * Added linelistener to SoundEffectAsset * commit * commit ofzo * Tests for SoundEffectManager * getLegalMoves logic seems fixed //todo write better tests * Tests toegevoegd * punk toegevoegd * Added shuffling on user request * Reworked NetworkingClientManager into SRP model. * Forgot to remove * Improved API for dependency injection * Some better docs. * gui refactor * fixed merge conflicts * Added exceptions. Added reconnect attempts and changeable address * Fixed event bug * add: reversi game * add: server chat box * visual update * Refactor to make Events easier to work with. * Quick fix for closing connection. * Documentation * Correct client creation and user polling * begin van audio display * Polling music event, fires every 1 second * Updated test. * Updated timings * Nuke everything on close. * Basis Audio Display toegevoegd + standaard CSS toegevoegd Kan nu zien hoe lang de song duurt, hoe lang ie al bezig is met draaien en de titel (-.mp3) * Clips now also return positional information * Skip Button * Skip Button * Fixes for garbage code by Omar * Tiny fix when natural skip * Small event fix * Faster event schedule for PlayingMusic event * test fix * added method for sorting the flipped pieces by distance to Move.position * new reversi test (both players no legal moves) * connect4 with minimax AI * Toegevoegd: -Play Button + CSS + Events -Previous Button + CSS + Events -Changed interface for AudioResource to include a pause button which works really well with mediaplayer, however now SoundEffectAsset has an unnessescary pause * Made it so that it indicates with the play/pause button if its paused or played * add simple flip animations and fixed(?) server somewhat * fixed tests * can start game from playerlist screen * tourney ready * spam minder * fixed setgamelabels * spam minder v2 * canvas changes * moved score out of game * can now go to last using previous and being at the first song * mainview false for sendchallengeview * moved score out of game * kleine ui fix * updated music ma,es * started working on the widget system * iets met timing verkeerd temporary fix * Fixes for garbage code by Omar * Added replace to reduce boiler plate code * Manually fallback to the fallback locale when a ResourceBundle is missing a resource key. Fallsback to "MISSING RESOUREC" if it's not present in the fallback. * Removed unused import and unused parameter * cool onhover effect for reversi * Made the GameState enum it's own file and fixed imports * Removed unused import * Turned abstract methods into an interface * Moved the Move record into it's own file, seperated from Game * Removed unused imports * Renamed Interface Playtable to IPlayable * Turned Abstract Method for AI into interface * Refactored Game to follow encapsulation principle * Removed unused imports * Applied encapsulation principle to TurnBasedBame.java * Privated methods that didn't have to be public * Reversi: made method private * Changed checkForEarlyDraw so it doesn't need a game as input. * Fixed warning "Warning:(27, 12) Copy constructor does not copy field 'mostRecentlyFlippedPieces'", removed unused field * Made connect4 public method private * half done with the widget system * added some comments and made some methods a bit more readable * widget system almost complete * Functional code, is now object orientated * Removed no more needed comments * started a basis for the tutorials, tic tac toe is almost done with some general stuff still to do. * rest van de tutorials toegevoegd * resizable true * fixed turn skip bug fixed end score bug now only shows legal and highlight moves when human * Squashed commit of the following: commit a517f2f302baa89f8ef59946a31c7bb59c56770f Author: Stef Date: Thu Nov 27 15:43:43 2025 +0100 Make it so the game shows "Waiting on ... to make their move". Styling isn't done but it is easier to see who's turn it is. There is a lot of structuring to do in the previous code... * merge widgets with development * readd previous game thread code * Revert "readd previous game thread code" This reverts commit d24feef73e0ba05357776d24e2a607d8be4aa849. * Revert "Merge remote-tracking branch 'origin/Development' into Development" This reverts commit 59d46cb73c3bf208ee359ce86f3ce4306d4e5964, reversing changes made to 38681c5db03e3e170c90ec3ec6795b6331b157df. * Revert "merge widgets with development" This reverts commit 38681c5db03e3e170c90ec3ec6795b6331b157df. * Fixed compilation errors * Changed the way turns are being stored in TurnBasedGame. * Removed views * Added function input for enabling/disabling localization p/text * Fix eventbus problems (#265) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Debugs for EventBus and fixed unsubscribe all (#266) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Fix music display not working (#267) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Added LoadingWidget.java for server feedback * Replace deprecated with correct function * Removed loading widget from Server.java * Fixed old new EventFlow().listen() missing false as third param * Tutorials to Dev (#264) * Fixed garbage code * added a pop button * Tutorial images now use ImageAsset.java * Added button to continue and start game. Refactors * Refactored nextScreen runnable * Removed unused imports * Refactored switch statement * Added documentation * Removed space * Added translations * Added function input for enabling/disabling localization p/text --------- Co-authored-by: ramollia <> * Merge new framework into development (#269) * Created a somewhat generic TurnBasedGame thread. Temporary UI that only works for TicTacToe rn. Added a LocalPlayer with the intent to add more players * (RANDOM COMMIT) Hope it works * Changes by bas * Fixed dependency issues * Fixed major issue in game deepcopy * Merge conflict fix * Removed unused import * Update GTBGT branch from dev branch (#263) * started a basis for the tutorials, tic tac toe is almost done with some general stuff still to do. * rest van de tutorials toegevoegd * Removed views * Merge conflict fix * Removed unused import --------- Co-authored-by: michiel301b Co-authored-by: ramollia <> Co-authored-by: Bas Antonius de Jong <49651652+BAFGdeJong@users.noreply.github.com> * Revert "Update GTBGT branch from dev branch (#263)" This reverts commit 9134d7e3432a9e35cf6ae9a49c9d7940581677cd. * Fixed frontend not using GameController because of spaghetti code. * Removed unused imports * GameCanvas not implements a DrawPlayerMove that can be overridden for specific implementations * Created an event that will request the controller to refresh the UI. * ADDED DEPENDENCY. Renamed GameControllers to GameManagers, gameThread is not game controller. * Attempt at adding an online player. I think it doesn't work because of unsubscriben after success not working * Multiplayer is functional through OnlineThreadBehaviour. Empty slots are currently represented by -1 in the GUI. * Removed sout spam, added logger than I can't get to work. * Idek what these changes are * Te lang geen commit, sorry * Multiplayer seems to work pretty well now, hopefully I can add the other games soon. * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Inbetween commit of adding Reversi. This is a lot of spaghetti. * Fixed stress tests * Fixed typo in NetworkingGameClientHandler that prevented losses from being received * Missed 2nd typo. Fixed * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Works now with updated EventFlow(). Unsubscribing works. ReversiAIR has an issue where a forced move returns -1 and local play back button doesn't work properly. To be fixed * Fixed ReversiR issue that caused skip turn desync * Fixed color mismatch with server and online main player is now correct. * Added a bunch of java doc and small changes * Small changes * Added a new Thread Behaviour to test framework. * Fixed human error I made in TicTacToeR logic... * Fixed broken event and wrong player being presented as winner. * Idk changes * Fixed PR conflicts --------- Co-authored-by: michiel301b Co-authored-by: Bas Antonius de Jong <49651652+BAFGdeJong@users.noreply.github.com> * added back button sounds because SOMEONE fucked it up..... * 231 connecting to server feedback (#275) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Added LoadingWidget.java for server feedback * Imports * fixed loadingwidget * Workable LoadingWidget and trying to connect to server * Removed output * Small bug temp fix --------- Co-authored-by: ramollia <> * Double loading call fix, LoadingWidget docs * Main menu loader (#277) * LoadingWidget main menu * fixed garbage code * Fixed garbage code 2 * LoadWidget fix, added loading to starting the game. Removed unnecessary console output --------- Co-authored-by: ramollia <> * Fixed systems starting, before assets being loaded (I am retarded) * Added infinite boolean, fixed loading behaviour at startup * 272 remake game framework interfaces to properly represent vmc (#278) * Cleaned up a lot of old files and renamed/remade interfaces to better suit the framework * Broken commit * Fixed online play * Better file structure and closer to MVC * Best fix for white screen at start * Making threads verbose regarding exceptions * Loading circle, better loading colors. * Event bus now testable, improved UI (#284) * turn updates * smalle fixes aan turn updates * better human/ai selector with bot selection and depth on TicTacToeAIR * depth + thinktime back to AIs, along with a a specific TicTacToeAIRSleep * fixed overlapping back and disconnect buttons * Changed to debug instead of info * changed the transitionNextCustom to be easier to use * added getAllWidgets to WidgetContainer * Correct back view * added replacePrevious in ViewWidget * added removeIndexFromPreviousChain * fixed incorrect index counting * Fixt wrong view order * Removed todo * Challenge popups "Fixed" * Popups now remove themselves * localize the ChallengePopup text * made the game text a header instead * fixed getAllWidgets * Escape popup * fixed redundant container * Escape remove popup * Working escape menu * Added find functionality * Tutorials moved to escape menu * Escape can't be opened in mainview now * Can now test the event bus, created testable interfaces * Logging errors * Made events and handlers more generic * Suppress * Managers now have changeable eventbus * Tutorials fixed * Removed import * Single threaded eventbus * Fixed wrong eventbus * Removed get * Removed old code * Renaming * Optimization * Removed useless comment * Removed unnecessary imports * Rename * Renaming, refactor and type safety * Rename * Removed import --------- Co-authored-by: michiel301b Co-authored-by: ramollia <> * initSystems now uses latch instead of timer. Moved single threads to Executor * Safety * Deleted unnecessary imports * Code cleanup * changed "fullscreen exit key combination" from esc to F11 * shitty fix for player selector spacing issue * shitty fix for player selector spacing issue v2 * fixed reversi colors being switched, causing multiple issues * Merge bitboards into development (#285) * added new classes for the games that use bitboards instead. also combined game with turnbasedgame * (DOES NOT COMPILE) In-between commit * turn updates * smalle fixes aan turn updates * Bitboard implemented with scuffed TicTacToe translation done by game. This should be done by the view. * Almost done with implementing bitboards. Reversi is broken and artifical players don't work yet. * better human/ai selector with bot selection and depth on TicTacToeAIR * fixed getLegalMoves * depth + thinktime back to AIs, along with a a specific TicTacToeAIRSleep * fixed overlapping back and disconnect buttons * Changed to debug instead of info * changed the transitionNextCustom to be easier to use * added getAllWidgets to WidgetContainer * Correct back view * added replacePrevious in ViewWidget * added removeIndexFromPreviousChain * fixed incorrect index counting * Fixt wrong view order * fixed? getLegalMoves * Everything is broken * Removed todo * fixed getLegalMoves & getFlips * Challenge popups "Fixed" * Fixed local and online play for both games * Popups now remove themselves * Removed souts for debugging * localize the ChallengePopup text * made the game text a header instead * made more classes deepClonable. * fixed getAllWidgets * Added comment * Escape popup * fixed redundant container * Made all network events async again * Escape remove popup * Working escape menu * Removed old AI and old files. Added a new generic random AI. game no longer deals with translation. * Drawing of board on canvas is now done from bitboards rather than translating. * Added a method getWinner() to game interface.Controller now tells gameThreads how to deal with drawing UI and sending a move to server. * Added find functionality * Added a ChatGPT generated MiniMaxAI based on the old MiniMaxAI but with alpha-beta pruning and heuristics for Reversi * Removed System-Outs to clean up console * Update BitGameCanvas.java * Merge fixes * Removed unused imports --------- Co-authored-by: ramollia <> Co-authored-by: michiel301b Co-authored-by: lieght <49651652+BAFGdeJong@users.noreply.github.com> * Better limits to generic acceptance * Will fix tests etc later * Merge 292 into development (#293) Applied template method pattern to abstract player * Added documentation to player classes and improved method names (#295) * Init server code * Moves * Testing code * Removed Generics, pray nothing breaks. * Code cleanup * Tests and better instantiation * Init challenges * Working challenges * Fixed bugs, easy to use host button * Fixed tic tac toe naming * Fixes * Removed Generics, pray nothing breaks. * Added ability to take ServerPlayer from user * Added pairs * Using pairs now in server.java * Removed space in naming * Werkt nog niet * Fixed hasArgs * Closable server * Making moves works. Game notifies when game has ended. * Partial server refactor * Refactor done, added ability to subscribe * Working subscription, button only subs to reversi right now * Small improvements to usability, auto disconnect when server closes connection * Missed a boolean * Quick fix so more than one game can be played in succession * Removed user from subscription if in a game * UI fixes after game end * TableWidget * mcts v1 * Moved subscriptions to store * bitboard optimization * Collapsed interfaces from model portion * Fixed runtime error I forgot to fix. * Collapsed interfaces in Controller section * Collapsed interfaces in View section * Code readability * bitboard fix & mcts v2 & mcts v3. v3 still in progress and v4 coming soon * main * 289 server demo ready (#306) * Server update with new dev changes (#305) * merge widgets with development * readd previous game thread code * Revert "readd previous game thread code" This reverts commit d24feef73e0ba05357776d24e2a607d8be4aa849. * Revert "Merge remote-tracking branch 'origin/Development' into Development" This reverts commit 59d46cb73c3bf208ee359ce86f3ce4306d4e5964, reversing changes made to 38681c5db03e3e170c90ec3ec6795b6331b157df. * Revert "merge widgets with development" This reverts commit 38681c5db03e3e170c90ec3ec6795b6331b157df. * Merge 292 into development (#293) Applied template method pattern to abstract player * Added documentation to player classes and improved method names (#295) * mcts v1 * bitboard optimization * bitboard fix & mcts v2 & mcts v3. v3 still in progress and v4 coming soon * main * Hotfix for stuff * Logging and fixed user input getting stuck * Fixed merge mistakes * Revert "Merge remote-tracking branch 'refs/remotes/origin/main' into Development" This reverts commit e2132b549d92c6d7cf98720660d88db8210cc408, reversing changes made to 9aefcb9b7bdf599735d5bbe5a4ffb8da07fd0e58. --------- Co-authored-by: ramollia <@> Co-authored-by: Ticho Hidding Co-authored-by: Stef <48526421+StefBuwalda@users.noreply.github.com> Co-authored-by: Stef Co-authored-by: michiel Co-authored-by: ramollia <> Co-authored-by: tichohidding <58555714+tichohidding@users.noreply.github.com> --- app/src/main/java/org/toop/Main.java | 46 ++- app/src/main/java/org/toop/app/App.java | 25 +- app/src/main/java/org/toop/app/Server.java | 97 +++--- .../org/toop/app/canvas/BitGameCanvas.java | 6 +- .../java/org/toop/app/canvas/GameCanvas.java | 3 +- .../java/org/toop/app/canvas/GameDrawer.java | 7 - .../org/toop/app/canvas/ReversiBitCanvas.java | 9 +- .../toop/app/canvas/TicTacToeBitCanvas.java | 9 +- .../GenericGameController.java | 46 ++- .../gameControllers/ReversiBitController.java | 27 +- .../TicTacToeBitController.java | 30 +- .../java/org/toop/app/widget/Primitive.java | 7 +- .../app/widget/complex/ConfirmWidget.java | 2 +- .../app/widget/complex/PlayerInfoWidget.java | 2 +- .../toop/app/widget/complex/TableWidget.java | 61 ++++ .../toop/app/widget/complex/ViewWidget.java | 6 +- .../toop/app/widget/popup/ChallengePopup.java | 4 +- .../toop/app/widget/popup/EscapePopup.java | 8 +- .../app/widget/popup/SendChallengePopup.java | 4 +- .../widget/tutorial/BaseTutorialWidget.java | 4 +- .../tutorial/ShowEnableTutorialWidget.java | 6 +- .../org/toop/app/widget/view/GameView.java | 4 +- .../app/widget/view/LocalMultiplayerView.java | 37 +- .../org/toop/app/widget/view/LocalView.java | 4 +- .../org/toop/app/widget/view/MainView.java | 10 +- .../org/toop/app/widget/view/OnlineView.java | 38 +- .../org/toop/app/widget/view/ServerView.java | 42 ++- framework/pom.xml | 1 - .../toop/framework}/game/BitboardGame.java | 51 ++- .../java/org/toop/framework}/game/Move.java | 2 +- .../LocalFixedRateThreadBehaviour.java | 8 +- .../gameThreads/LocalThreadBehaviour.java | 8 +- .../gameThreads/OnlineThreadBehaviour.java | 48 ++- .../OnlineWithSleepThreadBehaviour.java | 7 +- .../gameThreads/ServerThreadBehaviour.java | 82 +++++ .../game/games/reversi/BitboardReversi.java | 328 ++++++++++++++++++ .../games/tictactoe/BitboardTicTacToe.java | 28 +- .../game/players/ArtificialPlayer.java | 21 +- .../framework/game/players/LocalPlayer.java | 108 ++++++ .../framework/game/players/OnlinePlayer.java | 51 +++ .../framework/game/players/ServerPlayer.java | 41 +++ .../framework/game/players/ai/MiniMaxAI.java | 0 .../framework/gameFramework/GameState.java | 6 +- .../controller/GameController.java | 13 +- .../controller/UpdatesGameUI.java | 10 - .../model/game/BoardProvider.java | 5 - .../gameFramework/model/game/Playable.java | 24 -- .../model/game/PlayerProvider.java | 7 - .../model/game/TurnBasedGame.java | 11 +- .../AbstractThreadBehaviour.java | 7 +- .../game/threadBehaviour/Controllable.java | 7 - .../SupportsOnlinePlay.java | 4 +- .../game/threadBehaviour/ThreadBehaviour.java | 5 +- .../gameFramework/model/player/AI.java | 3 +- .../model/player/AbstractAI.java | 2 +- .../model/player/AbstractPlayer.java | 30 +- .../model/player/MoveProvider.java | 7 - .../model/player/NameProvider.java | 5 - .../gameFramework/model/player/Player.java | 4 +- .../NetworkingClientEventListener.java | 8 +- .../NetworkingClientManager.java | 14 +- .../clients/TournamentNetworkingClient.java | 12 +- .../events/NetworkEvents.java | 8 +- .../exceptions/ClientNotFoundException.java | 2 +- .../exceptions/CouldNotConnectException.java | 2 +- .../NetworkingInitializationException.java | 2 +- .../handlers/NetworkingGameClientHandler.java | 4 +- .../interfaces/NetworkingClient.java | 4 +- .../interfaces/NetworkingClientManager.java | 8 +- .../types/NetworkingConnector.java | 2 +- .../{ => connection}/types/ServerCommand.java | 2 +- .../connection/types/ServerMessage.java | 3 + .../networking/server/GameServer.java | 22 ++ .../networking/server/OnlineGame.java | 10 + .../server/OnlineTurnBasedGame.java | 67 ++++ .../framework/networking/server/Server.java | 263 ++++++++++++++ .../gamechallenge/GameChallenge.java | 49 +++ .../gamechallenge/GameChallengeTimer.java | 35 ++ .../networking/server/client/Client.java | 19 + .../networking/server/client/NettyClient.java | 66 ++++ .../connectionHandler/ClientSession.java | 7 + .../connectionHandler/NettyClientSession.java | 58 ++++ .../server/gateway/GatewayServer.java | 7 + .../server/gateway/NettyGatewayServer.java | 111 ++++++ .../networking/server/handlers/Handler.java | 5 + .../server/handlers/MessageHandler.java | 110 ++++++ .../server/parsing/ParsedMessage.java | 4 + .../networking/server/parsing/Parser.java | 24 ++ .../networking/server/stores/ClientStore.java | 7 + .../networking/server/stores/GameStore.java | 3 + .../server/stores/MapSubscriptionStore.java | 71 ++++ .../server/stores/NettyClientStore.java | 34 ++ .../networking/server/stores/Store.java | 10 + .../server/stores/SubscriptionStore.java | 10 + .../server/stores/TurnBasedGameStore.java | 36 ++ .../server/stores/TurnBasedGameTypeStore.java | 32 ++ .../networking/types/ServerMessage.java | 3 - .../toop/framework/utils/ImmutablePair.java | 21 ++ .../org/toop/framework/utils/MutablePair.java | 29 ++ .../java/org/toop/framework/utils/Pair.java | 6 + .../org/toop/framework/utils/SimpleTimer.java | 7 + .../java/org/toop/framework/utils/Utils.java | 11 + .../NetworkingClientManagerTest.java | 2 +- .../events/NetworkEventsTest.java | 2 +- .../networking/server/ServerTest.java | 167 +++++++++ .../networking/server/servertests.ps1 | 17 + .../game/games/reversi/BitboardReversi.java | 170 --------- .../org/toop/game/players/LocalPlayer.java | 86 ----- .../org/toop/game/players/OnlinePlayer.java | 36 -- .../java/org/toop/game/players/ai/MCTSAI.java | 193 +++++++++++ .../org/toop/game/players/ai/MCTSAI2.java | 195 +++++++++++ .../org/toop/game/players/ai/MCTSAI3.java | 258 ++++++++++++++ .../toop/game/players/{ => ai}/MiniMaxAI.java | 22 +- .../toop/game/players/{ => ai}/RandomAI.java | 10 +- 114 files changed, 3173 insertions(+), 671 deletions(-) delete mode 100644 app/src/main/java/org/toop/app/canvas/GameDrawer.java create mode 100644 app/src/main/java/org/toop/app/widget/complex/TableWidget.java rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/BitboardGame.java (58%) rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/Move.java (77%) rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/LocalFixedRateThreadBehaviour.java (90%) rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/LocalThreadBehaviour.java (89%) rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/OnlineThreadBehaviour.java (62%) rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/OnlineWithSleepThreadBehaviour.java (77%) create mode 100644 framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java create mode 100644 framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/games/tictactoe/BitboardTicTacToe.java (79%) rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/players/ArtificialPlayer.java (74%) create mode 100644 framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java create mode 100644 framework/src/main/java/org/toop/framework/game/players/OnlinePlayer.java create mode 100644 framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java create mode 100644 framework/src/main/java/org/toop/framework/game/players/ai/MiniMaxAI.java delete mode 100644 framework/src/main/java/org/toop/framework/gameFramework/controller/UpdatesGameUI.java delete mode 100644 framework/src/main/java/org/toop/framework/gameFramework/model/game/BoardProvider.java delete mode 100644 framework/src/main/java/org/toop/framework/gameFramework/model/game/Playable.java delete mode 100644 framework/src/main/java/org/toop/framework/gameFramework/model/game/PlayerProvider.java delete mode 100644 framework/src/main/java/org/toop/framework/gameFramework/model/game/threadBehaviour/Controllable.java rename framework/src/main/java/org/toop/framework/gameFramework/model/game/{ => threadBehaviour}/SupportsOnlinePlay.java (81%) delete mode 100644 framework/src/main/java/org/toop/framework/gameFramework/model/player/MoveProvider.java delete mode 100644 framework/src/main/java/org/toop/framework/gameFramework/model/player/NameProvider.java rename framework/src/main/java/org/toop/framework/networking/{ => connection}/NetworkingClientEventListener.java (96%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/NetworkingClientManager.java (90%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/clients/TournamentNetworkingClient.java (88%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/events/NetworkEvents.java (96%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/exceptions/ClientNotFoundException.java (91%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/exceptions/CouldNotConnectException.java (89%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/exceptions/NetworkingInitializationException.java (76%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/handlers/NetworkingGameClientHandler.java (98%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/interfaces/NetworkingClient.java (66%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/interfaces/NetworkingClientManager.java (57%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/types/NetworkingConnector.java (73%) rename framework/src/main/java/org/toop/framework/networking/{ => connection}/types/ServerCommand.java (52%) create mode 100644 framework/src/main/java/org/toop/framework/networking/connection/types/ServerMessage.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/GameServer.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/Server.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallenge.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallengeTimer.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/client/Client.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/connectionHandler/ClientSession.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/connectionHandler/NettyClientSession.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/gateway/GatewayServer.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/gateway/NettyGatewayServer.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/handlers/Handler.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/parsing/ParsedMessage.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/parsing/Parser.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/ClientStore.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/GameStore.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/MapSubscriptionStore.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/NettyClientStore.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/Store.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/SubscriptionStore.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameStore.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameTypeStore.java delete mode 100644 framework/src/main/java/org/toop/framework/networking/types/ServerMessage.java create mode 100644 framework/src/main/java/org/toop/framework/utils/ImmutablePair.java create mode 100644 framework/src/main/java/org/toop/framework/utils/MutablePair.java create mode 100644 framework/src/main/java/org/toop/framework/utils/Pair.java create mode 100644 framework/src/main/java/org/toop/framework/utils/SimpleTimer.java create mode 100644 framework/src/main/java/org/toop/framework/utils/Utils.java rename framework/src/test/java/org/toop/framework/networking/{ => connection}/events/NetworkEventsTest.java (99%) create mode 100644 framework/src/test/java/org/toop/framework/networking/server/ServerTest.java create mode 100644 framework/src/test/java/org/toop/framework/networking/server/servertests.ps1 delete mode 100644 game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java delete mode 100644 game/src/main/java/org/toop/game/players/LocalPlayer.java delete mode 100644 game/src/main/java/org/toop/game/players/OnlinePlayer.java create mode 100644 game/src/main/java/org/toop/game/players/ai/MCTSAI.java create mode 100644 game/src/main/java/org/toop/game/players/ai/MCTSAI2.java create mode 100644 game/src/main/java/org/toop/game/players/ai/MCTSAI3.java rename game/src/main/java/org/toop/game/players/{ => ai}/MiniMaxAI.java (89%) rename game/src/main/java/org/toop/game/players/{ => ai}/RandomAI.java (78%) diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java index 3b4fef3..bd330d2 100644 --- a/app/src/main/java/org/toop/Main.java +++ b/app/src/main/java/org/toop/Main.java @@ -4,6 +4,50 @@ import org.toop.app.App; public final class Main { static void main(String[] args) { - App.run(args); + App.run(args); + // testMCTS(10); } + + // Voor onderzoek + // private static void testMCTS(int games) { + // var random = new ArtificialPlayer<>(new RandomAI(), "Random AI"); + // var v1 = new ArtificialPlayer<>(new MCTSAI(10), "MCTS V1 AI"); + // var v2 = new ArtificialPlayer<>(new MCTSAI2(10), "MCTS V2 AI"); + // var v2_2 = new ArtificialPlayer<>(new MCTSAI2(100), "MCTS V2_2 AI"); + // var v3 = new ArtificialPlayer<>(new MCTSAI3(10), "MCTS V3 AI"); + + // testAI(games, new Player[]{ v1, v2 }); + // // testAI(games, new Player[]{ v1, v3 }); + + // // testAI(games, new Player[]{ random, v3 }); + // // testAI(games, new Player[]{ v2, v3 }); + // testAI(games, new Player[]{ v2, v3 }); + // // testAI(games, new Player[]{ v3, v2 }); + // } + + // private static void testAI(int games, Player[] ais) { + // int wins = 0; + // int ties = 0; + + // for (int i = 0; i < games; i++) { + // final BitboardReversi match = new BitboardReversi(ais); + + // while (!match.isTerminal()) { + // final int currentAI = match.getCurrentTurn(); + // final long move = ais[currentAI].getMove(match); + + // match.play(move); + // } + + // if (match.getWinner() < 0) { + // ties++; + // continue; + // } + + // wins += match.getWinner() == 0? 1 : 0; + // } + + // System.out.printf("Out of %d games, %s won %d -- tied %d -- lost %d, games against %s\n", games, ais[0].getName(), wins, ties, games - wins - ties, ais[1].getName()); + // System.out.printf("Average win rate was: %.2f\n\n", wins / (float)games); + // } } diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java index 5d99acd..9645cd5 100644 --- a/app/src/main/java/org/toop/app/App.java +++ b/app/src/main/java/org/toop/app/App.java @@ -1,10 +1,14 @@ package org.toop.app; +import javafx.application.Application; import javafx.application.Platform; +import javafx.geometry.Pos; +import javafx.scene.Scene; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyEvent; - +import javafx.scene.layout.StackPane; +import javafx.stage.Stage; import org.toop.app.widget.Primitive; import org.toop.app.widget.WidgetContainer; import org.toop.app.widget.complex.LoadingWidget; @@ -16,8 +20,8 @@ import org.toop.framework.audio.*; import org.toop.framework.audio.events.AudioEvents; import org.toop.framework.eventbus.EventFlow; import org.toop.framework.eventbus.GlobalEventBus; -import org.toop.framework.networking.NetworkingClientEventListener; -import org.toop.framework.networking.NetworkingClientManager; +import org.toop.framework.networking.connection.NetworkingClientEventListener; +import org.toop.framework.networking.connection.NetworkingClientManager; import org.toop.framework.resource.ResourceLoader; import org.toop.framework.resource.ResourceManager; import org.toop.framework.resource.events.AssetLoaderEvents; @@ -27,12 +31,6 @@ import org.toop.framework.resource.resources.SoundEffectAsset; import org.toop.local.AppContext; import org.toop.local.AppSettings; -import javafx.application.Application; -import javafx.geometry.Pos; -import javafx.scene.Scene; -import javafx.scene.layout.StackPane; -import javafx.stage.Stage; - import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -86,7 +84,7 @@ public final class App extends Application { AppSettings.applySettings(); - setKeybinds(root); + setKeybinds(root); LoadingWidget loading = new LoadingWidget(Primitive.text( "Loading...", false), 0, 0, Integer.MAX_VALUE, false, false // Just set a high default @@ -94,7 +92,7 @@ public final class App extends Application { WidgetContainer.setCurrentView(loading); - setOnLoadingSuccess(loading); + setOnLoadingSuccess(loading); EventFlow loadingFlow = new EventFlow(); @@ -137,13 +135,12 @@ public final class App extends Application { } stage.show(); - - } + } private void setKeybinds(StackPane root) { root.addEventHandler(KeyEvent.KEY_PRESSED,event -> { if (event.getCode() == KeyCode.ESCAPE) { - escapePopup(); + escapePopup(); } }); stage.setFullScreenExitKeyCombination( diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index ef691b4..f6bcdec 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -11,17 +11,15 @@ import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.popup.SendChallengePopup; import org.toop.app.widget.view.ServerView; import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.game.players.OnlinePlayer; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.eventbus.GlobalEventBus; import org.toop.framework.gameFramework.model.player.Player; -import org.toop.framework.networking.clients.TournamentNetworkingClient; -import org.toop.framework.networking.events.NetworkEvents; -import org.toop.framework.networking.types.NetworkingConnector; -import org.toop.game.games.reversi.BitboardReversi; -import org.toop.game.games.tictactoe.BitboardTicTacToe; -import org.toop.game.players.ArtificialPlayer; -import org.toop.game.players.OnlinePlayer; -import org.toop.game.players.RandomAI; +import org.toop.framework.networking.connection.clients.TournamentNetworkingClient; +import org.toop.framework.networking.connection.events.NetworkEvents; +import org.toop.framework.networking.connection.types.NetworkingConnector; +import org.toop.framework.networking.server.gateway.NettyGatewayServer; +import org.toop.framework.game.players.LocalPlayer; import org.toop.local.AppContext; import java.util.List; @@ -32,7 +30,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; public final class Server { - // TODO: Keep track of listeners. Remove them on Server connection close so reference is deleted. + private NettyGatewayServer nettyGatewayServer; + private String user = ""; private long clientId = -1; @@ -60,10 +59,13 @@ public final class Server { return null; } + public Server(String ip, String port, String user) { + this(ip, port, user, null); + } // Server has to deal with ALL network related listen events. This "server" can then interact with the manager to make stuff happen. // This prevents data races where events get sent to the game manager but the manager isn't ready yet. - public Server(String ip, String port, String user) { + public Server(String ip, String port, String user, NettyGatewayServer nettyGatewayServer) { if (ip.split("\\.").length < 4) { new ErrorPopup("\"" + ip + "\" " + AppContext.getString("is-not-a-valid-ip-address")); return; @@ -83,6 +85,8 @@ public final class Server { return; } + this.nettyGatewayServer = nettyGatewayServer; + final int reconnectAttempts = 10; LoadingWidget loading = new LoadingWidget( @@ -113,7 +117,7 @@ public final class Server { return; } - primary = new ServerView(user, this::sendChallenge); + primary = new ServerView(user, this::sendChallenge, clientId); WidgetContainer.getCurrentView().transitionNextCustom(primary, "disconnect", this::disconnect); a.unsubscribe("connecting"); @@ -154,7 +158,8 @@ public final class Server { .listen(NetworkEvents.GameMatchResponse.class, this::handleMatchResponse, false, "match-response") .listen(NetworkEvents.GameResultResponse.class, this::handleGameResult, false, "game-result") .listen(NetworkEvents.GameMoveResponse.class, this::handleReceivedMove, false, "game-move") - .listen(NetworkEvents.YourTurnResponse.class, this::handleYourTurn, false, "your-turn"); + .listen(NetworkEvents.YourTurnResponse.class, this::handleYourTurn, false, "your-turn") + .listen(NetworkEvents.ClosedConnection.class, this::closedConnection, false, "closed-connection"); connectFlow = a; } @@ -178,7 +183,7 @@ public final class Server { gameController = null; - //if (!isPolling) return; +// if (!isPolling) return; String gameType = extractQuotedValue(response.gameType()); if (response.clientId() == clientId) { @@ -191,45 +196,29 @@ public final class Server { return; } - final int myTurn = response.playerToMove().equalsIgnoreCase(response.opponent()) ? 1 : 0; + final String startingPlayer = response.playerToMove(); + final int userStartingTurn = startingPlayer.equalsIgnoreCase(user) ? 0 : 1; + final int opponentStartingTurn = 1 - userStartingTurn; final GameInformation information = new GameInformation(type); - //information.players[0] = playerInformation; - information.players[0].name = user; - information.players[0].isHuman = false; - information.players[0].computerDifficulty = 5; - information.players[0].computerThinkTime = 1; - information.players[1].name = response.opponent(); - - /*switch (type){ - case TICTACTOE ->{ - players[myTurn] = new ArtificialPlayer<>(new TicTacToeAIR(9), user); - } - case REVERSI ->{ - players[myTurn] = new ArtificialPlayer<>(new ReversiAIR(), user); - } - }*/ - + information.players[userStartingTurn].name = user; + information.players[opponentStartingTurn].name = response.opponent(); + Player[] players = new Player[2]; + players[userStartingTurn] = new LocalPlayer(user); + players[opponentStartingTurn] = new OnlinePlayer(response.opponent()); switch (type) { - case TICTACTOE ->{ - Player[] players = new Player[2]; - players[(myTurn + 1) % 2] = new OnlinePlayer<>(response.opponent()); - players[myTurn] = new ArtificialPlayer<>(new RandomAI(), user); - gameController = new TicTacToeBitController(players); - } - case REVERSI -> { - Player[] players = new Player[2]; - players[(myTurn + 1) % 2] = new OnlinePlayer<>(response.opponent()); - players[myTurn] = new ArtificialPlayer<>(new RandomAI(), user); - gameController = new ReversiBitController(players);} + case TICTACTOE -> gameController = new TicTacToeBitController(players); + case REVERSI -> gameController = new ReversiBitController(players); default -> new ErrorPopup("Unsupported game type."); } - if (gameController != null){ + if (gameController != null) { + primary.reEnableButton(); // Re enable subscribe button gameController.start(); + isPolling = true; // Fixes server getting stuck } } } @@ -263,7 +252,7 @@ public final class Server { String gameType = extractQuotedValue(response.gameType()); final String finalGameType = gameType; var a = new ChallengePopup(challengerName, gameType, (playerInformation) -> { - final int challengeId = Integer.parseInt(response.challengeId().replaceAll("\\D", "")); + final long challengeId = Long.parseLong(response.challengeId().replaceAll("\\D", "")); new EventFlow().addPostEvent(new NetworkEvents.SendAcceptChallenge(clientId, challengeId)).postEvent(); isSingleGame.set(true); }); @@ -281,9 +270,27 @@ public final class Server { stopScheduler(); connectFlow.unsubscribeAll(); + if (nettyGatewayServer != null) { + nettyGatewayServer.stop(); + } + WidgetContainer.getCurrentView().transitionPrevious(); } + private void closedConnection(NetworkEvents.ClosedConnection e) { + new EventFlow().addPostEvent(new NetworkEvents.CloseClient(clientId)).postEvent(); + isPolling = false; + stopScheduler(); + connectFlow.unsubscribeAll(); + + if (nettyGatewayServer != null) { + nettyGatewayServer.stop(); + } + + WidgetContainer.getCurrentView().transitionPrevious(); + WidgetContainer.add(Pos.CENTER, new ErrorPopup("Server closed connection.")); + } + private void forfeitGame() { new EventFlow().addPostEvent(new NetworkEvents.SendForfeit(clientId)).postEvent(); } @@ -330,7 +337,9 @@ public final class Server { private void gamesListFromServerHandler(NetworkEvents.GamelistResponse event) { gameList.clear(); - gameList.addAll(List.of(event.gamelist())); + var gl = List.of(event.gamelist()); + gameList.addAll(gl); + primary.updateGameList(gl); } public void populateGameList() { diff --git a/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java b/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java index 85c6f7d..b441f44 100644 --- a/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java @@ -14,7 +14,7 @@ import org.toop.framework.gameFramework.view.GUIEvents; import java.util.function.Consumer; -public abstract class BitGameCanvas> implements GameCanvas { +public abstract class BitGameCanvas implements GameCanvas { protected record Cell(float x, float y, float width, float height) { public boolean isInside(double x, double y) { return x >= this.x && x <= this.x + width && @@ -78,6 +78,7 @@ public abstract class BitGameCanvas> implements GameC } canvas.setOnMouseClicked(event -> { + if (event.getButton() != MouseButton.PRIMARY) { return; } @@ -93,9 +94,6 @@ public abstract class BitGameCanvas> implements GameC } }); - - - render(); } diff --git a/app/src/main/java/org/toop/app/canvas/GameCanvas.java b/app/src/main/java/org/toop/app/canvas/GameCanvas.java index d1361c5..e3826df 100644 --- a/app/src/main/java/org/toop/app/canvas/GameCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/GameCanvas.java @@ -3,6 +3,7 @@ package org.toop.app.canvas; import javafx.scene.canvas.Canvas; import org.toop.framework.gameFramework.model.game.TurnBasedGame; -public interface GameCanvas> extends GameDrawer{ +public interface GameCanvas { Canvas getCanvas(); + void redraw(TurnBasedGame gameCopy); } diff --git a/app/src/main/java/org/toop/app/canvas/GameDrawer.java b/app/src/main/java/org/toop/app/canvas/GameDrawer.java deleted file mode 100644 index 261334c..0000000 --- a/app/src/main/java/org/toop/app/canvas/GameDrawer.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.toop.app.canvas; - -import org.toop.framework.gameFramework.model.game.TurnBasedGame; - -public interface GameDrawer> { - void redraw(T gameCopy); -} diff --git a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java index 7c2bde0..685a985 100644 --- a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java @@ -2,12 +2,9 @@ package org.toop.app.canvas; import javafx.scene.paint.Color; import org.toop.app.App; -import org.toop.game.games.reversi.BitboardReversi; +import org.toop.framework.gameFramework.model.game.TurnBasedGame; -import java.util.Arrays; -import java.util.function.Consumer; - -public class ReversiBitCanvas extends BitGameCanvas { +public class ReversiBitCanvas extends BitGameCanvas { public ReversiBitCanvas() { super(Color.GRAY, new Color(0f, 0.4f, 0.2f, 1f), (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, 8, 8, 5, true); canvas.setOnMouseMoved(event -> { @@ -33,7 +30,7 @@ public class ReversiBitCanvas extends BitGameCanvas { } @Override - public void redraw(BitboardReversi gameCopy) { + public void redraw(TurnBasedGame gameCopy) { clearAll(); long[] board = gameCopy.getBoard(); loopOverBoard(board[0], (i) -> drawDot(Color.WHITE, i)); diff --git a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java index 443adbd..7c9b5b4 100644 --- a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java @@ -2,12 +2,9 @@ package org.toop.app.canvas; import javafx.scene.paint.Color; import org.toop.app.App; -import org.toop.game.games.tictactoe.BitboardTicTacToe; +import org.toop.framework.gameFramework.model.game.TurnBasedGame; -import java.util.Arrays; -import java.util.function.Consumer; - -public class TicTacToeBitCanvas extends BitGameCanvas{ +public class TicTacToeBitCanvas extends BitGameCanvas{ public TicTacToeBitCanvas() { super( Color.GRAY, @@ -22,7 +19,7 @@ public class TicTacToeBitCanvas extends BitGameCanvas{ } @Override - public void redraw(BitboardTicTacToe gameCopy) { + public void redraw(TurnBasedGame gameCopy) { clearAll(); drawMoves(gameCopy.getBoard()); } diff --git a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java index 2c3ad49..0c68a74 100644 --- a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java +++ b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java @@ -10,15 +10,15 @@ import org.toop.app.widget.view.GameView; import org.toop.framework.eventbus.EventFlow; import org.toop.framework.eventbus.GlobalEventBus; import org.toop.framework.gameFramework.controller.GameController; -import org.toop.framework.gameFramework.model.game.SupportsOnlinePlay; +import org.toop.framework.gameFramework.model.game.threadBehaviour.SupportsOnlinePlay; import org.toop.framework.gameFramework.model.game.TurnBasedGame; import org.toop.framework.gameFramework.model.game.threadBehaviour.ThreadBehaviour; import org.toop.framework.gameFramework.model.player.Player; import org.toop.framework.gameFramework.view.GUIEvents; -import org.toop.framework.networking.events.NetworkEvents; -import org.toop.game.players.LocalPlayer; +import org.toop.framework.networking.connection.events.NetworkEvents; +import org.toop.framework.game.players.LocalPlayer; -public class GenericGameController> implements GameController { +public class GenericGameController implements GameController { protected final EventFlow eventFlow = new EventFlow(); // Logger for logging @@ -28,21 +28,23 @@ public class GenericGameController> implements GameCo protected final GameView gameView; // Reference to game canvas - protected final GameCanvas canvas; + protected final GameCanvas canvas; - protected final TurnBasedGame game; // Reference to game instance + protected final TurnBasedGame game; // Reference to game instance private final ThreadBehaviour gameThreadBehaviour; // TODO: Change gameType to automatically happen with either dependency injection or something else. - public GenericGameController(GameCanvas canvas, T game, ThreadBehaviour gameThreadBehaviour, String gameType) { - logger.info("Creating: " + this.getClass()); + public GenericGameController(GameCanvas canvas, TurnBasedGame game, ThreadBehaviour gameThreadBehaviour, String gameType) { + logger.info("Creating: {}", this.getClass()); this.canvas = canvas; this.game = game; this.gameThreadBehaviour = gameThreadBehaviour; // Tell thread how to send moves - this.gameThreadBehaviour.setOnSendMove((id, m) -> GlobalEventBus.get().post(new NetworkEvents.SendMove(id, (short)translateMove(m)))); + this.gameThreadBehaviour.setOnSendMove( + (id, m) -> GlobalEventBus.get().post(new NetworkEvents.SendMove(id, (short)translateMove(m))) + ); // Tell thread how to update UI this.gameThreadBehaviour.setOnUpdateUI(() -> Platform.runLater(this::updateUI)); @@ -53,24 +55,40 @@ public class GenericGameController> implements GameCo WidgetContainer.getCurrentView().transitionNext(gameView, true); // Listen to updates + logger.info("Game controller started listening"); eventFlow .listen(GUIEvents.GameEnded.class, this::onGameFinish, false) - .listen(GUIEvents.PlayerAttemptedMove.class, event -> {if (getCurrentPlayer() instanceof LocalPlayer lp){lp.setMove(event.move());}}, false); + .listen(GUIEvents.PlayerAttemptedMove.class, event -> { + logger.info("User attempting move {}", event.move()); + logger.info("Current player's turn {}", getCurrentPlayer().getName()); + logger.info("First player {}", game.getPlayer(0).getName()); + logger.info("Username {}", getCurrentPlayer().getName()); + logger.info("User is class {}, {}", getCurrentPlayer().getClass(), getCurrentPlayer() instanceof LocalPlayer); + if (getCurrentPlayer() instanceof LocalPlayer lp) { + try { + lp.setLastMove(event.move()); + } catch (Exception e) { + IO.println(e); + } + } + }, false); } public void start(){ logger.info("Starting GameManager"); updateUI(); gameThreadBehaviour.start(); + logger.info("GameManager started"); } public void stop(){ logger.info("Stopping GameManager"); removeListeners(); gameThreadBehaviour.stop(); + logger.info("GameManager stopped"); } - public Player getCurrentPlayer(){ + public Player getCurrentPlayer(){ return game.getPlayer(getCurrentPlayerIndex()); } @@ -91,14 +109,14 @@ public class GenericGameController> implements GameCo } private void onGameFinish(GUIEvents.GameEnded event){ - logger.info("Game Finished"); + logger.info("OnlineTurnBasedGame Finished"); String name = event.winner() == -1 ? null : getPlayer(event.winner()).getName(); gameView.gameOver(event.winOrTie(), name); stop(); } - public Player getPlayer(int player){ - if (player < 0 || player >= 2){ // TODO: Make game turn player count + public Player getPlayer(int player){ + if (player < 0 || player > game.getPlayerCount()-1){ // TODO: Make game turn player count logger.error("Invalid player index"); throw new IllegalArgumentException("player out of range"); } diff --git a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java index 40784b0..1ea8109 100644 --- a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java +++ b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java @@ -3,20 +3,21 @@ package org.toop.app.gameControllers; import org.toop.app.canvas.ReversiBitCanvas; import org.toop.framework.gameFramework.model.game.threadBehaviour.ThreadBehaviour; import org.toop.framework.gameFramework.model.player.Player; -import org.toop.game.gameThreads.LocalThreadBehaviour; -import org.toop.game.gameThreads.OnlineThreadBehaviour; -import org.toop.game.games.reversi.BitboardReversi; -import org.toop.game.players.OnlinePlayer; +import org.toop.framework.game.gameThreads.LocalThreadBehaviour; +import org.toop.framework.game.gameThreads.OnlineThreadBehaviour; +import org.toop.framework.game.games.reversi.BitboardReversi; +import org.toop.framework.game.players.OnlinePlayer; + +import java.util.Arrays; + +public class ReversiBitController extends GenericGameController { + public ReversiBitController(Player[] players) { + BitboardReversi game = new BitboardReversi(); + game.init(players); + + ThreadBehaviour thread = Arrays.stream(players).anyMatch(e -> e instanceof OnlinePlayer) ? + new OnlineThreadBehaviour(game) : new LocalThreadBehaviour(game); -public class ReversiBitController extends GenericGameController { - public ReversiBitController(Player[] players) { - BitboardReversi game = new BitboardReversi(players); - ThreadBehaviour thread = new LocalThreadBehaviour<>(game); - for (Player player : players) { - if (player instanceof OnlinePlayer){ - thread = new OnlineThreadBehaviour<>(game); - } - } super(new ReversiBitCanvas(), game, thread, "Reversi"); } } diff --git a/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java b/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java index 6307894..8315249 100644 --- a/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java +++ b/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java @@ -3,21 +3,21 @@ package org.toop.app.gameControllers; import org.toop.app.canvas.TicTacToeBitCanvas; import org.toop.framework.gameFramework.model.game.threadBehaviour.ThreadBehaviour; import org.toop.framework.gameFramework.model.player.Player; -import org.toop.game.gameThreads.LocalFixedRateThreadBehaviour; -import org.toop.game.gameThreads.LocalThreadBehaviour; -import org.toop.game.gameThreads.OnlineThreadBehaviour; -import org.toop.game.games.tictactoe.BitboardTicTacToe; -import org.toop.game.players.OnlinePlayer; +import org.toop.framework.game.gameThreads.LocalThreadBehaviour; +import org.toop.framework.game.gameThreads.OnlineThreadBehaviour; +import org.toop.framework.game.games.tictactoe.BitboardTicTacToe; +import org.toop.framework.game.players.OnlinePlayer; -public class TicTacToeBitController extends GenericGameController { - public TicTacToeBitController(Player[] players) { - BitboardTicTacToe game = new BitboardTicTacToe(players); - ThreadBehaviour thread = new LocalThreadBehaviour<>(game); - for (Player player : players) { - if (player instanceof OnlinePlayer){ - thread = new OnlineThreadBehaviour<>(game); - } - } - super(new TicTacToeBitCanvas(), game, thread , "TicTacToe"); +import java.util.Arrays; + +public class TicTacToeBitController extends GenericGameController { + public TicTacToeBitController(Player[] players) { + BitboardTicTacToe game = new BitboardTicTacToe(); + game.init(players); + + ThreadBehaviour thread = Arrays.stream(players).anyMatch(e -> e instanceof OnlinePlayer) ? + new OnlineThreadBehaviour(game) : new LocalThreadBehaviour(game); + + super(new TicTacToeBitCanvas(), game, thread, "TicTacToe"); } } diff --git a/app/src/main/java/org/toop/app/widget/Primitive.java b/app/src/main/java/org/toop/app/widget/Primitive.java index afb59a2..a8436c5 100644 --- a/app/src/main/java/org/toop/app/widget/Primitive.java +++ b/app/src/main/java/org/toop/app/widget/Primitive.java @@ -64,7 +64,7 @@ public final class Primitive { return imageView; } - public static Button button(String key, Runnable onAction, boolean localize) { + public static Button button(String key, Runnable onAction, boolean localize, boolean disableOnClick) { var button = new Button(); button.getStyleClass().add("button"); @@ -75,6 +75,7 @@ public final class Primitive { if (onAction != null) { button.setOnAction(_ -> { + if (disableOnClick) button.setDisable(true); onAction.run(); playButtonSound(); }); @@ -83,8 +84,8 @@ public final class Primitive { return button; } - public static Button button(String key, Runnable onAction) { - return button(key, onAction, true); + public static Button button(String key, Runnable onAction, boolean disableOnClick) { + return button(key, onAction, true, disableOnClick); } public static TextField input(String promptKey, String text, Consumer onValueChanged, boolean localize) { diff --git a/app/src/main/java/org/toop/app/widget/complex/ConfirmWidget.java b/app/src/main/java/org/toop/app/widget/complex/ConfirmWidget.java index e8719ce..1d6251d 100644 --- a/app/src/main/java/org/toop/app/widget/complex/ConfirmWidget.java +++ b/app/src/main/java/org/toop/app/widget/complex/ConfirmWidget.java @@ -26,7 +26,7 @@ public class ConfirmWidget implements Widget { public void addButton(String key, Runnable onClick) { Platform.runLater(() -> { - var button = Primitive.button(key, onClick); + var button = Primitive.button(key, onClick, false); buttonsContainer.getChildren().add(button); }); } diff --git a/app/src/main/java/org/toop/app/widget/complex/PlayerInfoWidget.java b/app/src/main/java/org/toop/app/widget/complex/PlayerInfoWidget.java index 97a1140..fe1cf52 100644 --- a/app/src/main/java/org/toop/app/widget/complex/PlayerInfoWidget.java +++ b/app/src/main/java/org/toop/app/widget/complex/PlayerInfoWidget.java @@ -91,7 +91,7 @@ public class PlayerInfoWidget { information.computerDifficulty = depth; information.computerThinkTime = thinktime; this.playerName.setText(getName(name)); - }); + }, false); } private String getName(String name) { diff --git a/app/src/main/java/org/toop/app/widget/complex/TableWidget.java b/app/src/main/java/org/toop/app/widget/complex/TableWidget.java new file mode 100644 index 0000000..8c0c2ae --- /dev/null +++ b/app/src/main/java/org/toop/app/widget/complex/TableWidget.java @@ -0,0 +1,61 @@ +package org.toop.app.widget.complex; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; + +import java.util.ArrayList; +import java.util.List; + +public class TableWidget extends PopupWidget { + private ObservableList serverList = FXCollections.observableArrayList(); + private TableView table = new TableView<>(); + + + public TableWidget(String... columns) { + var cols = new ArrayList>(); + + for (String column : columns) { + TableColumn col = new TableColumn<>(column.toUpperCase()); + col.setCellValueFactory(new PropertyValueFactory<>(column)); + cols.add(col); + } + + table.getColumns().addAll(cols); + update(); + onColumnClicked(); + + add(Pos.CENTER, table); + } + + public void add(DATATYPE serverFound) { + serverList.add(serverFound); + update(); + } + + public void add(List serverFound) { + serverList.addAll(serverFound); + } + + public void remove(DATATYPE serverFound) { + serverList.remove(serverFound); + update(); + } + + public void onColumnClicked() { + table.setOnMouseClicked(event -> { + DATATYPE selected = table.getSelectionModel().getSelectedItem(); + if (selected == null) return; + IO.println(selected.toString()); + }); + } + + private void update() { + table.setItems(serverList); + } + + +} diff --git a/app/src/main/java/org/toop/app/widget/complex/ViewWidget.java b/app/src/main/java/org/toop/app/widget/complex/ViewWidget.java index 217ac86..c280b1c 100644 --- a/app/src/main/java/org/toop/app/widget/complex/ViewWidget.java +++ b/app/src/main/java/org/toop/app/widget/complex/ViewWidget.java @@ -32,7 +32,7 @@ public abstract class ViewWidget extends StackWidget { var backButton = Primitive.button("back", () -> { view.transitionPrevious(); - }); + }, false); view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton)); } @@ -45,7 +45,7 @@ public abstract class ViewWidget extends StackWidget { var customButton = Primitive.button(key, () -> { runnable.run(); view.transitionPrevious(); - }); + }, false); view.add(Pos.BOTTOM_LEFT, Primitive.vbox(customButton)); } @@ -97,7 +97,7 @@ public abstract class ViewWidget extends StackWidget { var backButton = Primitive.button("back", () -> { view.transitionPrevious(); - }); + }, false); view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton)); } diff --git a/app/src/main/java/org/toop/app/widget/popup/ChallengePopup.java b/app/src/main/java/org/toop/app/widget/popup/ChallengePopup.java index cd4d87c..e20730c 100644 --- a/app/src/main/java/org/toop/app/widget/popup/ChallengePopup.java +++ b/app/src/main/java/org/toop/app/widget/popup/ChallengePopup.java @@ -37,8 +37,8 @@ public final class ChallengePopup extends PopupWidget { var acceptButton = Primitive.button("accept", () -> { onAccept.accept(playerInformation); this.hide(); - }); - var denyButton = Primitive.button("deny", () -> hide()); + }, false); + var denyButton = Primitive.button("deny", () -> hide(), false); var leftSection = Primitive.vbox( challengeText, diff --git a/app/src/main/java/org/toop/app/widget/popup/EscapePopup.java b/app/src/main/java/org/toop/app/widget/popup/EscapePopup.java index d742ab6..5b4acd5 100644 --- a/app/src/main/java/org/toop/app/widget/popup/EscapePopup.java +++ b/app/src/main/java/org/toop/app/widget/popup/EscapePopup.java @@ -18,13 +18,13 @@ public class EscapePopup extends PopupWidget { ViewWidget currentView = WidgetContainer.getCurrentView(); ArrayList nodes = new ArrayList<>(); - nodes.add(Primitive.button("Continue", this::hide, false)); // TODO, localize + nodes.add(Primitive.button("Continue", this::hide, false, false)); // TODO, localize if (!(currentView.getClass().isAssignableFrom(OptionsView.class))) { var opt = Primitive.button("options", () -> { hide(); WidgetContainer.getCurrentView().transitionNext(new OptionsView()); - }); + }, false); nodes.add(opt); } @@ -33,14 +33,14 @@ public class EscapePopup extends PopupWidget { if (tut != null) { nodes.add(Primitive.button("tutorialstring", () -> { WidgetContainer.getCurrentView().add(Pos.CENTER, tut); - })); + }, false)); } } nodes.add(Primitive.button("quit", () -> { hide(); WidgetContainer.add(Pos.CENTER, new QuitPopup()); - })); + }, false)); add(Pos.CENTER, Primitive.vbox(nodes.toArray(new Node[0]))); diff --git a/app/src/main/java/org/toop/app/widget/popup/SendChallengePopup.java b/app/src/main/java/org/toop/app/widget/popup/SendChallengePopup.java index bc42486..c5bfa7d 100644 --- a/app/src/main/java/org/toop/app/widget/popup/SendChallengePopup.java +++ b/app/src/main/java/org/toop/app/widget/popup/SendChallengePopup.java @@ -62,9 +62,9 @@ public final class SendChallengePopup extends PopupWidget { var sendButton = Primitive.button( "send", () -> { onSend.accept(playerInformation, gameChoice.getValue()); this.hide(); } - ); + , false); - var cancelButton = Primitive.button("cancel", () -> hide()); + var cancelButton = Primitive.button("cancel", () -> hide(), false); var leftSection = Primitive.vbox( challengeText, diff --git a/app/src/main/java/org/toop/app/widget/tutorial/BaseTutorialWidget.java b/app/src/main/java/org/toop/app/widget/tutorial/BaseTutorialWidget.java index 54f40b0..02c872d 100644 --- a/app/src/main/java/org/toop/app/widget/tutorial/BaseTutorialWidget.java +++ b/app/src/main/java/org/toop/app/widget/tutorial/BaseTutorialWidget.java @@ -47,8 +47,8 @@ public class BaseTutorialWidget extends PopupWidget implements Updatable { this.pages = pages; this.nextScreen = nextScreen; - previousButton = Primitive.button("goback", () -> { update(false); this.hide(); }); - nextButton = Primitive.button(">", () -> update(true)); + previousButton = Primitive.button("goback", () -> { update(false); this.hide(); }, false); + nextButton = Primitive.button(">", () -> update(true), false); var w = Primitive.hbox( previousButton, diff --git a/app/src/main/java/org/toop/app/widget/tutorial/ShowEnableTutorialWidget.java b/app/src/main/java/org/toop/app/widget/tutorial/ShowEnableTutorialWidget.java index 62fa0c7..168225e 100644 --- a/app/src/main/java/org/toop/app/widget/tutorial/ShowEnableTutorialWidget.java +++ b/app/src/main/java/org/toop/app/widget/tutorial/ShowEnableTutorialWidget.java @@ -10,9 +10,9 @@ public class ShowEnableTutorialWidget extends PopupWidget { public ShowEnableTutorialWidget(Runnable tutorial, Runnable nextScreen, Runnable appSettingsSetter) { var a = Primitive.hbox( - Primitive.button("ok", () -> { appSettingsSetter.run(); tutorial.run(); this.hide(); }), - Primitive.button("no", () -> { appSettingsSetter.run(); nextScreen.run(); this.hide(); }), - Primitive.button("never", () -> { AppSettings.getSettings().setTutorialFlag(false); nextScreen.run(); this.hide(); }) + Primitive.button("ok", () -> { appSettingsSetter.run(); tutorial.run(); this.hide(); }, false), + Primitive.button("no", () -> { appSettingsSetter.run(); nextScreen.run(); this.hide(); }, false), + Primitive.button("never", () -> { AppSettings.getSettings().setTutorialFlag(false); nextScreen.run(); this.hide(); }, false) ); var txt = Primitive.text("tutorial"); diff --git a/app/src/main/java/org/toop/app/widget/view/GameView.java b/app/src/main/java/org/toop/app/widget/view/GameView.java index 94d8cd7..441cc0e 100644 --- a/app/src/main/java/org/toop/app/widget/view/GameView.java +++ b/app/src/main/java/org/toop/app/widget/view/GameView.java @@ -40,7 +40,7 @@ public final class GameView extends ViewWidget { player2Icon = new Circle(); if (onForfeit != null) { - forfeitButton = Primitive.button("forfeit", () -> onForfeit.run()); + forfeitButton = Primitive.button("forfeit", () -> onForfeit.run(), false); } else { forfeitButton = null; } @@ -48,7 +48,7 @@ public final class GameView extends ViewWidget { exitButton = Primitive.button("exit", () -> { onExit.run(); transitionPrevious(); - }); + }, false); if (onMessage != null) { chatInput = Primitive.input("enter-your-message", "", null); diff --git a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java index 9b9bed2..9139720 100644 --- a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java +++ b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java @@ -2,24 +2,21 @@ package org.toop.app.widget.view; import javafx.application.Platform; import org.toop.app.GameInformation; -import org.toop.app.canvas.ReversiBitCanvas; -import org.toop.app.canvas.TicTacToeBitCanvas; -import org.toop.app.gameControllers.GenericGameController; import org.toop.app.gameControllers.ReversiBitController; import org.toop.app.gameControllers.TicTacToeBitController; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.gameFramework.model.player.Player; -import org.toop.game.games.reversi.BitboardReversi; -import org.toop.game.games.tictactoe.BitboardTicTacToe; -import org.toop.game.players.ArtificialPlayer; -import org.toop.game.players.LocalPlayer; +import org.toop.framework.game.players.ArtificialPlayer; import org.toop.app.widget.Primitive; import org.toop.app.widget.complex.PlayerInfoWidget; import org.toop.app.widget.complex.ViewWidget; import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.tutorial.*; -import org.toop.game.players.MiniMaxAI; -import org.toop.game.players.RandomAI; +import org.toop.framework.game.players.LocalPlayer; +import org.toop.game.players.ai.MCTSAI; +import org.toop.game.players.ai.MCTSAI2; +import org.toop.game.players.ai.MCTSAI3; +import org.toop.game.players.ai.MiniMaxAI; import org.toop.local.AppContext; import javafx.geometry.Pos; @@ -27,9 +24,6 @@ import javafx.scene.control.ScrollPane; import javafx.scene.layout.VBox; import org.toop.local.AppSettings; -import java.util.Arrays; -import java.util.Random; - public class LocalMultiplayerView extends ViewWidget { private final GameInformation information; @@ -58,14 +52,14 @@ public class LocalMultiplayerView extends ViewWidget { switch (information.type) { case TICTACTOE: if (information.players[0].isHuman) { - players[0] = new LocalPlayer<>(information.players[0].name); + players[0] = new LocalPlayer(information.players[0].name); } else { - players[0] = new ArtificialPlayer<>(new RandomAI(), "Random AI"); + players[0] = new ArtificialPlayer(new MCTSAI(100), "MCTS AI"); } if (information.players[1].isHuman) { - players[1] = new LocalPlayer<>(information.players[1].name); + players[1] = new LocalPlayer(information.players[1].name); } else { - players[1] = new ArtificialPlayer<>(new MiniMaxAI(9), "MiniMax AI"); + players[1] = new ArtificialPlayer(new MiniMaxAI(9), "MiniMax AI"); } if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstTTT()) { new ShowEnableTutorialWidget( @@ -86,14 +80,15 @@ public class LocalMultiplayerView extends ViewWidget { break; case REVERSI: if (information.players[0].isHuman) { - players[0] = new LocalPlayer<>(information.players[0].name); + players[0] = new LocalPlayer(information.players[0].name); } else { - players[0] = new ArtificialPlayer<>(new RandomAI(), "Random AI"); + // players[0] = new ArtificialPlayer(new RandomAI(), "Random AI"); + players[0] = new ArtificialPlayer(new MCTSAI3(50), "MCTS V3 AI"); } if (information.players[1].isHuman) { - players[1] = new LocalPlayer<>(information.players[1].name); + players[1] = new LocalPlayer(information.players[1].name); } else { - players[1] = new ArtificialPlayer<>(new MiniMaxAI(6), "MiniMax"); + players[1] = new ArtificialPlayer(new MCTSAI2(50), "MCTS V2 AI"); } if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstReversi()) { new ShowEnableTutorialWidget( @@ -113,7 +108,7 @@ public class LocalMultiplayerView extends ViewWidget { } break; } - }); + }, false); var playerSection = setupPlayerSections(); diff --git a/app/src/main/java/org/toop/app/widget/view/LocalView.java b/app/src/main/java/org/toop/app/widget/view/LocalView.java index f002bf8..51fdb7e 100644 --- a/app/src/main/java/org/toop/app/widget/view/LocalView.java +++ b/app/src/main/java/org/toop/app/widget/view/LocalView.java @@ -10,11 +10,11 @@ public class LocalView extends ViewWidget { public LocalView() { var ticTacToeButton = Primitive.button("tic-tac-toe", () -> { transitionNext(new LocalMultiplayerView(GameInformation.Type.TICTACTOE)); - }); + }, false); var reversiButton = Primitive.button("reversi", () -> { transitionNext(new LocalMultiplayerView(GameInformation.Type.REVERSI)); - }); + }, false); add(Pos.CENTER, Primitive.vbox( ticTacToeButton, diff --git a/app/src/main/java/org/toop/app/widget/view/MainView.java b/app/src/main/java/org/toop/app/widget/view/MainView.java index a60d753..7dc8aed 100644 --- a/app/src/main/java/org/toop/app/widget/view/MainView.java +++ b/app/src/main/java/org/toop/app/widget/view/MainView.java @@ -9,24 +9,24 @@ public class MainView extends ViewWidget { public MainView() { var localButton = Primitive.button("local", () -> { transitionNext(new LocalView()); - }); + }, false); var onlineButton = Primitive.button("online", () -> { transitionNext(new OnlineView()); - }); + }, false); var creditsButton = Primitive.button("credits", () -> { transitionNext(new CreditsView()); - }); + }, false); var optionsButton = Primitive.button("options", () -> { transitionNext(new OptionsView()); - }); + }, false); var quitButton = Primitive.button("quit", () -> { var a = new QuitPopup(); a.show(Pos.CENTER); - }); + }, false); add(Pos.CENTER, Primitive.vbox( localButton, diff --git a/app/src/main/java/org/toop/app/widget/view/OnlineView.java b/app/src/main/java/org/toop/app/widget/view/OnlineView.java index 16ed1df..533e097 100644 --- a/app/src/main/java/org/toop/app/widget/view/OnlineView.java +++ b/app/src/main/java/org/toop/app/widget/view/OnlineView.java @@ -6,6 +6,14 @@ import org.toop.app.widget.complex.LabeledInputWidget; import org.toop.app.widget.complex.ViewWidget; import javafx.geometry.Pos; +import org.toop.framework.game.games.reversi.BitboardReversi; +import org.toop.framework.game.games.tictactoe.BitboardTicTacToe; +import org.toop.framework.gameFramework.model.game.TurnBasedGame; +import org.toop.framework.networking.server.gateway.NettyGatewayServer; +import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore; + +import java.time.Duration; +import java.util.concurrent.ConcurrentHashMap; public class OnlineView extends ViewWidget { public OnlineView() { @@ -21,7 +29,31 @@ public class OnlineView extends ViewWidget { serverPortInput.getValue(), playerNameInput.getValue() ); - }); + }, false); + + var localHostButton = Primitive.button("host!", () -> { + + var tps = new TurnBasedGameTypeStore(); + tps.register("tic-tac-toe", BitboardTicTacToe::new); + tps.register("reversi", BitboardReversi::new); + + var a = new NettyGatewayServer(6666, tps, Duration.ofSeconds(10)); + + new Thread(() -> { + try { + a.start(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }).start(); + + new Server( + "127.0.0.1", + "6666", + "host", + a + ); + }, false, false); add(Pos.CENTER, Primitive.vbox( serverInformationHeader, @@ -32,7 +64,9 @@ public class OnlineView extends ViewWidget { playerNameInput.getNode(), Primitive.separator(), - connectButton + connectButton, + Primitive.separator(), + localHostButton )); } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/widget/view/ServerView.java b/app/src/main/java/org/toop/app/widget/view/ServerView.java index 7365e74..92c8101 100644 --- a/app/src/main/java/org/toop/app/widget/view/ServerView.java +++ b/app/src/main/java/org/toop/app/widget/view/ServerView.java @@ -1,26 +1,37 @@ package org.toop.app.widget.view; +import javafx.collections.FXCollections; +import javafx.css.converter.StringConverter; +import javafx.scene.control.ComboBox; import org.toop.app.widget.Primitive; import org.toop.app.widget.complex.ViewWidget; import java.util.List; +import java.util.Locale; import java.util.function.Consumer; import javafx.application.Platform; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.ListView; +import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.networking.connection.events.NetworkEvents; public final class ServerView extends ViewWidget { private final String user; private final Consumer onPlayerClicked; + private final long clientId; + private final ComboBox gameList; private final ListView