Compare commits

..

851 Commits

Author SHA1 Message Date
William Muir a1d468c689 Added toggle button for the chat history
#story[1274]
2017-09-28 16:39:59 +13:00
Haoming Yin 4f80640718 Polished raceview UI elements
- changed javaFx css style into Css file

tags: #story[1273]
2017-09-28 16:33:16 +13:00
Kusal Ekanayake 27379ae96d Fixed fatal bug to do with mark arrow on boat. 2017-09-28 16:27:57 +13:00
Kusal Ekanayake ce3e08abfc Changed minimise and maximise icons for minimap 2017-09-28 16:18:44 +13:00
Calum 923c381797 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:17:27 +13:00
Calum ece45ff967 Fixed map, parrot and camera. 2017-09-28 16:17:19 +13:00
William Muir 02dc1dbd3d Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:04:29 +13:00
Michael Rausch d9b9c2f808 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:04:07 +13:00
William Muir 4e3de02a93 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:04:04 +13:00
Michael Rausch 261f68f143 Added port number randomization
- Servers all run on different ports, so multiple servers can run on one host
- Port is displayed in lobby

Tags: #story[1281]
2017-09-28 16:03:59 +13:00
William Muir ed9b7acc62 New Map! Waiheke
#story[1274]
2017-09-28 16:03:56 +13:00
Michael Rausch 74c1219e0d Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java
2017-09-28 16:02:04 +13:00
Calum 83218ae0a0 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:01:32 +13:00
Calum 0231c43a2c Arrows work. mark arrow thinner. refactored marker class.
#fix
2017-09-28 16:01:24 +13:00
Michael Rausch a05a41d5ec Added port number randomization
- Servers all run on different ports, so multiple servers can run on one host
- Port is displayed in lobby

Tags: #story[1281]
2017-09-28 15:57:59 +13:00
Haoming Yin 06bc3644bc Removed dead code in MeesageFactory and redundant classes
tags: #story[1273]
2017-09-28 15:54:09 +13:00
Haoming Yin 7620f0023e Removed dead code in MainServerThread
tags: #story[1273]
2017-09-28 15:43:35 +13:00
Kusal Ekanayake 77ee1ebbc0 Fixed faulty tests. 2017-09-28 15:35:58 +13:00
William Muir 6d0835b0cf Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-09-28 15:29:00 +13:00
William Muir 54410efa12 Changed garbage collection to once every second, Changed wind walker icon to white
#story[1273]
2017-09-28 15:24:45 +13:00
William Muir 74241ee819 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 15:23:50 +13:00
Kusal Ekanayake a9ce8901f5 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 15:17:06 +13:00
Michael Rausch 8810554ce9 Fixed bug where server wasn't being unregistered from discovery server
- Added missing unregister() method call

Tags: #story[1281]
2017-09-28 15:16:37 +13:00
Kusal Ekanayake 7e3ed872ed Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/visualiser/ClientToServerThread.java
2017-09-28 15:08:53 +13:00
Kusal Ekanayake 21ce34dda2 Fixed finish screen and cleaned up dead code 2017-09-28 15:08:34 +13:00
William Muir 2bf318a122 Merge branch 'story1273_minimap' into develop 2017-09-28 15:08:32 +13:00
Michael Rausch e56d284792 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 15:00:24 +13:00
Michael Rausch 80c26a9e4a Fixed bug where server could connect to an expired server
- Increased update interval

Tags: #story[1281]
2017-09-28 15:00:00 +13:00
Calum e1ebbc71c1 Added drawing to fx thread
#fix
2017-09-28 14:57:52 +13:00
Calum c4a3df32c8 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 14:47:00 +13:00
Calum 1e19dd5ab6 Fixed parrot again. 2017-09-28 14:46:55 +13:00
William Muir c98297ea79 Merged dev changes back on to mini map
#story[1273]
2017-09-28 14:44:16 +13:00
Alistair McIntyre 1aedcaddf5 removed an added print statement
tags : #story[1275]
2017-09-28 14:42:34 +13:00
Alistair McIntyre d7fc339ad5 - Added Madagascar Map
tags : #story[1275]
2017-09-28 14:41:35 +13:00
William Muir a5eea10c87 Merge branch 'develop' into story1273_minimap
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
#	src/main/resources/meshes/boatSTLs/parrot_features.stl
2017-09-28 14:41:08 +13:00
Kusal Ekanayake 02aabc3162 Removing dead code in race view controller and fixed mark rounding bug 2017-09-28 14:35:40 +13:00
Alistair McIntyre d2a05de25a Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 14:34:39 +13:00
Calum 597fbe935f Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 14:28:16 +13:00
Calum 7cfad28d6b Fixed parrot 2017-09-28 14:28:07 +13:00
Michael Rausch 3345734efd Fixed memory leak by forcing garbage collection 2017-09-28 14:22:33 +13:00
Haoming Yin 9795083d4d Added confirm button in keybinding dialog.
-  clicking confirm button will exit the dialog
- [WIP] exit without clicking confirm button will still save changes, which should be fixed in the future

tags: #story[1273]
2017-09-28 13:58:25 +13:00
Kusal Ekanayake f02208ba3a Loopty loop map added 2017-09-28 13:33:09 +13:00
William Muir b9a2d60115 Merged dev changes back on to mini map
#story[1273]
2017-09-28 12:58:19 +13:00
William Muir 076c4c9a40 Merge branch 'develop' into story1273_minimap
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
#	src/main/resources/views/RaceView.fxml
2017-09-28 12:54:12 +13:00
Calum 8d74c3b756 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 12:44:33 +13:00
Calum 3f666fa092 Made waka larger. 2017-09-28 12:44:24 +13:00
Haoming Yin 55d82298b6 Beautified the loading splash screen
- added 7-color rainbow spinners
- added background image
- added subtitle
- changed font size and color

tags: #story[1273]
2017-09-28 12:42:46 +13:00
William Muir 909407fe63 Merge branch '1293_PowerUps_TokenInfo' into develop 2017-09-28 12:31:14 +13:00
William Muir cb4e47f71a Fixed icon backgrounds to be white
#story[1293]
2017-09-28 12:31:00 +13:00
William Muir 499acb9733 Merge branch '1293_PowerUps_TokenInfo' into develop 2017-09-28 12:21:12 +13:00
William Muir 5688e10e6f Tokens now display on the right and are clickable for further information
#story[1293]
2017-09-28 12:20:16 +13:00
Alistair McIntyre c72c4929ff Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 12:15:44 +13:00
Alistair McIntyre 265b20ad61 - Created Madagascar Map Initial
tags : #story[1275]
2017-09-28 12:12:22 +13:00
William Muir 5cbd729214 Tokens now display on the right and are clickable for further information
#story[1293]
2017-09-28 12:08:14 +13:00
Calum ddf5a96e0f Merge branch '1276_Next_Mark_Indicator' into develop 2017-09-28 12:03:30 +13:00
Calum 81b2d285e9 Changed arrow colour.
#fix
2017-09-28 12:02:24 +13:00
Calum 5d7f307260 Changed arrow colour.
#fix
2017-09-28 12:02:09 +13:00
Kusal Ekanayake 4ec23a1785 Fixed race fxml not showing other elements 2017-09-28 11:30:09 +13:00
Haoming Yin 37e4fe4ce7 Issue #83: Server creation dialog need to be polished
- rearranged the layout of all the nodes
- set CSS files for the dialog
- added close button

tags: #story[1273]
2017-09-28 11:13:02 +13:00
Calum e87931a8fc Merge branch 'develop' into story1273_minimap 2017-09-28 10:21:23 +13:00
Calum d1edbc4b8a Put the arrows into the minimap. Fixed the issue with curved section of port marks.
#fix #implement
2017-09-28 10:19:32 +13:00
Calum 275a2cbab7 Made continous turning the default. Added triangles to minimap. Made mark areas bigger
#fix #implement
2017-09-28 10:12:18 +13:00
Calum 705669ad07 centered icons #fix 2017-09-28 07:23:25 +13:00
Calum 71f6b9accb Fixed duplicate waka files.
#fix
2017-09-28 06:59:44 +13:00
Calum caf04e1e99 Added a waka model.
#implement #story[1274]
2017-09-28 06:54:20 +13:00
Calum b9cb6fa5b4 Added token information to the lobby screen.
#implement #story[1293]
2017-09-28 05:09:54 +13:00
Calum 0b8e2499a7 Fixed some internal stl faces on parrot
#fix
2017-09-28 03:35:28 +13:00
Calum 9075d2a909 Added a minimap to the race view.
#implement #story[1273]
2017-09-28 03:17:33 +13:00
alistairjmcintyre 00e2af9c14 - Fixed Merge Errors and some broken lighting AGAIN
#tags [1276]
2017-09-28 02:20:34 +13:00
William Muir ba768deabc Initial commit for The Token info panel in the lobby controller
- Having some mad issues with front end formatting with JFX.
- Icons are put in boxes

#story[1293]
2017-09-28 02:17:39 +13:00
alistairjmcintyre 73861b2ef3 Merge branch 'develop' into 1276_Next_Mark_Indicator 2017-09-28 02:06:18 +13:00
alistairjmcintyre 4018dd783e - Fixed Merge Errors and some broken lighting
#tags [1276]
2017-09-28 02:05:47 +13:00
Michael Rausch 8b7407bf89 Various bug fixes
- Closed socket when discovery server crashes, so it can be restarted
- Flattened water on terrain mesh
- Added checks to ensure server is started before connecting
- Added a check to ensure client has started  before connecting to the server
- Fixed concurrency issue in server-> client thread list

Tags: #story[1281]
2017-09-28 01:58:49 +13:00
Calum 00ddf117b2 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/resources/images/wind-180.png
2017-09-28 00:26:09 +13:00
Calum a266779709 Added new Wind Waker mesh
#implement #story[1293]
2017-09-28 00:24:34 +13:00
Haoming Yin df24fe072a Added animation for wind turning.
- enlarged the wind image size to centre the compass
- added animation to smooth the turning
2017-09-28 00:13:45 +13:00
Calum a1a34b9bd7 Merge branch 'develop' of https://eng-git.canterbury.ac.nz/seng302-2017/team-13 into develop 2017-09-27 23:36:14 +13:00
Calum 42d490d6fd Added new Wind Waker mesh
#implement #story[1293]
2017-09-27 23:35:51 +13:00
Haoming Yin cd4a2f8da3 Merge remote-tracking branch 'origin/develop' into develop 2017-09-27 22:47:08 +13:00
Haoming Yin 287cfd77d0 Fix: smoothing wind rotation
- added animation for wind rotation
- enlarged wind image's background to centre the compass

#story[1273]
2017-09-27 22:45:56 +13:00
alistairjmcintyre a08a38c985 - Fixed Merge Errors
#tags [1276]
2017-09-27 22:25:32 +13:00
alistairjmcintyre 810dde6a21 Merge branch 'develop' into 1276_Next_Mark_Indicator
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelType.java
2017-09-27 22:15:02 +13:00
alistairjmcintyre 7a76efa2ce - Added ability to color the indicators.
#tags [1276]
2017-09-27 22:07:24 +13:00
William Muir ff4c2cd5b6 Merge branch '1273_Skybox' into 'develop'
1273 skybox

Server Discovery:
 - Created server discovery server.
 - Implemented protocols to support matchmaking & room code connection
 - Improved error handling for server disconnections

Skybox:
 - Added a skybox
 - Added a terrain mesh

See merge request !79
2017-09-27 21:52:34 +13:00
alistairjmcintyre c5e6302f86 - Added circle to boat to indicate which boat is the players and to show where the arrow is pointing.
#tags [1276]
2017-09-27 21:31:02 +13:00
Peter Galloway cd199767ae created new models for all pickups #story[1293] 2017-09-27 20:40:40 +13:00
Michael Rausch 5cc4898ab5 Fixed failing tests & other bug fixes
- Fixed server capacity in server list
- Fixed failing unit tests for chat

Tags: #story[1281] #pair[mra106, cir27]
2017-09-27 20:37:29 +13:00
Haoming Yin 22e1e57c24 Issue #73: If you change controls to 'Continuously turning' before moving into game, it is not applied
- always send turning mode packet when race starts to sync the steering mode

#story[1278]
2017-09-27 20:18:06 +13:00
Haoming Yin c5d2016733 Merge branch 'issue_#67_early_start' into 'develop'
added a check in the start logic to make sure a boat can't cross the start line early



See merge request !74
2017-09-27 19:42:05 +13:00
Kusal Ekanayake efc71f2003 Resolved issue #69 and added dock icon for splash screen. 2017-09-27 19:27:13 +13:00
Alistair McIntyre be72062c8e Merge branch 'develop' into 1276_Next_Mark_Indicator
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
2017-09-27 19:25:08 +13:00
Alistair McIntyre 0d212a4a1d - Indicator works correctly, sits in the right place, rotates around the boat correctly and sits on top of the water now.
tags : #story[1276]
2017-09-27 19:20:33 +13:00
Alistair McIntyre 0e9b818071 - Indicator points towards the next mark. Seems to do some funny stuff when entering a compound mark(gate).
tags : #story[1276]
2017-09-27 18:50:38 +13:00
Alistair McIntyre 452e83c1c3 - Marker seems to be detecting the correct mark but somethings wrong with the maths.
tags : #story[1276]
2017-09-27 17:52:54 +13:00
Alistair McIntyre aded794a67 - Added new indicator for direction to next mark.
- Marker rotates towards a given heading.

tags : #story[1276]
2017-09-27 17:17:50 +13:00
Michael Rausch 2b3a972ed5 Various bug fixes
- Fixed bug where an invalid port number would crash the program
- Closed the stage before cleaning up resources. This speeds up closing the app.
- Added error handling for when the client looses connection to the server.

Tags: #story[1281]
2017-09-27 17:14:55 +13:00
Calum 2a523a5664 Added a duck boat mesh.
#implement #story[1274]
2017-09-27 17:03:02 +13:00
Michael Rausch 67f3124cfb Merge branch 'develop' into 1273_Skybox 2017-09-27 15:32:54 +13:00
Michael Rausch 7db387bdec Merged Host Customisation onto 1273_Skybox 2017-09-27 15:31:54 +13:00
Alistair McIntyre 2ceca2fd42 Merge branch 'loading_screens' into 'develop'
Loading screens

# Changes
- Fixed a bug with sound not being muted consistently (the music would play when you press play again even if the music was muted)
- Added a splash screen to show for ~2 seconds on launch, doesn't repeat again while playing the same instance
- Added a loading screen which disappears when the race view has finished being set up (boats in place etc)

# Testing
- Manual testing done, few irrelevant bugs have been found, will log in issue tracker

See merge request !78
2017-09-27 15:05:36 +13:00
Michael Rausch 00ff771fc3 Merge remote-tracking branch 'origin/story1275_host_customization' into 1273_Skybox
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/GameView3D.java
#	src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java
2017-09-27 14:56:09 +13:00
Michael Rausch d963785679 Added files from merge 2017-09-27 14:47:32 +13:00
Michael Rausch 78f64557c3 Merged dev onto 1273_Skybox 2017-09-27 14:46:12 +13:00
Michael Rausch 982fac38a0 Merge remote-tracking branch 'origin/develop' into 1273_Skybox
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/MessageFactory.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/ClientYacht.java
#	src/main/java/seng302/model/mark/MarkOrder.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/GameView3D.java
#	src/main/java/seng302/visualiser/controllers/ServerListController.java
#	src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java
#	src/main/resources/icons/bumperIcon.png
#	src/main/resources/icons/handlingIcon.png
#	src/main/resources/icons/velocity.png
#	src/main/resources/icons/windWalkerIcon.png
#	src/main/resources/views/RaceView.fxml
#	src/main/resources/views/dialogs/ServerCreationDialog.fxml
2017-09-27 14:23:38 +13:00
Kusal Ekanayake edbfb2f84f Modified timings for load screen. 2017-09-27 14:16:27 +13:00
Kusal Ekanayake c01111038f Merge branch 'develop' into loading_screens
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-27 14:05:46 +13:00
William Muir fd53fd52a4 Forgot to git add the new icon.. again.. sorree
#story[1293]
2017-09-27 12:44:50 +13:00
William Muir 6f62efcc93 Updated the icons to be more uniform and transparent
#story[1293]
2017-09-27 12:44:22 +13:00
Michael Rausch daf3867433 Server discovery bug fixes & error handling improvements
- Fixed concurrency bug that prevented players from connecting to servers
- Discovery server can restart itself if it crashes
- Added nicer error handling for server discovery.
- Using AWS to get servers external IP address.

Tags: #story[1281]
2017-09-27 12:32:17 +13:00
William Muir e5af7bf666 Minor fixes. Only one person can have wind walker now. Tokens spawn at 30s rather than 15
#story[1293]
2017-09-27 12:06:16 +13:00
William Muir 85ca91db96 Minor fixes. Only one person can have wind walker now. Tokens spawn at 30s rather than 15
#story[1293]
2017-09-27 11:55:40 +13:00
William Muir 2eb7e603f1 Merge remote-tracking branch 'origin/develop' into 1293_PowerUps 2017-09-27 03:01:41 +13:00
William Muir 658a342118 Added the bad random to git sorree forgot to git add
#story[1293]
2017-09-27 03:01:23 +13:00
Calum c0bd498f1b Added debugs for missing xml 2017-09-27 02:50:36 +13:00
Calum Irwin ea52977aeb Merge branch '1293_PowerUps' into 'develop'
1293 power ups

# Changes 
* Token Objects added to represent pickups along with their corresponding mesh objects 
* Yachts now have a powerup attribute 
* Power up attribute is checked in Game State updates and updates are now done appropriately, dependant on this power up 
* RaceViewController now has a grid pane to show the different power up icons. These will display when a token is picked up and blink when they are about to dissapear
* Token generator created. This generates token locations randomly in the map in circles centred between the legs of the race 
* Added Yacht EventCodes for the different type of power / up / down status effect actions
 
# Refactor
* Moved Timer tasks such as spawn tokens and update wind into the GameState where they belong
* Moved the creation of some messages in odd places, server side, into the MessageFactory class 
 
# Testing 
* Manual test done
* Junits created for the random token generator

See merge request !77
2017-09-27 02:47:57 +13:00
William Muir 10fa51a105 Added some testing for the Random spawner
#story[1293]
2017-09-27 02:27:30 +13:00
Calum b18d9e8573 Added empty cucumber
#test
2017-09-27 02:04:58 +13:00
Calum e9881bb24a Added per map max player count. Handles case when map cannot fit players behind start mark. Added initial implementation for spacing out yachts.
#implement  #story[1275]
2017-09-27 02:04:24 +13:00
William Muir c54a1e141d Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-27 01:49:18 +13:00
William Muir 6d51ea3574 Created a random place token generator.
Generates a location between any leg of the race in a random angle / distance of the radius of the centre point of the two gates to one of the gates

#story[1293]
2017-09-27 01:44:01 +13:00
Zhi You Tan d56468e4aa - Fixed snackbar not showing on race view
- Added close label on server creation dialog

#story[1273]
2017-09-27 00:38:42 +13:00
Calum ab5ad58237 Merge branch 'develop' into story1275_host_customization
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-26 23:37:59 +13:00
Calum df7264cc1f Added per map max player count. Handles case when map cannot fit players behind start mark. Added initial implementation for spacing out yachts.
#implement.
2017-09-26 23:34:19 +13:00
Zhi You Tan 5248921576 Multiple fixes:
- fix last button no longer default focused when loading keybinding dialog
- fix click and mouse exit still focused on button
- closing keybinding does not focus on chat anymore

#story[1273]
2017-09-26 22:52:58 +13:00
William Muir 330ccd272d The random token now has a 50% chance of causing your boat to have a speed penalty
#story[1293]
2017-09-26 21:13:35 +13:00
William Muir 4b7dfe38c4 Fixed Boats powering up and down correctly. Icons respond correctly
#story[1293]
2017-09-26 19:43:32 +13:00
William Muir ab07c7f298 Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-26 19:01:53 +13:00
William Muir b5076bc976 Fixed wind walker and bumper
Added a hack to bumper so that the collision distance is larger than the regular collision distance
Wind walker now makes you go at you max speed rather than VMG speed

#story[1293]
2017-09-26 18:57:15 +13:00
Michael Rausch 2dcdd1c248 Merge branch '1273_Changing_Cameras' into 'develop'
1273 changing cameras

# Multiple Camera Views

## 3 Camera Views Implemented
1. Normal 3D (Isometric)
2. Top Down Perspective
3. Chase Cam (Over the Shoulder)

- Isometric and Top Down Perspectives can Pan within limits.
- Chase Cam rotates the camera around the boat. (While still following it)
- All camera views can Zoom.

# Testing

No testing completed other than manually testing myself. A proper manual test should be completed by the merger.

See merge request !76
2017-09-26 18:36:59 +13:00
Alistair McIntyre 9b00f76907 removed print statements and added documentation.
tags : #story[1273]
2017-09-26 18:36:13 +13:00
Alistair McIntyre f11c457d28 removed print statements
tags : #story[1273]
2017-09-26 18:31:47 +13:00
Michael Rausch 9e4fa30787 Merge branch 'issue68_boat_not_turning_on_starbord_vmg' into 'develop'
the boat can now turn after snapping to starboard vmg #story[1273]



See merge request !75
2017-09-26 18:11:24 +13:00
Alistair McIntyre 99ce4fa11d Merged develop in and reimplemented keybindings for moving the camera.
tags : #story[1273]
2017-09-26 18:01:39 +13:00
Alistair McIntyre 69d1fa9488 Merge branch 'develop' into 1273_Changing_Cameras 2017-09-26 17:36:40 +13:00
Alistair McIntyre 66e6a8a2a4 - Small Changes
tags : #story[1273]
2017-09-26 17:35:36 +13:00
Kusal Ekanayake 671efcaf08 Adding spinners to the loading screen. 2017-09-26 17:25:57 +13:00
William Muir 8ba44d7476 Minor commit for testing
#story[1293]
2017-09-26 17:19:45 +13:00
Peter Galloway dd43097677 the boat can now turn after snapping to starboard vmg #story[1273] 2017-09-26 17:07:55 +13:00
Kusal Ekanayake 98abe64f00 Added splash and loading screen 2017-09-26 17:07:02 +13:00
Alistair McIntyre 1a53579317 - Isometric Camera
- Zoom Bounds added.
 - Camera Panning Bounds added. Need to be tested with extra maps.

tags : #story[1273]
2017-09-26 16:57:07 +13:00
Haoming Yin 132a729758 Temporarily added more options in key binding dialog. But still need to implement binding after camera story has been merged into develop
tags: #story[1273]
2017-09-26 15:49:16 +13:00
Peter Galloway 870d7a6e82 added a check in the start logic to make sure a boat can't cross the start line prematurely (they will have to go back and go through it again) #fix #refactor 2017-09-26 15:25:24 +13:00
alistairjmcintyre 2e7487fdfc - Chase Camera:
- Has panning bounds, zoom bounds, and general tidy up.
 - Now correctly observes the boat object rather than getting information from both the boat object AND the client yacht model.

Top Down Camera:
 - Can only pan within certain bounds now, and will continue to follow the boat regardless.
 - Can only zoom within certain bounds now.

Isometric Camera:
 - Nothing changed.

#tags [1273]
2017-09-26 15:06:21 +13:00
Haoming Yin 1bd4db73cd Issue 66: client side error pop ups use default javaFx style
- created JFeonix style pop up to replace the default one

tags: #story[1273]
2017-09-26 14:44:37 +13:00
William Muir 7a4cdbe0c9 Fixed WindWalker
#story[1293]
2017-09-26 11:12:29 +13:00
Calum 735699dc85 Changed default number of legs. 2017-09-26 01:53:33 +13:00
Calum 81e791bd1a Fixed issues with showing race view controller. Added missing icons. Added a smooth version of land.
#fix
2017-09-26 01:49:43 +13:00
Calum 06e5f4ae00 Merge remote-tracking branch 'origin/1273_Skybox' into 1273_Skybox 2017-09-26 01:35:07 +13:00
Calum cd2b4cb93c fixed anchor pane issues 2017-09-26 01:34:59 +13:00
Calum dde1c82dbb merge with host customization and dev. 2017-09-26 01:21:55 +13:00
Calum d9c832168b Merge branch 'story1275_host_customization' into 1273_Skybox
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
#	src/main/java/seng302/visualiser/controllers/LobbyController.java
#	src/main/java/seng302/visualiser/controllers/ViewManager.java
#	src/main/resources/views/LobbyView.fxml
#	src/main/resources/views/RaceView.fxml
2017-09-26 01:19:47 +13:00
Michael Rausch 9cfb3b9e5d Added functionality to automatically select a server
- Added functionality on the DiscoveryServer to return a random server to the player
- Added elements to the UI to support auto-selecting a server
- Added client side code to request a random server

Tags: #story[1281]
2017-09-26 01:14:02 +13:00
Calum e990c68d40 #document 2017-09-26 01:12:43 +13:00
Calum 83871a0336 Fixed boat trials rendering abnormally
#issue[65] #fix
2017-09-26 01:07:02 +13:00
Calum 6cba024d64 Made changes to the shape of boat trials. 2017-09-26 00:59:04 +13:00
Calum 51747e2d13 Refactored the 2D and 3D game view class setups. Made scaling more logical.
#refactor #story[1275]
2017-09-26 00:55:28 +13:00
Calum b3981b19e0 Merge branch 'develop' into story1275_host_customization
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/ServerYacht.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/controllers/LobbyController.java
#	src/test/java/seng302/models/YachtTest.java
2017-09-25 23:25:33 +13:00
Calum 3d7a64068f Fixed scaling issues.
#fix
2017-09-25 23:19:03 +13:00
Calum c12f7408ad experimenting with map scaling
#implement
2017-09-25 22:57:45 +13:00
Calum 7027de80c4 Fixed issues with correct protocol implementation.
#issue[64] #fix #testmanual
2017-09-25 22:09:26 +13:00
Calum 35b50d1436 Refactored 2d game view distance calculations to better size and sale the map,
#implement #refactor #story[1275]
2017-09-25 21:06:18 +13:00
Michael Rausch d0844e861d Changed water color to blue 2017-09-25 19:25:03 +13:00
Michael Rausch 5d32d76d9d Added local skybox texture, and changed water color
- Changed water color to a more sea-like blue
- Added an extra sun
- Moved skybox texture to the resources folder
2017-09-25 19:19:46 +13:00
Michael Rausch 9ca39d1a7c Merge branch '1273_Changing_Cameras' into 1273_Skybox 2017-09-25 18:40:15 +13:00
Michael Rausch 30dad8509e Added skybox & cleaned up server list UI
- Moved direct connect fields to a dialog as there was not enough room
- Moved room code to its own label
- Added a skybox texture to the game view
- Added the land mesh to the game view
2017-09-25 18:25:24 +13:00
William Muir 0211f2df38 Merged dev back on
#story[1293]
2017-09-25 17:38:09 +13:00
William Muir dba5a5680f Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/model/ServerYacht.java
#	src/main/resources/views/RaceView.fxml
2017-09-25 17:20:25 +13:00
William Muir 5c50e77efa Merge branch 'Story1278_keybindings' into 'develop'
Story1278 keybindings

# Changes

- Added customised action key binding for all boat actions
- Users can select the turning mode (continuously turning mode, and the default turning mode)
- Refined UI design for key bindings
- Added animation which mouse enters/exits the setting button, and also prompt text to guide users to press key
- Popup window to inform users if their key assignment is successful or not

# Testing

## Manual testing log as below (all passed according to the assigner)
- if a player toggles the turning mode toggle button, the labels for upwind and downwind will be changed correspondingly
- if a player clicks the "reset" button, all the key binding settings will be reset to default
- if a player assigns a key which is already is in use, a popup box will inform the assignment is failed, and action will be changed back
- if a player assigns a key successfully, a popup will inform the success, and the new key binding will appear on the button
- A player can change their key bindings before the race starts and during the race


See merge request !73
2017-09-25 17:11:12 +13:00
Zhi You Tan 0e93be7b36 Fixed send button traversable issue.
- removed sensitive characters.

#story[1278] #pair[hyi25, zyt10]
2017-09-25 17:06:36 +13:00
Zhi You Tan 191b818e38 Added close button for keyBindingDialog.
- fixed that you cannot bind the key you are using.

#story[1278] #pair[hyi25, zyt10]
2017-09-25 16:31:28 +13:00
Alistair McIntyre 00b09997b0 - Added Camera panning to chase camera mode.
tags : #story[1273]
2017-09-25 16:28:37 +13:00
Alistair McIntyre d250c635d8 - Adjusted server tick rate to test smoothing
tags : #story[1273]
2017-09-25 15:32:13 +13:00
Alistair McIntyre 376c4d25a8 Merge branch 'develop' into 1273_Changing_Cameras
# Conflicts:
#	src/main/java/seng302/model/ClientYacht.java
2017-09-25 14:40:19 +13:00
Alistair McIntyre e66abb4340 - An attempt at chase cam smoothing. needs work.
tags : #story[1273]
2017-09-25 14:39:09 +13:00
Alistair McIntyre a19e191684 - Chase cam kind of working, need to find a fix for the abrupt direction change.
tags : #story[1273]
2017-09-25 14:03:47 +13:00
William Muir 29b97a194d Merged dev back on
#story[1293]
2017-09-25 11:26:44 +13:00
William Muir 8a0ad8d6a9 Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/model/ServerYacht.java
2017-09-25 11:19:10 +13:00
Haoming Yin 19db6668da Fixed merge conflicts in server yacht
tags #story[1278]
2017-09-25 11:09:14 +13:00
Haoming Yin 44275aec04 Merge branch 'develop' into Story1278_keybindings
# Conflicts:
#	src/main/java/seng302/model/ServerYacht.java
2017-09-25 11:06:28 +13:00
Michael Rausch ca320f7fb8 Merge remote-tracking branch 'origin/1273_Changing_Cameras' into 1281_Server_Discovery_Internet 2017-09-25 00:18:35 +13:00
Zhi You Tan 64245833cd Merge branch 'Story1274_custom_boat_stats' into 'develop'
Story1274 custom boat stats

# Changes
- Added 3 areas for game play variation with the boats (stats)
    - Max speed
    - Handling
    - Acceleration
- Added stat bars on the customize boat screen so players can see the stats

# Testing
- Manual testing
- No JUnits made since no real processing methods were added


See merge request !72
2017-09-24 18:53:15 +13:00
Kusal Ekanayake aa0149b9a7 Merge branch 'develop' into Story1274_custom_boat_stats 2017-09-24 18:08:54 +13:00
Kusal Ekanayake f6b41f0513 Fixes Issue #59 2017-09-24 18:06:26 +13:00
Calum 9b00ba654a Added a race importer. Added imported races to visualizer. Made it so that the host sets the race. Refactored server to no longer be dependant on a specific race. Tested functionality of map manually. Some bugs found and listed below.
#implement #testmanual #story[1275]

Known bugs:
 * Can't move
 * Map is off center in lobby view.
 * 3D Map is off center
2017-09-23 22:45:53 +12:00
Haoming Yin 8dfdb228e9 Fixed a bug that game client tries to send turning mode packet when there is no socketThread
- add a if statement to check if socketThread is initialized before sending packet.

#story[1278]
2017-09-23 21:04:57 +12:00
Haoming Yin 1042817e4e Snackbar's color can be changed according to the message type
- load a separate css file to change the color
- if the assignment failed, the snackbar prompt will be red, otherwise theme color

#story[1278]
2017-09-23 20:59:29 +12:00
Haoming Yin 066557584f Implemented turning mode toggle
- when the mode is toggled, a boat action package will be sent to notify server
to change the boat's turning mode
- turning mode toggle is now fully functional

#story[1245]
2017-09-23 19:37:13 +12:00
Haoming Yin 4011295b8b Slightly optimised code style and add more functionality
- optimised UI
- check conflicts when change key bind if the key has already been in use
- abstract keybind as a separate singleton class so all class can access it
- [WIP] turning mode is need to be finished

#story[1245]
2017-09-23 17:52:48 +12:00
William Muir 78259f8e33 Boat now changes color when it is bumped for a time
ClientYacht: Added ColorChangeListener from GameView3D to re paint the boat when the color attribute is changed

#story[1293]
2017-09-23 16:54:03 +12:00
William Muir c47e5b1450 Boat now changes color when it is bumped for a time
ClientYacht: Added ColorChangeListener from GameView3D to re paint the boat when the color attribute is changed

#story[1293]
2017-09-23 16:31:18 +12:00
Kusal Ekanayake 0a885dd8fd Clean up changes
#story[1274]
2017-09-23 15:37:16 +12:00
Kusal Ekanayake e9b50038a9 Balance changes. Always wanted to use that as a commit message.
#story[1274]
2017-09-23 15:09:22 +12:00
Kusal Ekanayake 364264377a Fixed merge errors and reimplemented handling multiplier
#story[1274]
2017-09-23 15:04:11 +12:00
Kusal Ekanayake 9112183ac3 Merge branch 'develop' into Story1274_custom_boat_stats
# Conflicts:
#	src/main/java/seng302/model/ServerYacht.java
#	src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java
2017-09-23 14:48:50 +12:00
William Muir 8c7f9a878d Created Boat bumper logic. Refactored logic for powering up / dpwn
YachtEventType: Added some new events, a generic power down event and a bumper_crash event for an affected boat
GameState: Implemented boat bumper logic
MessageFactory: Made new messages for powerdown and status effect
ClientYacht: Had to create another powerDown functional interface to inform the race view controller when to turn off the icon
RaceViewController/GameClient: Now waits for a message about powering down before turning off rather than waiting time client side

#story[1293]
2017-09-23 13:23:16 +12:00
William Muir ecb3d4ecbf Removed sendServerMessage to be replaced with notifyMessageListeners. Minor structure move arounds
#story[1293]
2017-09-23 11:49:56 +12:00
William Muir e61b6d50a1 Small refactor. Fixed tokens to spawn on the minute mark.
Moved updates of wind and token timers into gamestate from mainserver thread. Now triggered upon GameState change to start

#story[1293]
2017-09-23 11:33:01 +12:00
Zhi You Tan 957821f1f2 [WIP] Created a snackbar for notification. Currently used for keybinding success/fail. Need to show red if fails.
#story[1278]
2017-09-23 01:39:26 +12:00
William Muir 061e49bab9 Implemented wind walker algorithm. Refactored some GameState updating logic to allow for better token logic integration
GameState: Moved all token logic into its own function startPoint so that it is dsijoint from other updating logic
GameState: Implemented wind walker algorithm.
GameState: Changed Generic 'speedMultiplier' to 'serverSpeedMultiplier' to make it obviously disjoint from a boats speed multiplier
MessageFactory: Moved some found message creation (Chatter Message)  server side into MessageFactory that wasnt already there
ServerYacht: Added a speed multiplier and a handling multiplier to the serveryacht class that is set and reset upon powerup / down

#story[1293]
2017-09-22 23:44:03 +12:00
Zhi You Tan 094eb4c1cf Merge remote-tracking branch 'origin/develop' into Story1278_keybindings
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-22 21:22:06 +12:00
William Muir a3c555d5fe Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/model/ClientYacht.java
2017-09-22 21:18:58 +12:00
William Muir 607acff7c6 Merge branch 'Custom_boat_selection' into 'develop'
Custom boat selection

# Story 1274 Feature Custom Boat Selection
## Changes
- 2 new boats!
- A boat selector in the customisation for boat dialog
- The potential for everyone to use whatever boats and for everyone to see

## Testing
- Basic JUnit tests added to test basic util methods added to the BoatMeshType class
- Manual testing completed

See merge request !71
2017-09-22 21:14:12 +12:00
William Muir 22fdf1e4ac Changed the boatType attribute from all around the place from String lit to enum
#story[1274]
2017-09-22 21:00:28 +12:00
William Muir da8c91f5c1 Review fixes for merge request.
PlayerCell now takes in the yacht for construction rather than taking in a whole lot of values extracted from the yacht

Reduced boiler plate in BoatCustomizeController

#story[1274]
2017-09-22 20:44:06 +12:00
Kusal Ekanayake 52dc7a956d Turned handling into a multiplier.
#story[1274]
2017-09-22 17:42:32 +12:00
Kusal Ekanayake 9f64b2380d Implemented acceleration and full loading bars.
#story[1274]
2017-09-22 17:28:42 +12:00
Kusal Ekanayake b05580f018 Worked on making a visual component to the stats. Need to implement acceleration.
#story[1274]
2017-09-22 16:45:10 +12:00
Haoming Yin c20c6fb264 [WIP] Added new toggle for steer turning mode and submit and reset button (restore the setting to default)
- minor fix of UI elements to make the font smaller
- centred labels and buttons

tags: #story[1246]
2017-09-22 13:53:36 +12:00
Kusal Ekanayake faeece27ff Started working on individual boat stats. Already modified turning rate. Need to add a vsual component.
#story[1274]
2017-09-22 13:52:35 +12:00
Michael Rausch 5e3ae40d03 Made discovery more reliable & added docs/tests
- Added unit tests
- Added documentation for discovery classes
- Improved error handling

Tags: #story[1281]
2017-09-22 00:01:13 +12:00
Michael Rausch 95ad7a4840 Finished implementing room codes.
- Fixed bug where room code wasn't parsed correctly
- Added room code selection to server list screen.
- Added room code to hosts lobby.
- Implemented communication protocols on the game client.

Tags: #story[1281]
2017-09-21 22:48:33 +12:00
Calum 6ca75b2cac Changed default race 2017-09-21 15:08:39 +12:00
Alistair McIntyre 6ff309a40c - Perspective Camera Works
- Top Down Camera Works
- Started on chase cam but the math is a bit tricky.

tags : #story[1273]
2017-09-21 14:40:35 +12:00
Calum 40a7f9bc5b New server creation view created. Added templates for custom races. Updated xml generator to remove all hard coded values. Updated XMLParser to parse custom race files. No unit tests exists currently.
#implement #story[1275]
2017-09-21 12:59:37 +12:00
Kusal Ekanayake c4a6113f6c Minor bug fixes (like all enemy sails being toggled in when they should be out)
#story[1274]
2017-09-20 21:07:49 +12:00
Kusal Ekanayake 307e79ecfc Completed working boat selection screen.
When a user selects a different boat, it is sent to all other clients and updates accordingly. Boats are all shown with their correct models in game.

#story[1274]
2017-09-20 20:46:23 +12:00
Michael Rausch e17e9749d8 Implemented server to manage a list of available servers on the internet.
- Implemented a server manager that keeps track of servers & room codes, and removes old servers
- Implemented queries to find a server with a specific room code
- Implemented protocol to register servers

#story[1281]
2017-09-20 20:26:14 +12:00
Kusal Ekanayake 7d8a6afa5f Merge branch 'new_meshes' into Custom_boat_selection 2017-09-20 19:40:43 +12:00
Peter Galloway ea0be5e952 Added pirate ship meshes to application. Updated boat model to allow for jib sails and a fixed sail. #story[1274] 2017-09-20 17:56:07 +12:00
William Muir 3be8cd264d Adding icon files to git
#story[1245]
2017-09-20 17:52:02 +12:00
Peter Galloway 7197bc2bee created meshes for pirate ship #story[1274] 2017-09-20 17:33:32 +12:00
William Muir 66d9a06f9e Adding icon files to git
#story[1245]
2017-09-20 17:19:14 +12:00
Calum fba522d0c3 Fixed BoatMeshType enum names.
#fix
2017-09-20 16:44:38 +12:00
Calum 0e829874c2 Fixed BoatMeshType enum names.
#fix
2017-09-20 16:43:04 +12:00
Calum c5d56065b6 Fixed cat ate a meringue sail rotation.
#fix #story[1274]
2017-09-20 16:42:26 +12:00
Kusal Ekanayake 410d765745 Started working on the boat selection screen.
Customised the boat customisation UI to contain it. Need to have another boat to test whether we can switch boats and also if the messages get sent correctly.

#story[1274]
2017-09-20 16:36:27 +12:00
Calum fe76e85c71 Merge branch 'develop' into new_meshes 2017-09-20 15:59:01 +12:00
Calum 9d61a43bd7 Added catamaran mesh to possible boat meshes. Made catamaran the default boat.
#implement #story[1274]
2017-09-20 15:58:22 +12:00
Kusal Ekanayake c39582de5c Updated PartyParrot logo 2017-09-20 15:41:20 +12:00
William Muir 034e4c252a Icons now display, blink when they are about to run off, and turn off after their time out
TokenType Enum now also has a timeout construction field
#story[1245]
2017-09-20 13:09:09 +12:00
William Muir 6cde016401 Fixed random token assigning and realisation
Token class now has two functions: assignRandomType and realiseRandomType
The former can be used to assign any random type to the token including the random type
The latter can be used to assign a concrete random type to the token (not the random type)

#story[1245]
2017-09-20 12:02:12 +12:00
Zhi You Tan d4d7ddf8e2 Keybinding now works in the actual race. A map of keybind is shared between GameClient and KeyBindDialogController.
#story[1278]
2017-09-20 11:02:13 +12:00
Zhi You Tan a1933c2869 - Created keybindingcontroller which can detect keypress and can save the keybind throughout the app
- Changed keybindingglyph to keyboard icon
- Fix button hover CSS to change text fill

#story[1278]
2017-09-20 02:42:02 +12:00
Zhi You Tan 8084a61333 Fix keybinding dialog creating on top of another keybinding dialog.
#story[1278]
2017-09-19 23:41:06 +12:00
William Muir 52d3cea592 Added preliminary icons for pickups
RaceView now has a grid pane to contain some icons to display power ups. These are just preliminary

ClientYacht now has a power up field that is set from recieveing messages in the Game Client, as well as observed by the RaceViewController to display the relevant icon when the powerup field is changed

#story[1245]
2017-09-19 23:04:17 +12:00
Zhi You Tan 03f5f91043 Done some CSS on keybindingdialog
#story[1278]
2017-09-19 19:49:36 +12:00
Peter Galloway 9ed52a1225 created catamaran mesh #story[1274] 2017-09-19 19:43:03 +12:00
Zhi You Tan 027324cc4f - Fixed JFXDialog initialised in lobby, raceview, serverlist controller by default. Now, dialog only appears when called.
- [WIP] Created keybindingdialog fxml. CSS not yet done.
 - Removed top most anchorpane on raceview so parent is stackpane like other views.

#story[1278]
2017-09-19 18:40:01 +12:00
William Muir 78596ea111 Initial commit for Power Up story
Made new preliminary models for each power up. Currently just different colour balls
Added new YachtEventTypes in the enum for each pick up to be sent out to clients
Tokens now not only randomise location but also randomise which type of token will be sent out
Added new methods to the MessageFactory class - Make collision and Make pickup Message
Game Client now checks what type of Yacht Event code has come in to respond appropriately rather than just generic collision / token.. although this has not been implemented yet
Game View loads appropriate token models depending on what is in XML

#story[1245]
2017-09-19 17:47:05 +12:00
Calum da263355f4 Changed raceview background.
#fix
2017-09-19 14:55:26 +12:00
Calum ebecd25ed2 Merge remote-tracking branch 'origin/develop' into develop 2017-09-19 14:54:15 +12:00
Calum 0f5137c2b6 Fixed the orientation of .stl files.
#fix
2017-09-19 14:52:02 +12:00
Kusal Ekanayake 73799954e4 Fixed tests that failed when running on lower end computers. Needed to add a couple of thread.sleeps 2017-09-15 12:47:40 +12:00
Haoming Yin edfeb2b287 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-14 15:40:26 +12:00
Haoming Yin 0355784000 Broadcast messages when boats pass legs or a token is picked up or expired.
tags: #story[1250] #pair[hyi25, zyt10]
2017-09-14 15:40:12 +12:00
Alistair McIntyre 02df69b7b4 - Merged Dev into branch
Tags: #story[1245]
2017-09-14 15:27:10 +12:00
Alistair McIntyre 242132b800 Merge remote-tracking branch 'origin/develop' into NewUI_merge
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-14 15:26:57 +12:00
Alistair McIntyre 3a671d4ed0 - Added Values to Finish Dialog.
Tags: #story[1245]
2017-09-14 15:24:58 +12:00
Alistair McIntyre 482d987839 - Fixed Null Pointer
- Build Should pass

Tags: #story[1245]
2017-09-14 15:10:48 +12:00
Haoming Yin cc124b2d19 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
2017-09-14 14:50:49 +12:00
Haoming Yin b3320ad805 Fixed server message sender
tags: #story[1246]
2017-09-14 14:49:25 +12:00
Alistair McIntyre 33779ad5c1 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-14 14:42:57 +12:00
Alistair McIntyre 3a41c27d8d - Race Finish Dialog showing up, unsure if its actually showing the correct ordering or not.
tags : #story[1245]
2017-09-14 14:42:25 +12:00
Calum e24203904b Removed print statements.
#chore
2017-09-14 14:37:22 +12:00
Calum eb188495ce Fixed position issues on exit arrows.
#implement #story[1266] #fix
2017-09-14 14:32:45 +12:00
Calum 62a7e2b8fa Fixed position issues on entry arrows.
#implement #story[1266] #fix
2017-09-14 14:21:04 +12:00
Michael Rausch acd0e790fe Added method to send server debug messages to players
Tags: #story[1246]
2017-09-14 14:14:21 +12:00
Zhi You Tan 46013474c0 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-14 13:37:01 +12:00
Alistair McIntyre bf427f24d3 - Created a Race Finish Dialog.
tags : #story[1245]
2017-09-14 13:34:48 +12:00
Alistair McIntyre 7d0a47446d - Fixed bug in customize dialog.
tags : #story[1245]
2017-09-14 13:02:31 +12:00
Alistair McIntyre 889098bb50 - Commented out broken test (non-deterministic thing)
- Merged 3d factory branch in

tags : #story[1245]
2017-09-14 12:46:17 +12:00
Alistair McIntyre 6223a8fc0b Merge remote-tracking branch 'origin/story1266_3d_model_factory' into NewUI_merge
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-14 12:40:20 +12:00
Calum 391bd33548 Fixed position issues on first 2 mark arrows.
#implement #story[1266]
2017-09-14 12:38:36 +12:00
Alistair McIntyre 7e0c2abbfd - Fixed a shutdown bug that left the game process running long after the window shut
- Changed SVG Icon for volume toggle to something a bit nicer

tags : #story[1245]
2017-09-14 12:31:49 +12:00
Calum 42a5e86bf8 Merge remote-tracking branch 'origin/NewUI_merge' into story1266_3d_model_factory
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-14 12:06:19 +12:00
Calum 20d73d8f2f Removed dead code from fxObjects and GameView 3D
#chore
2017-09-14 12:05:20 +12:00
Calum 0a62c538ca Added 3D mark arrows and cleaned up other classes. 2017-09-14 11:28:50 +12:00
Zhi You Tan 24a04aa530 Fix the wind direction arrow rotation.
#story[1245]
2017-09-14 01:05:52 +12:00
Haoming Yin 7ee6a09626 Fixed that wind speed did not updated frequently and UI polishing.
- added shadow for raceview boxes
- split up message history and input text block
- changed timer font

#story[1245]
2017-09-13 21:11:40 +12:00
Zhi You Tan 47798b19fe Added player position, boat speed, boat heading to race view.
#story[1245]
2017-09-13 11:22:05 +12:00
Zhi You Tan d9247eb031 Added player position, boat speed, boat heading to race view.
#story[1245]
2017-09-13 11:21:33 +12:00
Zhi You Tan 7b0d31438e Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge_ryan 2017-09-13 09:44:17 +12:00
Alistair McIntyre 1e74321aab - Lobby Disconnection works.
tags : #story[1245]
2017-09-12 18:26:25 +12:00
Zhi You Tan f0fc75feec [WIP] Adding player position, boat speed, boat heading
#story[1245]
2017-09-12 18:25:46 +12:00
Kusal Ekanayake c8dc448a52 Added tests for sounds and modified the transparency for the chat history window.
#story[1245]
2017-09-12 18:11:32 +12:00
Michael Rausch e518d13fd5 Fixed bug where number of players was off by 1
#story[1247]
2017-09-12 17:47:02 +12:00
Alistair McIntyre 167545cbef - Deleted old controllers that didn't do anything anymore.
tags : #story[1245]
2017-09-12 17:45:39 +12:00
Alistair McIntyre 20b656b16d - Fixed a bug in new customize dialog.
- Chat should work correctly when pressing enter now.

tags : #story[1245]
2017-09-12 17:26:52 +12:00
Alistair McIntyre 90a54beb8d Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-12 17:19:29 +12:00
Alistair McIntyre e375efb8e9 - Added documentation to controllers
- Moved Customization Dialog logic into LobbyController

tags : #story[1245]
2017-09-12 17:19:18 +12:00
Michael Rausch 06e9c55d2c Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-12 17:17:46 +12:00
Michael Rausch 9cba76f979 Fixed maven source encoding 2017-09-12 17:17:16 +12:00
Calum d5ce61a0ff Merge branch 'NewUI_merge' into story1266_3d_model_factory
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-09-12 17:09:47 +12:00
Alistair McIntyre 634322de3f Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-12 17:08:22 +12:00
Calum 6f534a430d Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
2017-09-12 17:04:37 +12:00
Calum 17b0864815 Moved transformation of boat icon view from controller class to model factory class.
#implement #story[1266] #refactor
2017-09-12 17:03:50 +12:00
Alistair McIntyre 3455321f01 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-12 16:54:55 +12:00
Alistair McIntyre 7e9e96c091 - Added documentation to controllers
tags : #story[1245]
2017-09-12 16:54:40 +12:00
Zhi You Tan b25c3367a9 Reimplemented wind. Wind arrow will rotate based on wind direction. Added labels for wind direction and wind speed.
#story[1245]
2017-09-12 16:52:44 +12:00
Kusal Ekanayake ec7ee34305 Fixed tests. 2017-09-12 16:52:26 +12:00
William Muir 9dad88e56a Fixed bug where server creation dialog validation was not working
#story[1245]
2017-09-12 16:45:52 +12:00
William Muir 6a4547f3f9 Minor fix so no lag when token is picked up
upon receiving a new RaceXML when one has been recieved we no longer update the course. Just update tokens

#story[1245]
2017-09-12 16:37:29 +12:00
Peter Galloway 71f626f57e fixed sail rotation broken from port to 3d #story[1266] 2017-09-12 16:30:20 +12:00
William Muir 1c343ec02d Changed the lobby map view to the 2D race rather than the 3D one.
Stripped back game view class appropriately.

#story[1245]
2017-09-12 16:13:14 +12:00
William Muir 5046ca6ffa Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-12 16:08:39 +12:00
William Muir bd31bae586 Changed the lobby map view to the 2D race rather than the 3D one.
Stripped back game view class appropriately.

#story[1245]
2017-09-12 16:08:29 +12:00
Michael Rausch 2f973deacc Merge branch 'NewUI_merge' of https://eng-git.canterbury.ac.nz/seng302-2017/team-13 into NewUI_merge 2017-09-12 15:56:31 +12:00
Michael Rausch f4c5e483ce Merge remote-tracking branch 'origin/3D_view_working_with_maven' into NewUI_merge 2017-09-12 15:56:17 +12:00
Haoming Yin bb3ee424cc Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-12 15:52:34 +12:00
Haoming Yin 99f38fa05f [WIP] Added wind image to the bottom left of the race view.
tags: #story[1245]
2017-09-12 15:52:22 +12:00
Kusal Ekanayake 6a8c77c670 Made the project successfully build and deploy using new libraries on a local maven repo. Removed old unused libraries.
#story[1266]
2017-09-12 15:11:27 +12:00
Kusal Ekanayake 659a521cc9 Started making a cucumber test for allchat.
Will need to incorporate mockito in order to mock controller input. Have commented out the tests as they are not working correctly yet.

 #story[1246]
2017-09-12 14:55:49 +12:00
Calum da3613fe36 Split off marker classes. 2017-09-12 14:48:30 +12:00
Calum 8dc3e54186 Merge remote-tracking branch 'origin/story1266_3d_model_factory' into story1266_3d_model_factory 2017-09-12 14:11:11 +12:00
Calum 8fd35392b0 Added experimental assets for water.
#story[1266] #implement
2017-09-12 14:11:00 +12:00
Alistair McIntyre bc9f0ea924 Injected a simple toggle into the decorator for the window for the sound.
Unsure if this is the best way to do it but not a bad thing to try for now.

tags : #story[1245] #story[1249]
2017-09-12 13:53:24 +12:00
Haoming Yin 6d9864e677 Fixed chat history text line spacing to a smaller amount.
tags: #story[1245]
2017-09-12 11:12:35 +12:00
Haoming Yin 8c2125276e Polished race view text area and send button UI style to make them pretty
tags: #story[1245]
2017-09-12 10:59:08 +12:00
alistairjmcintyre 235d6c9cef Added 3D element to lobby screen to show the player their boat before the race.
tags: #story[1245]
2017-09-12 03:57:29 +12:00
Michael Rausch 5dd936f8f1 Added chat functionality & timer back into the game + bug fixes
- Added chat back into the game
- Fixed a bug where the timer would show "race finished" when the race hadn't started
- Fixed a bug where resources weren't being deallocated when the game was closed

Tags: #story[1246]
2017-09-12 01:31:38 +12:00
Michael Rausch d223d393fa Merge branch 'story1266_3d_model_factory' into NewUI_merge 2017-09-11 23:45:31 +12:00
Haoming Yin aa098569f3 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-11 23:43:46 +12:00
Haoming Yin d49e84e6d2 Fixed a bug that race view doesn't fit in decorator.
- recreated a new stage and decorator to fix the bug as decorator might
not be able to be reused.

#story[1245]
2017-09-11 23:42:08 +12:00
Michael Rausch 75bf92a67f Added map image to lobby screen
- Lobby screen has map of the course
- Map resizes with window

Tags: #story[1245]
2017-09-11 23:24:21 +12:00
Haoming Yin 0d7201e235 Race view is default to be full screen now and minor bug fixes.
- race view is force to be full screen and run in a new stage
- fixed button animations in lobby view
- polished UI element is boat customization dialog

#story[1245]
2017-09-11 23:04:41 +12:00
cir27 0197de6fe3 Drawing player icon assets but line segment was not added to repo some app crashes.
#implement #story[1266]
2017-09-11 22:19:08 +12:00
cir27 d79ff0f1cf Merge remote-tracking branch 'origin/story1266_3d_model_factory' into story1266_3d_model_factory
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelType.java
2017-09-11 22:03:52 +12:00
cir27 18f36d7ea4 Added assets to identify the player. Needs to merge with 3d player specification for code side to be implemented.
#story[1266] #implement
2017-09-11 22:02:21 +12:00
Michael Rausch 131cd80e02 Added button sounds on hover, click and in the lobby
- Started playing start & lobby sounds
 - Started playing button hover & click sounds

Tags: #story[1249]
2017-09-11 19:50:17 +12:00
Alistair McIntyre 3d0209300e - Validation completely done
- Some documentation added.

tags : #story[1245]
2017-09-11 19:36:16 +12:00
hyi25 6b4f7eb42b Merge develop into NewUI, and 3D
tags: #story[1245]
2017-09-11 18:56:26 +12:00
Kusal Ekanayake 8b9b3a31bd Trying to start getting the 3D branch to successfully build and run on git and on computers.
Solving maven issues.
2017-09-11 18:50:01 +12:00
Haoming Yin 0bf83aa858 Merge remote-tracking branch 'origin/develop' into NewUI_merge
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java
#	src/main/java/seng302/visualiser/controllers/LobbyController.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/java/seng302/visualiser/controllers/StartScreenController.java
#	src/main/resources/views/LobbyView.fxml
#	src/main/resources/views/RaceView.fxml
#	src/main/resources/views/StartScreenView.fxml
2017-09-11 18:15:08 +12:00
Calum dff261cf41 Added 3D assets for a trail and generated them at regular intervals.
#story[1266] #implement
2017-09-11 17:16:13 +12:00
William Muir 83ee217cef Merge branch 'Story1248_Game_App_Scaling' into 'develop'
Story1248 Race view scaling

# Changes
* Added listener to widthProperty and heightProperty in GameView.fxml.
* Changed some of the race view fxml hierarchy to support resizing.

# Testing
* Manual test log completed.

See merge request !70
2017-09-11 17:11:27 +12:00
William Muir d4826739e3 Merge branch 'develop' into Story1248_Game_App_Scaling 2017-09-11 16:56:49 +12:00
William Muir fdfb5959fa Minor change so that boats still are checked for collision after passing the finish line
#story[1250]
2017-09-11 16:53:12 +12:00
Calum 878c0e0f43 Added ocean asset. Moved camera to center of race.
#story[1266]
2017-09-11 16:24:21 +12:00
Zhi You Tan 1ce8df976c changed name: contentanchorpane to contentgridpane
#story[1248]
2017-09-11 16:08:24 +12:00
Zhi You Tan 6fcd4ae4cc updated raceview javafx after develop merge to bring in text chat pane.
#story[1248]
2017-09-11 16:01:07 +12:00
William Muir 534eaee8ce Merge remote-tracking branch 'origin/develop' into develop 2017-09-11 15:54:30 +12:00
William Muir ab35e3506d fixed bug
#story[1250]
2017-09-11 15:54:16 +12:00
Michael Rausch 1fec620427 Merged 3d branch into new UI
Tags: #story[1245]
2017-09-11 15:50:22 +12:00
Zhi You Tan 00100eb991 Merge remote-tracking branch 'origin/develop' into Story1248_Game_App_Scaling
# Conflicts:
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/resources/views/RaceView.fxml
2017-09-11 15:47:47 +12:00
Kusal Ekanayake 58512fdbdf Replaced hover sound to work in .jar.
#story[1249]
2017-09-11 15:40:13 +12:00
Michael Rausch 76a1a3c7a0 Merge remote-tracking branch 'origin/story1266_3d_model_factory' into NewUI_merge
# Conflicts:
#	pom.xml
#	src/main/java/seng302/App.java
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/utilities/XMLGenerator.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/resources/views/RaceView.fxml
#	src/main/resources/views/StartScreenView.fxml
2017-09-11 15:29:33 +12:00
William Muir 1b8c503712 fixed bug
#story[1250]
2017-09-11 15:29:08 +12:00
William Muir 334e13295f fixed bug
#story[1250]
2017-09-11 15:24:42 +12:00
William Muir 0c4d001510 Merge remote-tracking branch 'origin/develop' into develop 2017-09-11 15:11:49 +12:00
William Muir 24a3a54ccb Added sounds to coin pick up
Refactored check for token collision to move into the generic check for collision method
Created a YachtEventType enum to differentiate between collision and pickup on client side.
Client now plays a sound when they pick up a token

#story[1250]
2017-09-11 15:11:11 +12:00
Alistair McIntyre 40408cff27 -Validation on server list screen and server creation dialog done.
tags : #story[1245]
2017-09-11 15:08:34 +12:00
William Muir 9fcb8915c2 Added sounds to coin pick up
Refactored check for token collision to move into the generic check for collision method
Created a YachtEventType enum to differentiate between collision and pickup on client side.
Client now plays a sound when they pick up a token

#story[1250]
2017-09-11 14:45:04 +12:00
Kusal Ekanayake caf910c4c5 Adjusted volume to make more balanced.
#story[1249]
2017-09-11 14:39:40 +12:00
Kusal Ekanayake 4f07786449 Changed the hover noise from a mediaplayer to an audio clip.
Fixes #50

#story[1249]
2017-09-11 14:21:47 +12:00
Alistair McIntyre 2b53e0d5b4 Validation fixed on server list screen.
Server List Screen done.
tags : #story[1245]
2017-09-11 13:51:29 +12:00
Calum 1210f9342b Removed rounding in GameView that caused objects to be rendered at incorrect positions.
#bug
2017-09-11 11:37:50 +12:00
cir27 f136a970db Added placeholder assets for velocity pickups. 2017-09-11 03:11:42 +12:00
alistairjmcintyre 800ae2864f - Fixed a missing validation call.
tags: #story[1245]
2017-09-11 02:55:47 +12:00
alistairjmcintyre e764caee60 - Learned how JFX Validators work and implemented them for direct connection.
- Aside from the error message when a server cannot be found (which is the default javafx one) I think the serverlist is pretty much done.

tags: #story[1245]
2017-09-11 02:53:41 +12:00
cir27 78b4786482 Added assets for the border and for gates. Drew them in correct locations.
#implement
2017-09-11 02:50:31 +12:00
cir27 e3ccb570ed Merge remote-tracking branch 'origin/story1266_3d_model_factory' into story1266_3d_model_factory 2017-09-10 22:54:49 +12:00
cir27 470bf121a5 Added assets for borders. 2017-09-10 22:54:40 +12:00
alistairjmcintyre f077486e22 - Added methods for validating direct connection, Port Number Complete, Host Name not Complete.
- Added No Servers found Message
- Found a potential bug with windows machines not running the correct service to handle Bonjour Service Addresses.

tags: #story[1245]
2017-09-10 18:24:15 +12:00
Haoming Yin 717f7558d9 Fixed issue that when go back to start screen, start view doesn't fit
in to the decorator properly.

- Moved start screen view initialization logic into ViewManager.
- When go back to start screen view, a new stage within the start screen
view will be initialized.

#story[1245]
2017-09-10 12:43:17 +12:00
Zhi You Tan 05236337ba Fixed horizontal and vertical resizing not to draw larger than scene.
#story[1248]
2017-09-10 03:17:26 +12:00
Zhi You Tan 1b76d59acb Removed drawGoogleMap()
#story[1248]
2017-09-10 02:21:30 +12:00
William Muir 02e6d2a98b Fixed Client connection delegate bug
#story[1250]
2017-09-09 18:26:22 +12:00
Calum 06a4dde216 Ported game rendering to 3d environment for boats and markers.
#implement
2017-09-09 17:34:18 +12:00
Haoming Yin 1516e817b7 Fixed some UI bugs, and redesigned some UI elements.
- Changed class structure (added dialogs, cells folder)
- Changed font to Baloo as it has better font height
- Figured out a way to change the font color of max player slider thumb
- Added cursor effect when mouse hover on any button
- Fixed drop shadow bug for lobby view player cell
- Moved drop shadow effect from player cell controller to css

#story[1245]
2017-09-09 15:00:32 +12:00
William Muir bd7ea920b6 Fixed Client connection delegate bug
#story[1250]
2017-09-09 14:46:42 +12:00
William Muir 4a170f8179 Merged new develop on
#story[1250]
2017-09-09 14:13:50 +12:00
William Muir 1f9e6154ae Merge branch 'develop' into 1250_SendingGameObjects
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-09-09 14:02:12 +12:00
William Muir 5595e0439b Merge branch 'Story1249_SoundsAndMusic' into 'develop'
Story1249 sounds and music AND text chat

## Changes
* Added music for the following parts of the game:
    * Menu music
    * Race music
    * Finish screen music
* Added sound effects for the following events:
    * Button clicking
    * Button hovering (Although it is incredibly quiet)
    * Cap gun when the countdown hits 00:00
    * Ambient ocean noises
    * Collisions (between boats and boats, marks, gates, boundaries)
    * Boat rounding a mark
    * Boat finishing the race 
* Chat window now appears in lower right for all clients/host
* When the message is sent using the 'Enter' key or the send button, all clients/host receive the message in the senders boat colour
* There are two "cheat codes" which when types into chat give the following effect:
    * ">speed x" - Will multiply all boats speeds by x
    * ">finish" - Will make the race automatically finish and move to the finish screen

## Testing
* Manual test log completed
* Unit tests completed for chat cheat codes
* Cucumber tests completed for general sending of chat between clients 

See merge request !69
2017-09-09 13:17:12 +12:00
Calum 08f7127b69 Altered test to hopefully fix occasional indeterministic bug that occurred. 2017-09-09 13:13:45 +12:00
William Muir 8ba28ffda0 Minor refactor moving Spawning and token creation to game state
#story[1250]
2017-09-09 13:11:44 +12:00
Calum edd52a07a7 Added logger to HeartBeatThread. 2017-09-09 13:07:04 +12:00
Calum 875a6b4e98 Merge remote-tracking branch 'origin/Story1249_SoundsAndMusic' into Story1249_SoundsAndMusic 2017-09-09 13:04:00 +12:00
Calum faefcc7938 Fixed bug with initializing race view elements. Made chat box unselectable. Only manually tested.
#bugs #test #implement
2017-09-09 13:03:55 +12:00
William Muir 0c956f93c8 Merge request fixes. minor refactor
#story[1246]
2017-09-09 12:37:31 +12:00
Calum 0e2946f20b Added ocean object 2017-09-09 12:34:08 +12:00
Zhi You Tan f66ef3c208 [WIP]
- Horizontal and vertical resizing works fine now.
- Issue: Have to implement maximum horizontal and vertical scaling.

#story[1248]
2017-09-09 03:14:10 +12:00
Michael Rausch cf4f8813d2 re-implemented existing functionality in UI
- Correct player count is shown in server list
- Servers now advertise their capacity and number of players connected
- Players can click join on the servers in the server list
- Direct connect works
- Can set max players / server name in host dialog
- Server starts correctly when host clicked
- Implemented boat customization
- Implemented 'begin race button', and disabled it for players that aren't hosts
- Added countdown timer in lobby
- Fixed bug where app wouldn't close

Tags: #story[1245]
2017-09-08 18:00:09 +12:00
William Muir e2bc613c9d Merge request fixes
#story[1246]
2017-09-08 15:52:01 +12:00
cir27 c2c3c9eb53 Experimented with parallel camera in 3d gameview. Works ok for rendering boats in isometric view.
#test
2017-09-08 14:05:52 +12:00
cir27 cadf995bf7 Added area rounding area to mark assets.
#implement
2017-09-08 13:32:17 +12:00
cir27 62f139c604 Added 3D window to GameView3D to begin adding assets to. Used it to refine all 3D assets implemented by ModelFactory and manually test that they work.
#implement #test
2017-09-08 01:51:31 +12:00
cir27 0bf6dd9e6b Added 3D window to GameView3D to begin adding assets to. Used it to refine all 3D assets implemented by ModelFactory and manually test that they work.
#implement #test
2017-09-08 01:50:56 +12:00
Calum eed5f56690 Created factory class for making different views for 3d models of boats.
#implement
2017-09-07 19:23:07 +12:00
Michael Rausch b35126ff4e Added server list updates, and added lobby
- Server list updates when a server is added/removed
- Player can host a server
- Lobby view shows players connected

Tags: #pair[mra106, hyi25] #story[1245]
2017-09-07 19:20:36 +12:00
Calum c39499cee7 Fixed 3d tests 2017-09-07 18:17:42 +12:00
Kusal Ekanayake cff15ba07d Added missing button click.
#story[1249]
2017-09-07 17:54:28 +12:00
Kusal Ekanayake 6be7c17c40 Fixed manual test bugs in sounds.
#story[1249]
2017-09-07 17:39:59 +12:00
Calum 64811354e3 added peters boat 2017-09-07 17:09:52 +12:00
Kusal Ekanayake 3364f8b516 Made chat history transparent.
#story[1246]
2017-09-07 17:02:42 +12:00
Michael Rausch 8cc725616c Merge remote-tracking branch 'origin/Story1247_AutoDiscovery' into NewUI
# Conflicts:
#	pom.xml
#	src/main/java/seng302/App.java
#	src/main/java/seng302/visualiser/controllers/StartScreenController.java
#	src/main/resources/views/StartScreenView.fxml
2017-09-07 16:36:30 +12:00
Michael Rausch 0feccdc8b9 Replaced existing views with new views and controllers from the test repository.
Tags: #pair[mra106, ajm412] #story[1245]
2017-09-07 16:32:34 +12:00
Calum 1a755cec33 Fixed bug that caused mark arrows to be rendered on Marker id not LegNumber
#bugs
2017-09-07 16:25:55 +12:00
Calum d565552fcc Added jar files to repo 2017-09-07 15:34:38 +12:00
Calum 26a8d76f8b Merged with remote changes 2017-09-07 14:56:08 +12:00
Calum d87dcaa4fe Merged with remote changes 2017-09-07 14:54:23 +12:00
Kusal Ekanayake 0b61dffe71 Fixed some docstrings to make build work.
#story[1246]
2017-09-07 14:50:08 +12:00
Zhi You Tan 4e69157c09 Merge remote-tracking branch 'origin/Story1248_Game_App_Scaling' into Story1248_Game_App_Scaling
# Conflicts:
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/resources/views/RaceView.fxml
2017-09-06 01:27:57 +12:00
Zhi You Tan d67566e217 [WIP]
- changed contentAnchorPane to Grid Pane temporarily so added child will be able to resize natively
- implemented zooming when resizing
Bugs:
- horizontal resizing works as intended, but vertical resizing will result in canvas moving far too left
- need to solve the right and bottom empty space when resizing

#story[1248]
2017-09-06 01:26:12 +12:00
Kusal Ekanayake 56f1dd2efb Reverted change, didn't work.
#story[1246]
2017-09-05 18:20:56 +12:00
Kusal Ekanayake 302bc91461 Tried to fix build by removing invalid '>' char.
#story[1246]
2017-09-05 18:17:20 +12:00
Kusal Ekanayake 488ab47c8d Finished off chat cucumber test.
#story[1246]
2017-09-05 18:00:43 +12:00
Kusal Ekanayake 0650ba30e2 Fixed chat tests
#story[1246]
2017-09-05 17:27:34 +12:00
Calum 04518c35b0 Created new yacht shape and altered the number of lights.
#implement
2017-09-05 17:17:42 +12:00
Kusal Ekanayake f33e4cc137 Added finish music and merged with text chat.
#story[1249]
2017-09-05 15:24:56 +12:00
Kusal Ekanayake 7a4b3f0ad9 Merge branch 'text_chat' into Story1249_SoundsAndMusic
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/StartScreenController.java
2017-09-05 14:42:20 +12:00
Kusal Ekanayake 1619c95098 Added mark rounding noise and hover button noise.
#story[1249]
2017-09-05 14:33:37 +12:00
Kusal Ekanayake 396098e009 Added finish noise.
#story[1249]
2017-09-05 13:44:14 +12:00
Calum e4dbbd05c7 Merged with remote changes 2017-09-04 23:42:10 +12:00
Calum a1e3ec54c7 Merge remote-tracking branch 'origin/text_chat' into text_chat 2017-09-04 23:11:02 +12:00
Calum 47f3f6e27d Created a new chat history class that allows for rich formatting of individual messages. Current implementation allows for bold and coloured text only. Has been manually tested. Fixed 3/5 chat command tests.
#implement #test #story[1246]
2017-09-04 23:10:54 +12:00
Kusal Ekanayake fce7aa4f9a Started making a cucumber test for allchat.
Will need to incorporate mockito in order to mock controller input. Have commented out the tests as they are not working correctly yet.

 #story[1246]
2017-09-04 19:43:05 +12:00
Calum 81afad1bcc Wrote tests that are currently broken for sending server commands through text chat.
#tests
2017-09-04 14:43:13 +12:00
Calum 5026c568a7 Wrote tests that are currently broken for sending server commands through text chat.
#tests
2017-09-03 20:38:31 +12:00
Calum 88d1e91b6f Added processing of input from host via chat to manually trigger race finishing or to speed up boats.
#implement
2017-09-03 19:18:30 +12:00
Calum 67f39e9049 Tested several methods of creating 3D assets. Added a 3D file importer to library of project and replaced some assets with temporary 32 ones to test creating 32 objects.
#implement
2017-09-03 16:54:53 +12:00
Michael Rausch eb1d3f1a60 Fixed bug where discovery wasn't working under windows
- getLocalHost() was returning the networks public IP address, changed this to getByName() for the local IP

Tags: #story[1247]
2017-09-02 02:16:40 +12:00
Zhi You Tan 54ca12f3b6 [WIP]
- Updated raceview.fxml to scale race view when resize.
- Implemented a listener on game view to know the current window size.
Issues:
- Border updates with resizing until a certain size and it draws out of canvas
- Marks are not drawn within border
- Trails do not scale at all
2017-09-01 17:10:00 +12:00
Michael Rausch 3f910b8db7 Fixed JavaDoc errors by adding missing parameters 2017-09-01 16:13:18 +12:00
Michael Rausch b346d5a706 Implemented server re-registration when a server closes / updates
- When a server is closed, it will disappear from the server list
- When a player joins a server, the number of spaces left will decrease
- Servers now disappear instead of duplicating
- Added tests for ServerDescription
- Added documentation for new classes

Tags: #story[1247]
2017-09-01 16:05:47 +12:00
Peter Galloway 45fa73595f fixed being able to zoom while chatting by holding shift and then pressing z and x #story[1246] 2017-08-31 17:26:02 +12:00
Peter Galloway 01ca3f3453 tweaked formatting of chat history #story[1246] 2017-08-31 17:06:13 +12:00
Peter Galloway ba8e333d81 fixed issue with the chat history updating weirdly (made sure it run synchronously with platform.runlater) #story[1246] 2017-08-31 16:49:12 +12:00
Peter Galloway 24d4c1df15 made chat history always scroll to the bottom after a message is sent #story[1246] 2017-08-31 16:35:51 +12:00
Michael Rausch 0c5d661995 Fixed discovery bug, implemented server list, added server parameters
- Resolved DNS bug by updating to a newer version of JmDNS
- Added server list, this is populated with new servers as they are discovered
- Added map name and spaces remaining to server advertisement

Tags: #story[1247]
2017-08-31 01:11:17 +12:00
Michael Rausch 262f27fa8a Added basic auto discovery functionality
- Servers can advertise themselves
- Clients can detect servers on their local network

Tags: #story[1247]
2017-08-30 22:53:45 +12:00
Peter Galloway 0fcdf41419 fixed broken fps counter #story[1246] 2017-08-30 20:56:28 +12:00
Peter Galloway 4ebf7d6104 chat packets sent to server and then sent back to all clients. #story[1246] 2017-08-30 20:42:11 +12:00
Peter Galloway 353dd48829 sending chatter packets to server #story[1246] 2017-08-30 19:14:47 +12:00
William Muir 4bd7291a4a WIP: Yachts now power up upon collecting an item
Power up is speed boost x2 multiplier
Lasts 10 seconds
Do not stack

#story[1250]
2017-08-29 22:11:37 +12:00
William Muir 0d0b2e59d5 WIP: Tokens works well with collection. Dissapear upon picking up across all clients.
Still bug with mark ordering and arrows :/

#story[1250]
2017-08-29 21:40:25 +12:00
William Muir ace48a8404 Refactored MainServer Class in prep for better sending out of XML messages
All messages are now created through MessageFactory class
Minor tweaks to improve code base server side
Removed observer from Server to Client threads

#story[1250]
2017-08-29 21:23:46 +12:00
William Muir 201405d070 WIP: Marks randomly appear in course now. Mark arrows broken.
Something about sending raceXML during the course of the race breaks the mark rounding arrows functionallity, crashing the game.

#story[1250]
2017-08-29 19:13:48 +12:00
William Muir dc19310849 Tokens now appear client side
#story[1250]
2017-08-29 17:17:06 +12:00
William Muir 1c866ea8c2 GameClient now extracts Tokens client side
#story[1250]
2017-08-29 16:50:31 +12:00
William Muir 23027705da Sample Tokens are now sent out in RaceXML correctly
Token and TokenType class created

#story[1250]
2017-08-29 15:37:01 +12:00
William Muir c15f13bc2c Refactored some of the XMLGenerator code. Added tokens to the generated XML
Refactor not complete. Generation needs some tidying.

#story[1250]
2017-08-29 14:56:06 +12:00
Kusal Ekanayake 6ee2517f74 Added most sound functionality.
There is not background music and sound effects (button clicking, ocean noises, crashes for collisions). Can mute the sound and the music independently of each other from the main menu.

#story[1249]
2017-08-28 16:37:09 +12:00
Peter Galloway 75155fe481 implemented basic single client proof of concept for the chat history #story[1246] 2017-08-25 17:57:45 +12:00
William Muir 2fcff65dd6 Fixed null pointer when cant find a server
tags: #fix
2017-08-17 15:44:05 +12:00
William Muir 4c730ea890 Fixed null pointer when cant find a server
tags: #fix
2017-08-17 15:40:55 +12:00
Alistair McIntyre a501b21d66 Merge branch 'develop' into 'master'
Sprint 6.0 Merge

Merge for sprint 6.0 tag to master.

See merge request !67
2017-08-17 14:59:01 +12:00
Alistair McIntyre 5fb8a0c2c1 Merge branch 'issue47_disconnect_crash_rebranch' into 'develop'
Issue47 disconnect crash rebranch

Fix for all disconnection issues. Fix is not robust. Need consistent interface between disconnection of ServerToClientThreads and MainServerThread.

See merge request !66
2017-08-17 14:55:45 +12:00
Alistair McIntyre d867a4b7a2 Fixed bug, should fix disconnection issues.
tags : #issue[47]
2017-08-17 14:53:54 +12:00
Michael Rausch 3c91db59f3 Changed wind change variation 2017-08-17 14:49:39 +12:00
Alistair McIntyre 72a390b484 Fixed build bug.
tags : #issue[47]
2017-08-17 14:47:20 +12:00
Alistair McIntyre 978def4cf7 Merge remote-tracking branch 'origin/develop' into issue47_disconnect_crash_rebranch
# Conflicts:
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-08-17 14:36:16 +12:00
Alistair McIntyre 2331942bf9 Merge branch 'Story1124_Sparkline' into 'develop'
Fixing Ordering

# Changes 
* Fixed ordering which was broken from a previous commit 
* Removed Sparkline as we could not get it working in time 

# Testing 
* Manual testlog only 

See merge request !65
2017-08-17 14:25:32 +12:00
Calum d41bdfebbc Merged Boat customization onto develop.
#bug #merge #refactor
2017-08-17 14:21:06 +12:00
Calum d0565503e8 Merge branch 'develop' into issue47_disconnect_crash_rebranch
# Conflicts:
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/GameClient.java
2017-08-17 14:15:27 +12:00
Haoming Yin f0c48e76e1 Merge branch 'Story80_BoatCustomization' into 'develop'
Story 80: Boat Customization

# Implementation
- Added Messages for Boat Customization Requests and Responses.
- Added functionality to handle Name and Boat Color Customization. (Shapes would be a next sprint thing)

# Testing
- Manually tested personally, will test correctly when boat shapes have also been implemented.


See merge request !64
2017-08-17 14:11:04 +12:00
Calum 3639e0d3ce Fixed disconnection issues. Fix is only temporary until a consistent interface for disconnections exists.
#bug #implement
2017-08-17 14:10:38 +12:00
Calum 0276911b88 Fixed disconnection issues. Fix is only temporary until a consistent interface for disconnections exists.
#bug #implement
2017-08-17 14:02:18 +12:00
Alistair McIntyre af3a400841 Fixed build bug.
tags : #story[1142]
2017-08-17 13:44:34 +12:00
Zhi You Tan 5a2a78a7d5 Bug fixes for final commit 2017-08-17 13:43:31 +12:00
Alistair McIntyre 5fc7442359 Merged Develop into branch.
tags : #story[1142]
2017-08-17 13:40:00 +12:00
Alistair McIntyre 39cfaf6780 Merge remote-tracking branch 'origin/develop' into Story80_BoatCustomization
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/ServerPacketParser.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/gameServer/messages/ChatterMessage.java
#	src/main/java/seng302/gameServer/messages/MarkRoundingMessage.java
#	src/main/java/seng302/model/ServerYacht.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/GameView.java
2017-08-17 13:31:27 +12:00
Zhi You Tan 7a11b5eb77 Merge branch 'develop' into Story1124_Sparkline 2017-08-17 13:14:08 +12:00
Alistair McIntyre faf4600f51 Fixed some weird bug with the messages package, trying to add some small QoL changes with potential interaction bugs with the customization/lobby menu.
tags : #story[1142]
2017-08-17 13:13:07 +12:00
Zhi You Tan 3e383465a9 Attempted to fix sparklines, temporarily disabled them for end of sprint. 2017-08-17 13:12:09 +12:00
Alistair McIntyre ac279583df Small documentation changes.
tags: #story[1142]
2017-08-17 12:31:15 +12:00
Calum ef2659a7b9 Merge branch 'develop' into issue47_disconnect_crash_rebranch
# Conflicts:
#	src/main/java/seng302/visualiser/GameClient.java
#	src/test/java/seng302/visualiser/ClientToServerTests/RegularPacketsTest.java
2017-08-17 12:16:14 +12:00
Calum 769d1956b3 Moved client side disconnection handling to this branch and reimplemented it with develop functionality.
#refactor #issue[47]
2017-08-17 12:11:36 +12:00
Haoming Yin 8ca455ed24 Fixed:
-  Fixed regularPacketsTest unit test, which checks how regularly packets are sent from C2S thread.
- Removed misused GameClient in main server thread.

tags: #story[1124]
2017-08-17 12:03:43 +12:00
Haoming Yin 7bda2bc580 Fixed:
-  Fixed regularPacketsTest unit test, which checks how regularly packets are sent from C2S thread.
- Removed misused GameClient in main server thread.

tags: #story[1124]
2017-08-17 11:46:14 +12:00
Haoming Yin d7a290478d Merge remote-tracking branch 'origin/develop' into develop 2017-08-17 11:02:54 +12:00
alistairjmcintyre d73e4f8ec5 Fixed a build error.
tags: #story[1142]
2017-08-17 01:23:34 +12:00
alistairjmcintyre 6e02d3e533 Added some general UI improvements such as autofilling the color field of the form, and looked at how best to deal with response packets, as it should be part of the spec.
tags: #story[1142]
2017-08-17 01:20:16 +12:00
Calum 7b4a70817b Merged onto develop.
#mergre #refactor
2017-08-17 01:03:14 +12:00
Calum 87acce71ea Merge branch 'develop' into story1118_map_arrows
# Conflicts:
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/model/RaceState.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-08-17 00:52:41 +12:00
Calum 95b1c8a01f Arrows now work as intended. Case added for interior angles.
#implement #story[1118]
2017-08-17 00:43:07 +12:00
Zhi You Tan dfd421c3b7 Merge branch '1124b_Fixing_Update_Order' into 'develop'
Updating Yacht Positions / Finish Screen

# Change Log 
* Yachts now update their position on the side bar as they pass marks 
* Finish screen is now displayed correctly at end of race, populated by races 

# Testing 
* Manual test log performed


See merge request !63
2017-08-17 00:11:13 +12:00
William Muir 4596f1e0f8 Finish screen all done, updates during race
tags: #story[1124] #pair[wmu16, cir27]
2017-08-16 23:42:07 +12:00
William Muir a59d06fbbf Finish screen 2017-08-16 23:36:45 +12:00
William Muir 65286f273b Working ordering for in game AND race finish screen.
List in RaceState holds a sorted list of yachts.
A Listener is added to this list, listening for a permutation change, on perm change, sorts the list by comparitor of leg number of each yacht (stable sort)
2017-08-16 23:22:58 +12:00
William Muir 9727e86249 Merge remote-tracking branch 'origin/story1118_map_arrows' into 1124_Fixing_Order_And_Finish_Screen
# Conflicts:
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/resources/server_config/xml_templates/race.ftlh
2017-08-16 22:40:32 +12:00
William Muir db614fe845 Initial commit for Fixing order 2017-08-16 21:16:27 +12:00
Calum 85899e3fbe Merged with develop functionality. 2017-08-16 21:11:34 +12:00
Michael Rausch 87d6799c10 Re-added wind speed & direction variations
- Wind speed  & direction are randomly updated
- Removed two duplicate threads ;)

Tags: #story[1124]
2017-08-16 20:48:37 +12:00
Alistair McIntyre 67f0c213c2 Everything works. Needs a bit of polish, and possibly look at boat shapes next.
tags: #story[1142]
2017-08-16 20:38:11 +12:00
Calum c103595bba Merge branch 'develop' into story1118_map_arrows
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/model/RaceState.java
#	src/main/java/seng302/visualiser/GameClient.java
2017-08-16 20:34:27 +12:00
Calum 86a7c2565c Arrows now rendered in correct orientation but rounding arc sometimes inverted.
#implement #story[1118]
2017-08-16 20:29:56 +12:00
Calum 21e6819f16 Arrows now rendered in correct orientation but rounding arc sometimes inverted.
#implement #story[1118]
2017-08-16 20:17:25 +12:00
William Muir 28569506f0 Merge remote-tracking branch 'origin/develop' into develop 2017-08-16 20:09:20 +12:00
William Muir dad2ebf693 Fixed double thread issue! :D 2017-08-16 20:09:05 +12:00
Alistair McIntyre 02a7b804c1 Boat Names Change. Colors Change too. Updates clients during lobby when a change is made.
tags: #story[1142]
2017-08-16 19:31:27 +12:00
Peter Galloway 9dbb31dcef Merge branch 'Story40_Zooming' into 'develop'
Story40 zooming

# Zooming and Tracking
## Changes
* Boats can now be selected by clicking and selecting on the drop down menu
* Selected boats can now be tracked when the zoom level is increased
* Zoom in with the 'z' key and zoom out with the 'x' key

## Testing
* Manual testing logged in doc
* No cucumber tests made for this story

## Bug Fixes
* Fixed the sails animation bug

See merge request !62
2017-08-16 18:25:58 +12:00
Kusal Ekanayake a932f41cc2 Removed unused boolean in boat objects 2017-08-16 18:19:55 +12:00
Kusal Ekanayake 3570a3d2eb Removed unneeded imports 2017-08-16 18:16:55 +12:00
Kusal Ekanayake 85852df176 Modified limits to zooming
#story[1121]
2017-08-16 18:06:39 +12:00
Alistair McIntyre 6d045e9976 Merge branch 'develop' into Story80_BoatCustomization
# Conflicts:
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/LobbyController.java
2017-08-16 17:59:11 +12:00
Alistair McIntyre 4fc00f8a3c Boat names now change, just the issue of the lobby not updating unless another person joins/leaves to try and fix.
tags: #story[1142]
2017-08-16 17:57:22 +12:00
Kusal Ekanayake 9c2bac36b6 Merge branch 'develop' into Story40_Zooming 2017-08-16 17:27:09 +12:00
Kusal Ekanayake 8501fc0b6d Added limits to zooming
#story[1121]
2017-08-16 17:25:51 +12:00
Michael Rausch e9e7f306cd Merge branch 'Story1117_Course_Boundary_Collision' into 'develop'
Checked if a boat has crossed the boundary/course limit, if so, bounce the boat back.

# Boundary crossing detection
* if a boat has crossed the boundary, it will be bounced back to where it has came from

# Testing
* Manual testing has been done.
* Boats have bounced back when collides with other boats, mark or boundary. 

#story[1117] #pair[hyi25, zyt10]

See merge request !60
2017-08-16 17:25:14 +12:00
Michael Rausch fa68a5fdff Fixed commented out test
#story[1117]
2017-08-16 17:23:52 +12:00
William Muir 07a39722fb Minor bug fix to velocity calculation 2017-08-16 17:23:14 +12:00
William Muir 1d4ab0e1fa Merge remote-tracking branch 'origin/develop' into develop 2017-08-16 17:22:14 +12:00
William Muir 653651f97f Minor bug fix to velocity calculation 2017-08-16 17:22:00 +12:00
Haoming Yin b1ba6e729a Merge branch 'StartScreen' into 'develop'
Start screen

## Changes
* Race timer now works
* Lobby switches to race view at T-5 seconds
* Updated lobby title to show race name

## Testing
* Manual testing completed
* No unit or cucumber testing as this is mostly UI code

See merge request !61
2017-08-16 17:12:17 +12:00
Haoming Yin 99685d76a9 Merge remote-tracking branch 'origin/develop' into develop 2017-08-16 16:55:53 +12:00
Michael Rausch 711c94001b Fixed game crash, and improved timer
- Fixed the null pointer exception that happened on slower computers
- Made the timer start counting down when the host clicks ready

Tags: #story[1109]
2017-08-16 16:34:31 +12:00
Zhi You Tan 7f3d66d01d Checked if a boat has crossed the boundary/course limit, if so, bounce the boat back.
#story[1117] #pair[hyi25, zyt10]
2017-08-16 16:33:14 +12:00
Alistair McIntyre 1db75a8ae4 Request Messages now sending to server, need to update game and send response packet.
tags: #story[1142]
2017-08-16 14:54:50 +12:00
Kusal Ekanayake 7b9d28ade9 Progress made on the improper tracking of boats (boats aren't being correctly centered). 2017-08-16 14:51:52 +12:00
Michael Rausch 5843fc9212 The merge went well!!
Tags: #story[1109]
2017-08-16 14:51:44 +12:00
Calum 3542c646f8 Marker class can now store and show multiple arrows sequentially
#implement #story[1118]
2017-08-16 14:51:05 +12:00
Michael Rausch 8fb5ea2223 Merge branch 'develop' into StartScreen
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/utilities/StreamParser.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/LobbyController.java
2017-08-16 14:31:14 +12:00
Kusal Ekanayake 958c1e216f Fixed sail toggling issues and test. 2017-08-16 14:30:37 +12:00
Kusal Ekanayake 100689a20b Merged develop onto zooming for easier merge later on.
#story[1121]
2017-08-16 13:15:15 +12:00
Kusal Ekanayake 2da887e677 Merge branch 'develop' into Story40_Zooming
# Conflicts:
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/test/java/steps/ToggleSailSteps.java
2017-08-16 13:13:39 +12:00
Alistair McIntyre bd213bcd9e Merge branch 'develop' into Story80_BoatCustomization 2017-08-16 13:06:31 +12:00
William Muir bf016356a6 Finish screen now displays correctly on finishing.
GameState update now checks for finishing the race
Can now go back to main menu from finish screen
Labeled all threads for better debugging
Still need to implement race list ordering and finish screen ordering
2017-08-16 13:04:34 +12:00
William Muir 76a750a764 Moved sendRaceStatus Message out of S2C Thread into MS Thread (minor refactor) 2017-08-16 11:53:29 +12:00
William Muir 000d562ffe SailIn / out animation on client is now correct again 2017-08-16 11:27:46 +12:00
Haoming Yin d02f2385dd Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/model/ClientYacht.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java
#	src/test/java/steps/ToggleSailSteps.java
2017-08-16 10:11:58 +12:00
Haoming Yin a5261494cd Merge remote-tracking branch 'origin/1124_broadcast_mark_rounding_message' into 1124_broadcast_mark_rounding_message 2017-08-16 10:06:25 +12:00
Calum ac47e9d88a Game state now updates based on boat position. Arrows drawn as boat travels course. Currently do not point in correct direction, also the sparkline does not work.
#bug #refactor #implement #story[1118]
2017-08-16 03:51:48 +12:00
Calum 7329f7dc65 Merge branch 'develop' into story1118_map_arrows 2017-08-16 01:35:15 +12:00
Calum 7c5f146b11 Merge to integrate develop with separated Yacht classes. Functionality from this branch is not yet completed.
#refactor
2017-08-16 01:23:38 +12:00
Calum e3fbbd4590 Fixed sails in and out test.
#bug #test
2017-08-16 01:19:34 +12:00
Calum dc8baa09a3 Re-implemented collision tests.
#test #bug
2017-08-16 01:17:40 +12:00
Calum 720ce0ae5b Merged with develop. Moved all collision logic into game state.
#refactor
2017-08-16 01:04:16 +12:00
Calum a7a667b4bc Merge branch 'develop' into 1124_switching_to_finish_screen
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/test/java/seng302/visualiser/ClientToServerTests/RegularPacketsTest.java
2017-08-15 23:45:50 +12:00
Calum 4e68cf31cf Fixed finish screen switch
tags: #fix
2017-08-15 23:30:27 +12:00
Zhi You Tan d03460d69e Implemented boat tracking when boat is selected by either clicking or selecting from sidebar combo box. Clicking tracked boat will cancel tracking, but using combobox will always result in one boat being selected.
#story[1121] #pair[wmu16, zyt10]
2017-08-15 23:16:25 +12:00
Peter Galloway 50baf6f85b implemented race finish functionality, finish screen not loading properly yet #story[1124] 2017-08-15 20:48:51 +12:00
William Muir 23a04facbe ServerYachts now send now have their own boat status.
This allows clients to know when this boat has finished

tags: #story[1124]
2017-08-15 20:24:51 +12:00
Kusal Ekanayake 7fbecc8b3d Fixed juttery movements when zooming and sometimes tracking.
Need to look into getting the boat propery fixed in the center.

#story[1121]
2017-08-15 19:14:16 +12:00
Alistair McIntyre 9cb5956f3c Updated lobby controller to pass the player ID through, and the lobby view to have a customize button.
tags: #story[1142]
2017-08-15 16:48:23 +12:00
Alistair McIntyre 366ebb3adb Merge branch 'Story66_Collision' into 'develop'
Collision branch merging to develop

# Change log
* Added yacht-mark collision and yacht will be pushed back upon collision.
* Added yacht-yacht collision and both yachts will be pushed back upon collision.
* Updated yacht map position initialisation. Yachts will all be spawned behind start line with a distance apart from each other.
* Added a collision visual alert when collision packet is received.
* Added two extra colours to support for 8 boats.

# Testing
* Junit tests for yacht-yacht collision.
* Manual testing for yacht map position initialisation
    * Yacht spawned apart from each other.
    * Yacht will spawn behind start line even if start line is different direction.

See merge request !59
2017-08-15 15:53:36 +12:00
Haoming Yin 458bd5408f Merge remote-tracking branch 'origin/1124_broadcast_mark_rounding_message' into 1124_broadcast_mark_rounding_message 2017-08-15 15:21:10 +12:00
Calum c00d165f47 Merge remote-tracking branch 'origin/1124_broadcast_mark_rounding_message' into 1124_broadcast_mark_rounding_message
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
2017-08-15 15:13:40 +12:00
Calum d2bb15471a Changed the velocity equation for boats to handle outlying scenarios such as 0 velocity.
#bug
2017-08-15 15:12:39 +12:00
Zhi You Tan c0cd260610 Fixed junit fail 2017-08-15 15:06:11 +12:00
Haoming Yin 6a9357f598 Merged Develop onto refactored yacht branch
tags: #story[1124] #pair[hyi25, wmu16]
2017-08-15 15:04:35 +12:00
Haoming Yin 6909f99773 Merge remote-tracking branch 'origin/develop' into 1124_broadcast_mark_rounding_message
# Conflicts:
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/visualiser/GameView.java
2017-08-15 14:58:13 +12:00
Zhi You Tan ce5424cc79 Fixed develop merge and now collision works 2017-08-15 14:53:15 +12:00
Haoming Yin c125708a4a Final commit for yacht refactor
tags: #story[1124] #pair[hyi25, wmu16]
2017-08-15 14:49:16 +12:00
Haoming Yin 2dc0ba07d9 WIP: Second commit for seperating server and client yacht classes
tags: #story[1124]
2017-08-15 14:30:39 +12:00
Zhi You Tan 2a3231d334 Merge remote-tracking branch 'origin/develop' into Story66_Collision
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/model/mark/MarkOrder.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-08-15 14:30:01 +12:00
Haoming Yin d6a436d2eb WIP: Initial commit for seperating server and client yacht classes
tags: #story[1124]
2017-08-15 14:18:48 +12:00
William Muir baacd8a9c0 Refactor. Taken Rounding logic out of yacht and into game state.
tags: #story[1124]
2017-08-14 23:52:06 +12:00
William Muir e1dddd317d WIP: Minor fixes 2017-08-14 17:57:41 +12:00
Peter Galloway b9ae9c4730 made server send appropriate racestatus flags in the race status packet #pair[mra106, ptg19] #story[1109] 2017-08-14 17:55:53 +12:00
Kusal Ekanayake fab5f9229f Got the boat's to track and center correctly.
As well as allowing selecting different boats to track them, doesn't work as intuitively as I would like but will need to sort out a boat selection feature first made specifically for the selection of only one boat.

 #story[1121]
2017-08-14 17:27:14 +12:00
Peter Galloway ff92262a78 fixed race clock countdown/count up #story[1109] 2017-08-14 16:32:50 +12:00
William Muir a4547e12cb Merged develop into this branch and resolved conflicts
tags: #story[1124] #pair[wmu16, hyi25]
2017-08-14 16:21:18 +12:00
William Muir 1a39b6e4a3 Merge branch 'develop' into 1124_broadcast_mark_rounding_message
# Conflicts:
#	src/main/java/seng302/gameServer/ServerToClientThread.java
2017-08-14 16:16:04 +12:00
William Muir 58446ffaed MarkRounding Message now sent out correctly.
Added submark seqID attribute to each mark of a compound mark from parsing xml
Added Rounding side attribute to each individual mark as read from the xml
RoundingSide enum now has a method to get Enum from String literal
Now store the closest mark to each yacht in each update for purpose of knowing which mark they round
Minor code tidying, Added logger to serverToClientThread, removed 'serverLog' method
removed obsolete code
2017-08-14 16:11:32 +12:00
Alistair McIntyre 1f09005147 Message types for Request and Response created, and Messages for them also created.
tags: #story[1142]
2017-08-14 15:30:42 +12:00
Alistair McIntyre 3754b71f4d Merged updated develop into branch.
tags: #story[1142]
2017-08-14 14:31:02 +12:00
Alistair McIntyre 1d2222b599 Merge branch 'develop' into Story80_BoatCustomization 2017-08-14 14:23:05 +12:00
Alistair McIntyre 89ceab0c4b Merge branch 'Story64_SailsAnimations' into 'develop'
Story64 sails animations

The sail animations for the boats. 

The sail should follow the boat when the boats heading nears downwind and upwind. The shift key should make the sail have a squiggly animation and flow into the wind. A cucumber test has also been created and could be looked into for more stories.

Unintentionally merged in parts of the zooming story. (Basic zooming in and out)

See merge request !56
2017-08-14 14:19:00 +12:00
Alistair McIntyre 76dabb8138 Merge remote-tracking branch 'origin/Story64_SailsAnimations' into Story64_SailsAnimations
# Conflicts:
#	src/test/java/steps/ToggleSailSteps.java
2017-08-14 14:17:10 +12:00
Alistair McIntyre 8b543488e3 Fixed faulty develop merge and completed manual testing before merging back into develop.
tags: #story[1111]
2017-08-14 14:15:34 +12:00
Alistair McIntyre c52c345e53 Merge branch 'develop' into Story64_SailsAnimations
# Conflicts:
#	src/main/java/seng302/visualiser/GameClient.java
2017-08-14 14:04:53 +12:00
Alistair McIntyre 9420717b44 Added Messages to MessageType, continued working on request.
tags: #story[1142]
2017-08-14 13:38:41 +12:00
Kusal Ekanayake 9c1fe72f6b Merge and tests fix 2017-08-14 13:35:18 +12:00
Kusal Ekanayake 2e892f35ea Merge branch 'develop' into Story64_SailsAnimations
# Conflicts:
#	src/main/java/seng302/visualiser/GameClient.java
2017-08-14 13:32:57 +12:00
Alistair McIntyre bedd742c93 Started on Request/Response packets for the Boat customization to begin the boat customization process.
tags: #story[1142]
2017-08-14 13:26:51 +12:00
Kusal Ekanayake add6856727 Merge remote-tracking branch 'origin/Story64_SailsAnimations' into Story64_SailsAnimations
# Conflicts:
#	src/main/java/seng302/model/Yacht.java
2017-08-14 13:22:56 +12:00
Kusal Ekanayake 4dc6b2af2b Merge fix 2017-08-14 13:20:15 +12:00
Kusal Ekanayake e65558b8ac Merge branch 'develop' into Story40_Zooming
# Conflicts:
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/visualiser/GameClient.java
2017-08-14 13:17:39 +12:00
William Muir e4cc5a0950 Fixing develop (sort of) 2017-08-14 12:52:58 +12:00
William Muir 4b4f8a25a3 Merge branch 'issue38_irregular_key_event_packets' into 'develop'
Issue38 irregular key event packets

A timed loop is now created on button press for sending out packets when a button is held down.
Removed the lists in LobbyController and replaced them with text objects to avoid the nested lists of single element lists.
Unit tests are in tests.java.seng302.visualiser.ClientToServerTets.RegularPacketsTest

**EDIT -** Tests fail due to some kind of error with reading from sockets in VM environment. Unable to fix at present.

See merge request !57
2017-08-14 12:49:52 +12:00
Zhi You Tan c77adf385e Terminating client thread before server thread to prevent alert box popping up 2017-08-14 11:21:33 +12:00
Zhi You Tan 9b7f4a93d8 Merge remote-tracking branch 'origin/issue38_irregular_key_event_packets' into issue38_irregular_key_event_packets 2017-08-14 11:02:19 +12:00
Zhi You Tan e780b47160 Fix javafx error on ci 2017-08-14 11:02:07 +12:00
Haoming Yin 028fc44dce Yacht now extends observable and can notify server to client thread to broadcast message.
#story[1124]
2017-08-14 10:48:11 +12:00
cir27 a185c9dc96 Implemented a factory class that creates mark arrows as needed. Needs to integrated with the real world data and tested to work. Works with all test data so far.
#implement #story[1118]
2017-08-14 03:44:46 +12:00
Calum 52e10997f1 Build issues caused by vm unable to open socket connections. Leaving as is for now.
#bug
2017-08-13 21:07:21 +12:00
Calum f2f750298c Added print statements for determining where javaFX is accessed from in the test. 2017-08-13 21:05:28 +12:00
Calum 1755b00079 Unncommented test to see if it breaks the build at remote repo. 2017-08-13 20:59:03 +12:00
Calum a844585faf Empty tests to check where bug is occuring 2017-08-13 20:54:13 +12:00
Calum b7fe79a5cc Attempted fix for build issues due to javaFX toolkit not being initialized. 2017-08-13 20:44:23 +12:00
Calum 2d5492601f Fixed build issues caused by changes to a yacht step turn constant.
#bug
2017-08-13 20:40:18 +12:00
Calum 0ee12021e2 Fixed bug that stopped clients from getting updated xml data.
#issue[46] #bug
2017-08-13 20:29:10 +12:00
Calum 6218d5506b Fixed bug that stopped clients from getting updated xml data.
#issue[48] #bug
2017-08-13 20:24:03 +12:00
Calum d79b0421c2 Fixed merged conflicts with merge onto develop.
#bug
2017-08-13 19:00:06 +12:00
Zhi You Tan 0b978593d4 Solved the fps counter zoom together with canvas problem. Workaround used was changing fps counter on game view to race view.
#story[1117] #pair[ptg19, zyt10]
2017-08-13 18:52:42 +12:00
Calum 8cb5b8caec Merge branch 'develop' into issue38_irregular_key_event_packets
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/ServerPacketParser.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/GameClient.java
2017-08-13 18:44:34 +12:00
Calum 2093e79b6a Rather than a high frequency loop sending all packets a low frequency loop is made then destroyed on button press for sending turn packets. This means a fast response time on button press but fewer packets sent.
#implement #issue[38]
2017-08-13 18:38:24 +12:00
Kusal Ekanayake 8ec6490627 Started trying to get the zoomed in gave view to follow the boat.
Can easily make the boat stay put at the origin. can make it perfectly center, also weary of the weird jittery effect that is present when tracking. Tracking is active when the zoom scale is greater than 1.

#story[1121]
2017-08-13 17:02:35 +12:00
Kusal Ekanayake 0a7a9018f3 Merge branch 'develop' into Story64_SailsAnimations
# Conflicts:
#	src/main/java/seng302/model/Yacht.java
2017-08-13 15:27:25 +12:00
Zhi You Tan 93cb0ca600 Updated yacht-yacht collision to push back both yacht.
Tweaked acceleration to increase time to top speed.

#story[1117] #pair[ptg19, zyt10]
2017-08-13 15:14:14 +12:00
Kusal Ekanayake 25c2de63a2 Working cucumber tests for sails toggle.
When sails in will send a sails out message when sails out will send a sails in message and then checks for the new status of the sail

#story[1111]
2017-08-13 14:55:33 +12:00
Kusal Ekanayake 2411a3cc2c Merge branch 'develop' into Story64_SailsAnimations
# Conflicts:
#	src/main/java/seng302/model/Yacht.java
2017-08-13 14:34:42 +12:00
Zhi You Tan fda233f5ad Merge branch 'Story71_TackAndGybeSmoothly' into 'develop'
Story 71 Tack/Gybe, Story 65 VMG Autopilot

# Implementation
- Added autopilot functionality to move boat towards a given heading with a single function call.
- Added functionality to move boat from one side of the wind to the other (tack/gybe) with a single button press.
- Added functionality to move boat to correct VMG from polars with single button press.
- Pressing a button a second time will disable the autopilot, as will pressing the Upwind/Downwind keys.

# Testing
- Fairly simple JUnit testing for a set of beginning headings and expected ends for the autopilot
- Unsure how cucumber testing would actually be better than simple junit testing in this case.

See merge request !55
2017-08-13 14:22:28 +12:00
Zhi You Tan c58cb1a476 WIP: Researched and implemented a simple right of way calculation (might be wrong).
#story[1117]
2017-08-11 23:57:27 +12:00
Michael Rausch d2fd9ebaea Started work on start screen
- Server now sends out race start status messages during lobby & pre-start stages
- Added timer in lobby

Tags: #story[1109]
2017-08-11 19:03:57 +12:00
Zhi You Tan fda6625256 Merge remote-tracking branch 'origin/develop' into Story66_Collision
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/model/mark/MarkOrder.java
#	src/main/java/seng302/visualiser/GameClient.java
2017-08-10 20:23:56 +12:00
alistairjmcintyre 6ddaaa0dfa Removed extra print statement from test. 2017-08-10 20:18:36 +12:00
William Muir 55c22fa7e2 Merge branch 'MessageExtensions' into 'develop'
Message extensions

## Changes
* Implemented new Client<->Server handshake protocol

## Testing
* Manually tested as tests cannot be simulated in code. The following cases were tested
    * Client connects normally with empty lobby
    * Client connects normally with one other player in lobby
    * Client responds to lobby full error
    * Client responds to general error 

See merge request !54
2017-08-10 20:17:50 +12:00
Michael Rausch a7b8b0dbc3 Removed redundant input & output streams 2017-08-10 20:15:08 +12:00
Zhi You Tan 7e1686a980 Packets are sent out when collision happens and receiver is able to interpret and display as visual alert. Updated visual alert to looks better.
- Created yacht event code message to be sent out as packet.
- Added observers to main server thread on yacht so when collision detected, main server thread will send out yacht event message to all server to client threads.
- Updated collision visual alert using circle and animation timer.

#story[1117]
2017-08-10 19:50:30 +12:00
Alistair McIntyre 32b231e78a Added testing for the vmg autopilot
tags: #story[1107]
2017-08-10 19:19:41 +12:00
Michael Rausch 3ad37faedc Merge branch 'develop' into MessageExtensions 2017-08-10 19:01:46 +12:00
Michael Rausch 09c4f98056 Implemented new client - server handshake protocol
- Implemented new packet types
- Changed server & client logic to use new protocol

Tags: #story[1124] (Issue 39)
2017-08-10 19:01:30 +12:00
Alistair McIntyre 1c2870649a Added testing for the tack/gybe settings.
tags: #story[1105]
2017-08-10 18:58:38 +12:00
Alistair McIntyre a2ee4411be Merge branch 'develop' into Story71_TackAndGybeSmoothly 2017-08-10 17:59:19 +12:00
Alistair McIntyre a23352ef85 Merge branch 'develop' into Story71_TackAndGybeSmoothly 2017-08-10 17:59:10 +12:00
Alistair McIntyre f9d5bd10b1 Merge branch 'develop' into Story71_TackAndGybeSmoothly 2017-08-10 17:58:19 +12:00
William Muir 0b8ad137b3 Minor fixes for merge
#story[1124] #pair[wmu16, hyi25]
2017-08-10 17:47:24 +12:00
Alistair McIntyre a746191dba VMG works correctly, auto pilot is interupted by a repeated keypress or an upwind/downwind press.
tags: #story[1105]
2017-08-10 17:46:28 +12:00
Michael Rausch 1772d1c05e Merge branch '1124_Mark_Rounding_Implementation' into 'develop'
1124 mark rounding implementation

# ChangeLog 

* Implemented Mark Rounding Algorithm so the server acknowledges when boats pass around and through marks / gates 
* Compound Mark class changed so that it has one constructor which takes a list of Mark objects
* GeoUtility has had many methods added to it for purposes of deducing mark rounding

# Testing 

* JUnit tests done for GeoUtility Class
* JUnit tests done for CompoundMark Class
* Test class removed for Yacht Class as no longer testable
* Manual test-log entry made for mark rounding in game

See merge request !53
2017-08-10 17:20:33 +12:00
William Muir 1d7b527130 Tidied code. Added tests
#story[1124] #pair[wmu16, hyi25]
2017-08-10 16:45:30 +12:00
Alistair McIntyre 430779c943 Boat auto pilots correctly for tacking/gybing. Needs proper testing.
#story[1105]
2017-08-10 14:53:24 +12:00
William Muir 9c79897e01 Tidied code, added MidPoint to CompoundMark class
Compound Mark class is now constructed with a list of marks.
A mid point is created on its construction for use in Geo Calculations

#story[1124] #pair[wmu16, hyi25]
2017-08-10 13:58:32 +12:00
Michael Rausch 07386ed2db Improved boat bounce-back calculation
- Changed boat bounce back send the boat n meters in the opposite direction.
- Improved test to use the minimum of yacht and mark collision distances

Tags: #story[1117]
2017-08-10 13:01:31 +12:00
William Muir abb15f6edf Fixed Mark rounding Algorithm
Algorithm now knows when a player has to round a gate or just pass right through

#story[1124] #pair[wmu16, hyi25]
2017-08-10 12:08:03 +12:00
William Muir 87f2f1fe63 Fixed Mark rounding Algorithm
Algorithm now knows when a player has to round a gate or just pass right through

#story[1124] #pair[wmu16, hyi25]
2017-08-10 12:07:47 +12:00
William Muir 249ad9e5c0 Fixed Mark rounding Algorithm
Algorithm now knows when a player has to round a gate or just pass right through

#story[1124] #pair[wmu16, hyi25]
2017-08-10 12:02:19 +12:00
alistairjmcintyre 9d02d2fbea Implemented a fairly simple auto pilot setting for the yacht, on update if the boat is set to autopilot it will adjust the heading towards the desired heading. Needs some refinement.
#story[1105]
2017-08-10 02:04:51 +12:00
Michael Rausch b1598ccb0f Changed testUpdateYachtWithCollision to use MARK_COLLISION_DISTANCE
Changed testUpdateYachtWithCollision to use MARK_COLLISION_DISTANCE constant.

#story[1117]
2017-08-09 22:36:34 +12:00
Michael Rausch 08304f9c3e Fixed failing test 2017-08-09 22:05:49 +12:00
Michael Rausch 4cc48a355e Added mark collisions
- Boats now collide with marks
- Added method to MarkOrder to get all marks
- Reduced the frequency at which collisions are detected. This fixed some performance issues
- Added method to bounce the boat off a mark

Tags: #story[1117]
2017-08-09 21:57:50 +12:00
Calum 2c5fddb695 Implemented zooming and clipping of race border. Implementation is still hackish.
#pair[ptg19, cir27] #story[1121]
2017-08-09 16:56:46 +12:00
Calum 126d8ea870 Added factory class for producing mark arrows.
#story[1118]
2017-08-09 15:24:32 +12:00
Calum 30a6cb98ec Action packets now sent at regular 20ms intervals
#issue[38] #implement
2017-08-09 14:03:21 +12:00
Zhi You Tan 8813d06010 Created a simple red blink on a top of a yacht given source id.
Created and updated methods reading yacht event packet to translate to collision alert on visualiser.
WIP: sending yacht event packet to inform collision

#story[1117]
2017-08-09 01:26:59 +12:00
Kusal Ekanayake 0fbca89030 Merge branch 'develop' into Story64_SailsAnimations
# Conflicts:
#	src/main/java/seng302/model/Yacht.java
2017-08-08 19:45:08 +12:00
Kusal Ekanayake 421ef3c65a Started progress on zooming, can now use z and x keys to zoom into map.
Nothing scales correctly asides from the map itself (the boats stay in the same position).

#story[1121]
2017-08-08 19:41:51 +12:00
Zhi You Tan 5937f8b640 Merge remote-tracking branch 'origin/develop' into Story66_Collision
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/model/Yacht.java
2017-08-08 17:04:34 +12:00
Zhi You Tan 5ec67d0b80 Added junit for update yacht (after collision implementation). Removed another version of initialise boat positions.
#story[1117]
2017-08-08 16:51:29 +12:00
Kusal Ekanayake 941febaf62 Tried to fix cucumber tests, getting closer.
#story[1111]
2017-08-08 16:31:27 +12:00
William Muir a545e9dbc3 Removing '>' characters from docstrings to fix build
Note: This is probably a XML style guid thing and is stupid. Can probably fix this
2017-08-08 16:14:13 +12:00
William Muir b0e7dddaf3 Fixed gate passing algorithm
boats now must pass through the correct way. This works for start in-race and finish gates
Refactored yacht algorithm code for better readability
Logging function added or seeing mark roundings occur

tags: #story[1124] #pair[hyi25, wmu16]
2017-08-08 15:58:13 +12:00
Haoming Yin ed0a783374 Fixed the bug that boats could round over a gate but still "across" it. Added unit test to ensure the algorithm works.
tags: #story[1124]
2017-08-08 10:42:36 +12:00
Kusal Ekanayake 97696cc95b Started work on cucumber tests. Trying to sort through threads, getting inconsistent results.
#story[1111] #pair[kre39,ptg19]
2017-08-07 17:54:34 +12:00
William Muir 4375b73257 Implemented algorithm for checking if boat passes through a mark.
Mark rounding works for whole course (WITH BUGS)
Still some gate logic to work out.
Moved gate function to GeoUtil class

tags: #story[1124] #pair[hyi25, wmu16]
2017-08-07 17:28:12 +12:00
Kusal Ekanayake f97b18d594 Sailsin graphics moving and working as expected.
#story[1111] #pair[kre39,ptg19]
2017-08-07 16:48:30 +12:00
Kusal Ekanayake c7857872ce Luffing sails animation working correctly, working on sailsin animation now.
#story[1111] #pair[kre39,ptg19]
2017-08-07 15:24:01 +12:00
Zhi You Tan 79105a1bdc Created a simple collision detection by iterating each boats per update. Working but sequential checks can be costly.
#story[1117]
2017-08-07 12:01:26 +12:00
Zhi You Tan a4b22190c0 Changed the spawn point to behind start line and calculated quadrant to make sure yachts spawn behind start line in different map scenario.
#story[1117]
2017-08-07 11:50:07 +12:00
Calum a3ce5998ff Action packets now sent at regular 20ms intervals
#issue[38] #implement
2017-08-07 10:58:07 +12:00
William Muir 7f0329dda6 WIP: Implemented basic mark rounding algorithm.
Removed RacePosition class. Instead marks are just grabbed from the mark order class when necessary.
No marks are stored as an attribute in the yacht class but the 'currentMarkSeqID' which is used to get current, and surrounding marks.
Works for all marks in between but not including starting and finishing gate as no angle can be made with them. Still to work out how to implement this

 #story[1124]
2017-08-07 00:23:54 +12:00
Calum 8a40119a98 Action packets now sent at regular 20ms intervals
#issue[38] #implement
2017-08-06 22:17:08 +12:00
Zhi You Tan a470cb66a2 Updated initialise boat function so it can now initialise boats with distance apart in meters.
Created a second prototype function which is more testable compared to the initial design. New function takes in parameters (starting marks, yacht starting position, yacht) and initialise yacht correctly with position.

#story[1117]
2017-08-06 21:16:14 +12:00
Kusal Ekanayake ecf2c52cfa Added tests, and sails to all clients.
#story[1111]
2017-08-06 15:43:22 +12:00
Haoming Yin 43788bd153 Added a method to test if a geo point is located in a triangle which is formed by other three geo points.
The method helps to check the mark rounding.

Also unit tests have been done for this method.

tags: #story[1124]
2017-08-06 12:36:57 +12:00
Zhi You Tan 81c2a8e0fd WIP: Added test initialise boat position test. Corrected ColorsTest after addition of two new colours. 2017-08-05 23:59:58 +12:00
William Muir e90a0ce435 Merge branch '1124_Mark_Sequence_From_RaceXML' into 'develop'
Loading mark sequence from RaceXML

# Loading mark sequence from RaceXML

## Change Log
1. Added MarkOrder class
* Mark order is read from the generated RaceXML and stored
* Added .getNextMark() to get the next mark in the race
* Added .equals() and .hashCode() for Marks
* NEW: Added RacePosition class to hold players position in the race
* NEW: Fixed issue where the duplicates weren't stored in the mark order

## Testing
* Unit tests in models/MarkOrderTest.java

## Acceptance Criteria
* Use the mark sequence in the raceXML
    * Met by change log item (1)

* Store relevant mark details with each participating boat (Last mark, next mark)
    * Method in MarkOrder to get next mark, however the last mark and next mark will need to be stored by whoever implements the second task.

See merge request !52
2017-08-05 15:18:26 +12:00
Zhi You Tan a727014fcb Implemented boats spawning in parallel at the start line with spacing.
Added two more colours to support up to eight boats.

#story[1117]
2017-08-05 00:31:36 +12:00
Kusal Ekanayake ae28ccf228 Made sails luff in the right direction.
#story[1111]
2017-08-04 16:24:34 +12:00
Michael Rausch 281ce2d842 Loading course mark order from RaceXML
- Re-engineered code to work with the new marks
- Fixed bug where race order wasn't correct (added RacePosition class to fix)
- Rewrote tests to work with new RacePosition class

Tags: #story[1124] (Task 1)
2017-08-04 13:20:50 +12:00
Kusal Ekanayake f8af9cc259 Works for clients and server.
Due to the information being sent and received, it only currently works on client side boats.

#story[1111]
2017-08-03 19:07:30 +12:00
Zhi You Tan 8af80e6c3a WIP: Connected game client to main server thread to pass compound mark variable.
Boats are initialised in main server thread behind start line before game starts.

#story[1117]
2017-08-03 18:39:15 +12:00
William Muir 874cdec654 Added booleans: has entered rounding zone, has crossed first line, has crossed second line
All for purposes of checking mark rounding.

Currently not yet finished

tags: #story[1124] #pair[hyi25, wmu16]
2017-08-03 17:39:07 +12:00
Kusal Ekanayake 99d5545ed3 Made the sails work properly by toggling.
Need to remove the unneeded code I added.

#story[1111]
2017-08-03 16:33:51 +12:00
William Muir 423f1acdb6 Merge remote-tracking branch 'origin/develop' into develop 2017-08-03 16:29:22 +12:00
William Muir 454e9ac9f1 Added an attribute to each yacht: 'DistanceToNextMark'
This attribute is calculated at each update of the boat as prompted by the game state regularly
Removed the lat and lng attribute from the Yacht class and replaced its usage with the GeoPoint object instead

Removed redundant test files and merged GeoUtility and testGeoUtil test classes into one

tags: #story[1124] #pair[hyi25, wmu16]
2017-08-03 16:29:12 +12:00
Kusal Ekanayake a8e70b3631 Merge branch 'develop' into Story64_SailsAnimations
# Conflicts:
#	src/main/java/seng302/controllers/LobbyController.java
#	src/main/java/seng302/fxObjects/BoatGroup.java
#	src/main/java/seng302/model/Yacht.java
2017-08-03 15:19:13 +12:00
Kusal Ekanayake eb83e9dcc5 Working idle sail animation.
Need to work on getting sails to toggle properly. Have the 2 animations almost working but unable to switch between the two.

#story[1111]
2017-08-03 14:50:56 +12:00
Zhi You Tan 1ab849fd0d Added cucumber dependency. 2017-08-03 14:02:52 +12:00
William Muir db078538ff Minor cleaning in yacht class
tags: #story[1124]
2017-08-03 13:53:30 +12:00
Calum 1c0d869894 Corrected a value in the race.xml 2017-08-03 13:49:53 +12:00
Calum f9e6df46c1 Fixed issues caused by merge.
#bug
2017-08-03 13:23:43 +12:00
Calum 5228c078bc Merge branch 'develop' into 1124_Mark_Sequence_From_RaceXML
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/server/simulator/Simulator.java
#	src/main/java/seng302/models/mark/Mark.java
#	src/main/java/seng302/visualiser/map/CanvasMap.java
2017-08-03 12:27:11 +12:00
William Muir f5f73ede6b Merge branch 'story61_player_perspective' into 'develop'
Big boy merge request. Issue 34. Issue 35.

# This merge request is to fix **Issue 34** and **Issue 35**
*This is will require some further work but is being added to develop as is*

# Changelog

## Mark classes from server now used in client also.
The mark setup client side was poor because all marks were of type AbstractMark but they all had different methods so you had to identify what kind of mark they were anyway. The server side implementation
used the same calls for all Mark types and had the bonus of a GeoPoint class with utilities for distance and calculations.

## Yacht Class now contains observable values
The yacht attributes used by the model are now observable.

## StreamParser now static utils class.
Data no longer needs to be stored in the staticly available thread. Can now be processed in a more direct fashion by classes calling the parsing utils when needed.

## XMLParser now static utils class.
XMLParser now converts XML formatted doc objects and returns the containing data, this removes the need for the class to store multiples kinds of XML data and can instead just return it for use elsewhere.

## Data storage classes added to java/seng302/model/stream/parser
Rather than the StreamParser updating the Model directly it just processes the data into basic data types and shoves it all into objects for processing elsewhere. This avoids the static StreamParser class needing to know about Model objects.

## All static ultilities moved to their own package to make them easier to locate. Any child classes moved to their own files and added to packages in the model package.

## All visualiser code moved to the a new visualiser package

## Grouped all high level logic for the app and data management.
Previously all the high level logic (e.g. when to start a race, what fxml to show, how to process data from the stream) was in a number of classes. Mainly StreamParser, Controller, StartScreenController, RaceViewController, BoatGroup and LobbyController. All of this has been grouped into GameClient.
* This reduces the need to share data between these classes. Previously all the controllers needed references to one another to work so they were essentially the same class anyways.
* This makes it easier to find specific logic.
* Everything is now accessabile from GameClient, or from something GameClient knows about, making it easier to pass information if needed.

## Logic removed from LobbyController. Now only displays information

## Annotation box now a generic case for a rectange containg any number or type of annotation.
This means that if any new annotation needs to be added you don't have to hard code a specific case for it. Just initialize the annotation in the box at anytime.

## GameClient now observes the state of Yacht and Marker classes for position changes and updates them accordingly.
This avoids having to pass data to the GameView and having to poll for changes.

## CanvasController renamed GameView, now only concerned with displaying the race.
Moved all unnecessary logic to GameClient. Also fixed some issues where it polled RaceViewController for data instead of being updated by RaceViewController.

## MarkerObjects now a simple circle bound to the location of a given Mark. To display a gate lines are bound between the circles bound to Marks if a CompoundMark has more than one Mark.
Made all the logic here much more straight forward.

## Replaced most public static data classes with listeners.
Removed a bunch of polling. Made sharing data simplier and more readable.

# Known Issues & Limitaitons

* Pretty much everything that wasn't working at the end of sprint 5.
* Because listeners are triggering stuff on the JavaFX thread you have to use `Platform.runLater(() -> {//Do stuff});` whenever you want to access FX stuff from other threads. You can't just be lazy and put everything in it because then the JavaFX thread goes really slow. This is actually good practice anyways since you want to process data off of them FX thread (so not anything that's not triggered by a controller or an event) to keep JavaFX responsive.
* There is a 100% chance stuff has broken with this refactor that I'm not aware of. Some of it I am aware of.

# Testing

Good joke. I did manual testing though.

# Acceptance criteria

It works more or less.

See merge request !50
2017-08-03 12:11:20 +12:00
William Muir 1160f274ee Reformatted code in appropriate style
Build fails server side only due to some dependency issue. Internet problem server side?? (M I C H A E L?)

tags: #issue[34]
2017-08-03 12:06:07 +12:00
William Muir 53f5d63f15 Fixed build. (Actually this time) ((NOW WERE READY TO MERGE)))
All doc string annotations were required to be fixed for all methods

tags: #issue[34]
2017-08-03 11:50:07 +12:00
William Muir 1150ec3e43 Merge branch 'develop' into story61_player_perspective
# Conflicts:
#	src/main/java/seng302/App.java
2017-08-03 11:48:54 +12:00
William Muir c655cb3fab Fixed build. (Actually this time)
All doc string annotations were required to be fixed for all methods

tags: #issue[34]
2017-08-03 11:45:14 +12:00
William Muir 8e24c204fd Fixed build.
Google map does not work

tags: #issue[34]
2017-08-03 11:26:44 +12:00
Michael Rausch 7885b3fae2 Loading course mark order from RaceXML
- Mark order is read from the generated RaceXML and stored
- Added .getNextMark() to get the next mark in the race
- Added .equals() and .hashCode() for Marks

Tags: #story[1124] (Task 1)
2017-08-02 22:03:10 +12:00
Michael Rausch b01d39f19f Merge remote-tracking branch 'origin/develop' into develop 2017-08-02 20:42:22 +12:00
Michael Rausch bbf494e9a1 Merge branch 'master' into 'develop'
Merge Master into develop



See merge request !51
2017-08-02 20:42:07 +12:00
Michael Rausch eae201cb4b Merge remote-tracking branch 'origin/develop' into develop 2017-08-02 20:32:43 +12:00
Calum 87ef37a689 Fixed connecting to hosts. Fixed issue34 and 35 to the point where they can be developed off of.
#refactor #bug #issue[34, 35]
2017-08-02 00:26:57 +12:00
Alistair McIntyre b2c7b65191 Merge branch 'Logging' into 'master'
Added dependencies for slf4j



See merge request !49
2017-08-01 15:20:41 +12:00
Calum 908c0749cf Boats now move on screen as intended.
TODO - Make the client connect to the server.
2017-08-01 02:37:55 +12:00
Calum 47c5e6f155 Reverting some new graphics classes back to how they were on master. 2017-07-31 23:35:28 +12:00
Michael Rausch 9deba732b0 Added dependencies for slf4j 2017-07-31 18:34:55 +12:00
Calum b82d0d0137 Boats and map are now updated using the observer pattern.
#implement
2017-07-31 05:23:41 +12:00
Calum f1ad03e913 Refactored the setup for MarkObjects (now renamed Markers) and made the CompoundMark + Mark + GeoPoint classes the standard across all classes instead of GateMark + SingleMark + Mark.
#refactor
2017-07-31 02:19:19 +12:00
Calum 6cae338c1e Began fixing bugs with caused by asynchronous listener calls.
#bug
2017-07-30 20:12:19 +12:00
Calum 7894e31926 Merge branch 'develop' into story61_player_perspective
# Conflicts:
#	src/main/java/seng302/App.java
#	src/main/java/seng302/client/ClientPacketParser.java
#	src/main/java/seng302/client/ClientState.java
#	src/main/java/seng302/client/ClientStateQueryingRunnable.java
#	src/main/java/seng302/controllers/Controller.java
#	src/main/java/seng302/controllers/LobbyController.java
#	src/main/java/seng302/controllers/RaceViewController.java
#	src/main/java/seng302/controllers/StartScreenController.java
#	src/main/java/seng302/fxObjects/BoatAnnotations.java
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/model/stream/StreamReceiver.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/fxObjects/BoatObject.java
#	src/test/java/seng302/model/stream/StreamReceiverTest.java
2017-07-30 18:07:28 +12:00
Michael Rausch 25d8c8f9c4 Minor bug fixes.
Server will now only save incoming connections if in lobbying mode as it should
Commented out boat status printing

tags: #story[1047]
2017-07-27 14:15:55 +12:00
Zhi You Tan 1d9dd76356 For client's lobby view, it now can shows the connected host IP
#story[1055]
2017-07-27 13:12:53 +12:00
Zhi You Tan c2c34705d5 removed an unnecessary print statement and caught an exception 2017-07-27 13:01:04 +12:00
Zhi You Tan 96ed5e445e Replaced print stack trace with print statements 2017-07-27 12:47:18 +12:00
Kusal Ekanayake 870dc07fd2 Slight improvements to hosting.
Allow a host/client to disconnect and reconnect/make lobby, leave lobby and play the game.

#pair[kre39,hyi25] #story[1047]
2017-07-27 12:45:22 +12:00
Michael Rausch ecbb3f6658 Merge remote-tracking branch 'origin/develop' into develop 2017-07-27 11:06:00 +12:00
Haoming Yin 34704bd93d Merge remote-tracking branch 'origin/develop' into develop 2017-07-26 23:32:32 +12:00
Haoming Yin 201c88a253 Fixed a bug that program crashes when it receive regatta xml during the race, as it doesn't know how to handle the xml.
#story[984]
2017-07-26 23:32:16 +12:00
Peter Galloway 6c4da58d9d Merge remote-tracking branch 'origin/develop' into develop 2017-07-26 22:42:48 +12:00
Peter Galloway b56fa5cba3 refactored to make boat trails work again #fix #refactor 2017-07-26 22:42:37 +12:00
Peter Galloway 9cedbeb6f6 Fixed latency issues caused by clientside movement packets queueing up but currently the trails aren't working anymore #fix #refactor 2017-07-26 22:02:46 +12:00
Michael Rausch 4c6d107102 Merge remote-tracking branch 'origin/develop' into develop 2017-07-26 20:28:21 +12:00
Michael Rausch 7917a2584b Fixed alignment for wind direction 2017-07-26 20:28:13 +12:00
Alistair McIntyre f99f8a0d7c Merge remote-tracking branch 'origin/develop' into develop 2017-07-26 20:13:09 +12:00
Alistair McIntyre 7db716f51c Boat should move towards optimal angle upwind and downwind when pressing spacebar (VMG)
#story[988]
2017-07-26 20:12:57 +12:00
Haoming Yin 592e5a088f Merge remote-tracking branch 'origin/develop' into develop 2017-07-26 19:58:45 +12:00
Haoming Yin 2d6850950c Merge branch 'develop' into Documenting_client_and_server
# Conflicts:
#	src/main/java/seng302/client/ClientToServerThread.java
2017-07-26 19:57:43 +12:00
Haoming Yin ef6821a0cd Updated and added more documentations
#story[1047]
2017-07-26 19:55:35 +12:00
Michael Rausch 6e9535d78f Fixed race timer & Added boats to team position list
- Race status messages are sent at regular intervals instead of once at race start
- Boat positions are initialised on the Team Position list
- Timer counts up from when host clicks ready

Tags: #story[377]
2017-07-26 19:35:59 +12:00
Alistair McIntyre 72a45f5984 Fixed a bug where if boatMaxSpeed was 0 and sails were up, boat would not decelerate.
#story[986]
2017-07-26 17:11:34 +12:00
Alistair McIntyre de600fa062 Merge remote-tracking branch 'origin/develop' into develop 2017-07-26 17:10:29 +12:00
Haoming Yin 87e3b4f246 Merge branch 'story61_player_highlighting' into 'develop'
Story61 player highlighting

Added some highlighting for the players boat and a random name generator to help distinguish clients. The highlighting implementation is pretty hackish since they will be replaced by the visualiser overhaul anyways. To avoid refactoring a lot of code I just made some unused javaFX elements invisible rather than removing them, I can do it properly if requested.

See merge request !48
2017-07-26 16:31:53 +12:00
Alistair McIntyre 7b47d72ef0 Merge branch 'develop' of /home/cosc/student/ajm412/Documents/SENG302/team-13 with conflicts. 2017-07-26 16:22:01 +12:00
Calum 7392bdb80d Added documentation
#document
2017-07-26 16:03:11 +12:00
Zhi You Tan af9f1417f1 Documented client packet parser, client state, client state querying runnable, client to server thread and replaced e.printStackTrace() with client log messages. 2017-07-26 16:01:41 +12:00
Calum 8fc00fd750 Enabled boat path for only the player.
#story[987]
2017-07-26 16:01:01 +12:00
Calum 4e5b67abfa Merge branch 'develop' into story61_player_highlighting 2017-07-26 15:52:29 +12:00
Calum 84e8ac89fc Added random name generator until players can chose how to identify themselves. 2017-07-26 15:52:02 +12:00
Calum 12d081a1af Added highlighting for the player and moved all their assets to the foreground
#story[987]
2017-07-26 15:49:00 +12:00
William Muir 5e6b402bf5 Minor structural changes. GameState now has a thread which updates itself so its update
rate can be independent of sending packets to the client in the MainServerThread

#story[986] #pair[wmu16, ptg19]
2017-07-26 14:48:32 +12:00
Alistair McIntyre 2bfa6cb038 Adjusted the velocity calculations to allow for Acceleration/Deceleration of the boats, rather than just coming to a complete halt when the sails are pulled in.
#story[986]
2017-07-26 14:01:51 +12:00
Calum 8ac44d13df Began fixing conflicts with LobbyController
#bug
2017-07-26 12:05:03 +12:00
William Muir d99055901f Removed Music 2017-07-26 11:38:29 +12:00
Calum 9c9f6e4e80 Merge branch 'develop' into story61_player_perspective
# Conflicts:
#	src/main/java/seng302/fxObjects/BoatAnnotations.java
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/visualiser/controllers/LobbyController.java
2017-07-26 02:56:46 +12:00
Calum 08e369f1ae Merged with develop. Fixed many bugs in Visualiser.
#bugs
2017-07-26 02:49:31 +12:00
Michael Rausch b0e99ab444 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/server/ServerThread.java
2017-07-25 23:10:41 +12:00
Haoming Yin c77a48f589 Merge remote-tracking branch 'origin/develop' into develop 2017-07-25 23:06:06 +12:00
Haoming Yin 0135426dfe Changed lobby player profile to a lower risk pictures
#story[1055]
2017-07-25 23:05:52 +12:00
William Muir 37c745c139 Polar velocities should now work as intended.
Snapping to VMG still needs to be implemented.
Still an issue of not being able to pass the total upwind or downwind point

tags: #story[986]
2017-07-25 22:27:26 +12:00
William Muir 7880039801 Merge remote-tracking branch 'origin/develop' into develop 2017-07-25 22:19:19 +12:00
William Muir a56dac1e87 Polar velocities should now work as intended.
Snapping to VMG still needs to be implemented.
Still an issue of not being able to pass the total upwind or downwind point

tags: #story[986]
2017-07-25 22:19:03 +12:00
Haoming Yin 4ae422b47b When a player connects to the server, lobby will now show their user id and profile instead of showing all the profile gif at the beginning,
#story[1055] #pair[hyi25, zyt10]
2017-07-25 21:50:23 +12:00
Calum acd54dec7a Merge branch 'develop' into story61_player_perspective
# Conflicts:
#	src/main/java/seng302/App.java
#	src/main/java/seng302/client/ClientPacketParser.java
#	src/main/java/seng302/controllers/Controller.java
#	src/main/java/seng302/controllers/RaceViewController.java
#	src/main/java/seng302/fxObjects/BoatAnnotations.java
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/Boat.java
#	src/main/java/seng302/models/stream/XMLParser.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java
#	src/main/java/seng302/visualiser/controllers/StartScreenController.java
#	src/main/java/seng302/visualiser/fxObjects/BoatObject.java
#	src/main/resources/views/LobbyView.fxml
#	src/main/resources/views/MainView.fxml
2017-07-25 21:05:15 +12:00
Calum 6242ab0b2e Implemented observer and strategy pattern in BoatAnnotations, now renamed AnnotationsBox.
Also implemented various other small fixes and further refactored code.

#refactor
2017-07-25 20:45:27 +12:00
Michael Rausch c8a96dcce9 Fixed XML Loading error, used VMG to calculate boat velocity
- XML read from stream instead of file
- Started implementing VMG to calculate boat velocity dynamically

Tags: #pair[wmu16, mra106] #story[986]
2017-07-25 20:14:50 +12:00
Kusal Ekanayake 4f2dca7ecf Added proper the starting locations for marks and boats. 2017-07-25 18:48:33 +12:00
Zhi You Tan e569574c01 Merge remote-tracking branch 'origin/develop' into develop 2017-07-25 17:17:45 +12:00
Zhi You Tan f544734b4d Fixed sending wrong race xml when a player disconnected because xml is getting data from gamestate yacht but the yachts are not updated is player disconnect.
Heartbeat packet was sent out at wrong rate which cause the player disconnect detection to be slow. Heartbeat packet is send out every 200ms now.

#story[1055] #pair[hyi25, zyt10]
2017-07-25 17:17:36 +12:00
Kusal Ekanayake 80b439470b Merge remote-tracking branch 'origin/develop' into develop 2017-07-25 15:22:56 +12:00
Kusal Ekanayake 539197cef5 Added a visual indicator of wind speed during race (text box)
#pair[kre39,mra106] #story[1040]
2017-07-25 15:22:46 +12:00
Zhi You Tan 1a867be387 Added keystroke frequency limit
Updated client and server log format

#story[988] #pair[hyi25, zyt10]
2017-07-25 15:13:48 +12:00
Kusal Ekanayake 3785cd705f Fixed wind speed and direction being sent correctly.
#pair[kre39,mra106] #story[1036]
2017-07-25 15:08:10 +12:00
Kusal Ekanayake 5d7a438080 Changed default ip back to non local host. 2017-07-25 14:28:21 +12:00
Kusal Ekanayake 2f12f3e34f Fixed bug to let multiple people play at the same time. 2017-07-25 14:27:52 +12:00
Zhi You Tan 52bfa3ad34 Merge remote-tracking branch 'origin/Story1055_Send_Race_Status_When_Host_Ready' into develop
# Conflicts:
#	src/main/java/seng302/controllers/LobbyController.java
2017-07-25 00:03:58 +12:00
Zhi You Tan d1d659b698 Lobby view will switch to race view when received race status packet with race start type.
Ready button can only be pressed by host. Once pressed, it will send out race status packet with race start to all clients.

#story[1055]
2017-07-25 00:01:59 +12:00
William Muir cdb9337aed Deleted GameServerThread after being re merged in
#chore
2017-07-24 23:20:47 +12:00
Zhi You Tan 8b0af5bb62 Updated observer so it sends out updated boats.xml when client disconnects
#story[1047] #pair[wmu16, zyt10]
2017-07-24 21:35:31 +12:00
Zhi You Tan 83232a935e Merge remote-tracking branch 'origin/Story984_Send_XML_After_Clients_Connect' into develop
# Conflicts:
#	src/main/java/seng302/gameServer/ServerToClientThread.java
2017-07-24 21:30:12 +12:00
William Muir a30a1aa7c7 Tweaking to server loop making it send packets at 5Hz
Commented out some smoothing code in BoatGroup that was dependend on FPS screwing with movement
2017-07-24 21:14:17 +12:00
William Muir 07cebb6c5b Updated velocity in yacht constructor so the boat can be seen properly working for test purposes 2017-07-24 16:47:17 +12:00
Kusal Ekanayake 45bf65a3d3 Made clients receive new xml after new clients connect.
#pair[kre39,zyt10] #story[984]
2017-07-24 16:15:19 +12:00
Kusal Ekanayake 60f5a99b0c Merge branch 'Merging_GameLoop_with_Broadcast' into develop
# Conflicts:
#	src/main/java/seng302/controllers/StartScreenController.java
2017-07-24 15:32:52 +12:00
Kusal Ekanayake 526c12127f Merging game lobby with game state broadcast. Merge conflicts resolved.
Port numbers updated to 4942.
2017-07-24 15:26:51 +12:00
Kusal Ekanayake 1daac842f2 Merging game lobby with game state broadcast 2017-07-24 15:01:07 +12:00
Kusal Ekanayake 3e4a6f0f2e Merge remote-tracking branch 'origin/Story1055_Lobby_View_Update' into Merging_GameState_With_Lobby
# Conflicts:
#	src/main/java/seng302/client/ClientPacketParser.java
#	src/main/java/seng302/client/ClientToServerThread.java
#	src/main/java/seng302/controllers/LobbyController.java
#	src/main/java/seng302/controllers/StartScreenController.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
2017-07-24 14:58:14 +12:00
Kusal Ekanayake c1e937049e Merge remote-tracking branch 'origin/Story62_Swtich_To_RaceView_When_Race_Start' into Merging_GameLoop_with_Broadcast
# Conflicts:
#	src/main/java/seng302/controllers/LobbyController.java
#	src/main/java/seng302/controllers/StartScreenController.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
2017-07-24 14:37:56 +12:00
Zhi You Tan 8f8d5c7384 Removed a test sending xml
#story[1055]
2017-07-24 14:24:54 +12:00
Calum aad93d8913 Parsing classes now static utilities. Data now moved to model via controller class. Race logic shifted out of grpahics classes. Several improvements to code readability.
#story[986] #refactor
2017-07-24 12:14:08 +12:00
Zhi You Tan 027c7a1480 Updated start screen controller to connect to itself after setting up server.
#story[1047]
2017-07-24 12:09:23 +12:00
Zhi You Tan df2efa3329 Lobby controller list view is able to react to changes in client state boats and update the list view appropriately.
#story[1055]
2017-07-24 11:15:10 +12:00
Zhi You Tan 9d754c8819 Implemented list views initialisation which will set the first pane to be your source id (after three way handshake) and the remaining pane to be the source id of other players based on boats.xml received.
Updated client parser and client state to save a list of player's boat

WIP: refresh list view to show the latest update in players

#story[1055]
2017-07-23 20:42:21 +12:00
Zhi You Tan e11ceed28c Merge remote-tracking branch 'origin/Story62_Creating_Game_Loop' into Story1055_Lobby_View_Update
# Conflicts:
#	src/main/java/seng302/controllers/StartScreenController.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
2017-07-23 19:59:30 +12:00
Michael Rausch 8b8b6e4afa Fixed map glitch when race starts, and race XML bug
- Race XML wasn't being sent to clients, this was causing a null ptr exception
- Boat location was being set to an invalid lat/lng

Tags: #story[1047]
2017-07-23 18:20:13 +12:00
Kusal Ekanayake ed2a22b573 Tried to merge game loop with the broadcast. Minor error in canvas. need to fix.
#story[1047]
2017-07-23 17:37:45 +12:00
Kusal Ekanayake 41851ee925 Merge branch 'Story62_Creating_Game_Loop' into Merging_GameLoop_with_Broadcast
# Conflicts:
#	src/main/java/seng302/controllers/StartScreenController.java
#	src/main/java/seng302/gameServer/ServerListenThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/models/Yacht.java
2017-07-23 17:34:24 +12:00
Kusal Ekanayake ffc61942a9 Fixed broken pipe error.
Was caused by boat ids being over 1000 and when turned into xml having a comma placed between the hundreds and the thousands? So to fix, I just mad the max id number 999 so there should not be any issues regarding that if another broken pipe error occurs. Also switched to use the correct yacht constructor.

#story[1047]
2017-07-23 17:10:18 +12:00
Kusal Ekanayake 2e4382bff6 Trying to fix the boat information that is being sent over.
Current issue is that a broken pipe error keeps occurring potentially due to how the messages are being sent so quickly that the previous message may have not finished sending. Also only caused the xm packets to be sent on trigger when a new client connects.

#story[1047]
2017-07-23 16:22:59 +12:00
Zhi You Tan f542dbb61e Changed the competitors list view to eight individual list view.
Added eight individual image view to support future player icon implementation.

#story[1055]
2017-07-23 03:00:29 +12:00
William Muir 2869d139a3 Three way handshake implemented client and server side and functioning
Server generates a new Id for connections (Size of connections + 1)
Client now stores an id allocated to it by the server
The id is currently being saved in the clientToServer thread client side

tags: #story[987] #implement
2017-07-22 17:44:37 +12:00
William Muir 3ec930491f Minor refactor, threads now start themselves
tags: #story[989] #refactor
2017-07-22 16:45:24 +12:00
William Muir a0005064ac Fixed the Yacht clas so it now works.
Lists and Maps are instantiated as they should be in GameState which were creating NullPointers
Introduced ServerLog to server to client threads for bug reporting
Introduced some print statements to test the game state updating upon receiving key presses

tags: #story[989] #refactor #fix
2017-07-22 16:32:05 +12:00
Michael Rausch 33fae9d69a Added race boats to XML Generator
Tags: #story[1047]
2017-07-21 16:56:46 +12:00
Peter Galloway 913e5fee7b Hooked up key press actions to the GameState, applying the relevant maths to update headings etc.
tags: #story[989]  #pair[ptg19, wmu16]
2017-07-21 16:50:09 +12:00
Zhi You Tan 3992073303 Set race started state in client state when packet is passed in client packet parser.
#story[1055]
2017-07-21 16:36:56 +12:00
Zhi You Tan 797a99f632 Merge remote-tracking branch 'origin/develop' into Story62_Swtich_To_RaceView_When_Race_Start
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
2017-07-21 16:35:04 +12:00
Zhi You Tan e891ed8a64 LobbyView now can change to RaceView upon race start packet received.
Added port number text field in start screen controller.
Created a client state.

#story[1055] #pair[hyi25, zyt10]
2017-07-21 16:14:45 +12:00
Michael Rausch e8c2cf809b Fixed Null Ptr Exception in GameState 2017-07-21 15:42:20 +12:00
Michael Rausch ec761893c7 Merge branch 'Story62_Reading_Keystrokes' into 'develop'
Story62 reading keystrokes

Big merge

See merge request !44
2017-07-21 15:39:39 +12:00
Kusal Ekanayake 5df7efda03 Started implementing the gameState broadcasts.
Initial xml files are almost broad casted, just need to create them (or import the for the regatta). Started the setup for sending boat location packets, should work once we get at least the boat xml working when being sent.

#story[1047]
2017-07-21 13:16:43 +12:00
Kusal Ekanayake 2fff73c075 Merge remote-tracking branch 'origin/984_Xml_Generation' into Broadcasting_GameState
# Conflicts:
#	src/main/java/seng302/controllers/FinishScreenViewController.java
#	src/main/java/seng302/controllers/RaceViewController.java
#	src/main/java/seng302/gameServer/GameServerThread.java
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/models/Yacht.java
2017-07-21 12:31:35 +12:00
Zhi You Tan d37cbd263e Merge remote-tracking branch 'origin/Story62_Creating_Game_Loop' into Story62_Reading_Keystrokes
# Conflicts:
#	src/main/java/seng302/controllers/RaceViewController.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
2017-07-21 11:13:40 +12:00
Calum 3ec1242a9a Merge branch 'Story62_Reading_Keystrokes' into story61_player_perspective
# Conflicts:
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-07-21 11:13:04 +12:00
Calum 881f7f8e30 Changed package heirachy. Merged Controller and StartScreenController.
#refactor
2017-07-21 09:22:55 +12:00
Peter Galloway 12c2f31af9 Merge remote-tracking branch 'origin/Story62_Creating_Game_Loop' into Story62_Creating_Game_Loop
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
2017-07-20 19:38:07 +12:00
Peter Galloway 49c0c029c3 adjusted the way the server is receiving key presses to enable them be passed through to the game state #pair[ptg19, wmu16] #story[989] 2017-07-20 19:35:59 +12:00
Alistair McIntyre da7a34fc55 Started adding functionality to calculate yacht velocity from the wind speed and direction using polar tables. Also began writing tests to cover this functionality, as it can't currently be tested within the game itself.
#story[986]
2017-07-20 14:30:13 +12:00
Michael Rausch 322ff740e2 Added race start time to race XML
- Added race start time to race XML
- Added documentation
- Removed test code in MainServerThread

Tags: #story[984]
2017-07-20 14:28:59 +12:00
Kusal Ekanayake b1575e57df Host also can be it's own client.
The host can connect to itself to become a client, packets are also sending from the host to client, update method should be ready to fully implemented. Added chatter packets to packet types to be used mostly for testing but can be further implemented for proper use in the future.

#story[1055]
2017-07-20 13:53:53 +12:00
Michael Rausch 82b219cdba Boat and race XML now generated dynamically
- Removed course from XML Generator as it was not needed
- Boat and race XML added
- Method names in Yacht class updated to follow JavaBean standard so they can be read by the template engine

Tags: #story[984]
2017-07-20 13:30:55 +12:00
Peter Galloway e317de7562 Added mock yachts to the game state for each client #story[1047] 2017-07-20 13:11:37 +12:00
Calum 9ecaa7c3b3 Merge branch 'Story62_Reading_Keystrokes' into story61_player_perspective 2017-07-20 13:05:26 +12:00
Calum 037b0db01b Refactoring client for more atomic classes, will mimic the socket, game state, logic thread layout used by the server.
#refactor
2017-07-20 13:04:29 +12:00
Zhi You Tan 1e80d76acd Retrieve local host ip address and show it on lobby view.
#story[1055] #pair[hyi25, zyt10]
2017-07-20 12:52:53 +12:00
Calum 360c55fdb9 Merge branch 'Story62_Reading_Keystrokes' into story61_player_perspective
# Conflicts:
#	src/main/java/seng302/controllers/GameViewController.java
#	src/main/java/seng302/fxObjects/BoatGroup.java
2017-07-20 12:20:12 +12:00
Peter Galloway 176d65e0b2 Merge branch 'Story62_Reading_Keystrokes' into Story62_Creating_Game_Loop 2017-07-20 12:01:53 +12:00
William Muir 0c08f5a03c Refactoring to remove all superflous classes related to the server
GameServerThread --> MainServerThread
All server classes consolidated into the gameServer package and all others removed

tags: #story[1055] #refactor #fix
2017-07-20 11:46:06 +12:00
William Muir e257602b78 Merge remote-tracking branch 'origin/Story62_Reading_Keystrokes' into Story62_Reading_Keystrokes
# Conflicts:
#	src/main/java/seng302/controllers/LobbyController.java
#	src/main/java/seng302/gameServer/MainServerThread.java
2017-07-20 11:35:27 +12:00
William Muir 8f00f3a80c Refactoring for server package, Changed GameServerThread to MainServerThread.
All Server classes now in single gameServer package

tags: #story[1055]
2017-07-20 11:22:30 +12:00
Peter Galloway 63d24c001f Added position update in yacht #story[1047] 2017-07-19 19:41:07 +12:00
Peter 67668fe1fc Merge branch 'Story62_Reading_Keystrokes' into Story62_Creating_Game_Loop 2017-07-19 18:13:58 +12:00
Kusal Ekanayake dbbb41e12f Multiple clients are now shown in lobby of host.
When multiple clients connect to the host, the lobby table now fills up with the names of the threads (will need to be changed later). Re-enabled multiple people connecting and the lobby table. Formatting changes in the lobby screen also made.

#story[1047]
2017-07-19 16:05:21 +12:00
Michael Rausch 45053ba507 Added XML Generation
- Implemented a wrapper for Apache Freemake
- Implemented the regatta XML generator

Tags: #story[984]
2017-07-19 14:47:16 +12:00
Calum d9f5f7a137 Refactoring view for game development
#story[987]
2017-07-18 14:00:24 +12:00
William Muir b301ce5d27 fixed build (i think?)
tags: #story[1055] pair[wmu16, zyt10]
2017-07-18 12:26:47 +12:00
William Muir f02bd3b3f8 Merge remote-tracking branch 'origin/Story62_Reading_Keystrokes' into Story62_Reading_Keystrokes 2017-07-18 12:23:09 +12:00
William Muir e83eaa38e1 Upon hosting, and then creating a new instance and connecting to that IP, button transmissions work and print out on server!! :D
Took the send method out of the Message class as it didnt make sense to have it there. This meant taking it out of all subclasses too

tags: #story[1055] pair[wmu16, zyt10]
2017-07-18 12:22:58 +12:00
Kusal Ekanayake 102b5f3ca1 Added a program icon that I snipped from the logo using photoshop. 2017-07-18 10:46:41 +12:00
Haoming Yin 63958a6717 WIP: Implemented a temporary workaround to send an instance test to client server upon connection.
Still needs reengineering to change socket channels for sending to ouput stream in the message class.
Only client to server "working".

#story[1047] #pair[hyi25, wmu16] #pair[cir27, zyt10]
2017-07-17 17:00:04 +12:00
Haoming Yin 4b8ac32ca9 Merge branch '1047_Hosting_Game' into Story62_Reading_Keystrokes 2017-07-17 10:55:17 +12:00
Haoming Yin 00b29a1890 Merge remote-tracking branch 'origin/develop' into Story62_Reading_Keystrokes 2017-07-17 10:55:08 +12:00
Haoming Yin c7e5f93bc4 Merged GeoUtility and GeometryUtils classes
#story[1047]
2017-07-16 21:58:40 +12:00
Haoming Yin e4d87c91a2 Merge branch 'develop' into 1047_Hosting_Game 2017-07-16 21:54:08 +12:00
Zhi You Tan f84091e54e Removed (fxml) table view and its table column from lobby controller because the table view is removed from LobbyView.fxml
#story[988]
2017-07-14 18:27:54 +12:00
Zhi You Tan e03e8825b2 Merge remote-tracking branch 'origin/1047_Hosting_Game' into Story62_Reading_Keystrokes 2017-07-14 18:23:28 +12:00
Zhi You Tan 355f8543f5 Implemented a more reliable way for keystroke input and added boat action packet type so stream parser is able to read and decode the message appropriately.
#story[988] #pair[hyi25, zyt10]
2017-07-14 18:23:07 +12:00
William Muir 77e7db79cc WIP: Worked on new server thread class that would create and store multiple THREADS of connections. Researched Authorative server structures.
Fixed the current structure of the server to work with the old StreamReciever style and hook up to the Stream Parser

tags: #story[1047] pair[wmu16, mra106]
2017-07-14 17:09:33 +12:00
Zhi You Tan 2809d0d832 Merge branch '1047_Hosting_Game' into Story62_Reading_Keystrokes
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-07-14 16:28:42 +12:00
William Muir 5b908ec355 Merge remote-tracking branch 'origin/1047_Hosting_Game' into 1047_Hosting_Game
# Conflicts:
#	src/main/java/seng302/gameServer/GameServerThread.java
2017-07-13 22:55:49 +12:00
William Muir c480fca72a WIP: Worked on new server thread class that would create and store multiple THREADS of connections. Researched Authorative server structures
tags: #story[1047]
2017-07-13 22:55:03 +12:00
Michael Rausch c19f66a6a4 Added garbage collection for disconnected players
- Heartbeat messages are sent out from their own thread to each player
- If a heartbeat message can't be sent to a player, they are removed from the list of players
- Added equals method for players
Tags: #story[1047]
2017-07-13 22:07:03 +12:00
Michael Rausch 1e6fd1af09 Fixed bug where players were being added to the GameState twice
#story[1047]
2017-07-13 19:27:47 +12:00
Michael Rausch 55db2c9961 Fixed buffer overflow in message header
- Fixed buffer overflow by adding a reset method that  clears the buffer and sets the position to zero before re-writing the header
Tags: #story[1047]
2017-07-13 19:15:45 +12:00
Haoming Yin 6ec8b0c3c5 Terminated the game server socket when click exit lobby button
- the whole server thread should be terminated instead. To be fixed in the future.

#story[1047] #issue[28]
2017-07-13 17:51:25 +12:00
Kusal Ekanayake 78557a4536 Key presses are transmitted to a host (but there is no host currently connected)
#pair[kre39,zyt10] #story[988]
2017-07-13 15:39:48 +12:00
William Muir 8090cd7985 WIP: Adapted the old server thread class to the GameServerThread class to allow multiple clients to connect
tags: #story[1047]  #pair[wmu16]
2017-07-13 14:40:11 +12:00
Kusal Ekanayake 5ce34bed92 Key presses now assigned to enum and empty packet class is constructed.
#pair[kre39,zyt10] #story[988]
2017-07-13 14:35:41 +12:00
William Muir 035841f221 WIP: Adapted the old server thread class to the GameServerThread class to allow multiple clients to connect
tags: #story[1047]  #pair[wmu16, mra106]
2017-07-11 17:03:32 +12:00
Kusal Ekanayake ef61a687d6 Researched and implemented a way for the game to listen for key presses. When one of the valid key controls are pressed, feedback is given in the console. Has yet to be connected to a method which will create and send a message to the server.
#pair[kre39,zyt10] #story[988]
2017-07-11 16:32:15 +12:00
Haoming Yin fcb1e5e593 Removed unnecessary Position and GeoPoint classes to clear the code base.
- put utility classes in a package

#story[1047]
2017-07-10 23:51:01 +12:00
William Muir 752863a0d3 WIP: Created some basic controllers for the UI and started implementing backend for server stuff
Created GameState Class. Static, contains all info about current state of game: list of players and their respective details (coords etc) also Host info

Clients will observe this GameState class

Upon pressing host, new GameState is created and new GameConnectionListener created which listens for connections

Player class created which will be used to take each connection and store it as a player with other info about them regarding the game in the GameState class

tags: #story[1047]  #pair[wmu16, zyt10]
2017-07-10 16:03:13 +12:00
William Muir 1a3e330eb4 Created some basic UI for new start screen (host and connect) and a lobby
tags: #story[1047]  #pair[wmu16, zyt10]
2017-07-10 13:43:25 +12:00
William Muir 5f9da6b40a Fixed the bug where the polar file could not be read after being packaged
tags: #story[955]  #pair[wmu16, zyt10]
2017-07-10 12:36:32 +12:00
Michael Rausch aee62c29fe Merge remote-tracking branch 'origin/develop' into develop 2017-05-26 09:07:22 +12:00
Michael Rausch fe76ef9cdc Merge remote-tracking branch 'origin/develop' 2017-05-25 16:58:01 +12:00
Michael Rausch acbaa838ec Change default port to 4940
#story[956] #pair[wmu16, mra106]
2017-05-25 16:56:41 +12:00
Haoming Yin f4134d83b5 Merge branch 'issue#8_create_finish_screen' into 'develop'
Issue#8 create finish screen

Created a finish screen which user can see position of the final result and able to go back to start screen to rewatch new race

See merge request !41
2017-05-25 16:52:59 +12:00
Zhi You Tan 24cc10e1cd Merge remote-tracking branch 'origin/develop' into issue#8_create_finish_screen
# Conflicts:
#	src/main/java/seng302/controllers/CanvasController.java
2017-05-25 16:51:32 +12:00
Zhi You Tan 20b79b40f2 Fix the button position #story[923] 2017-05-25 16:45:35 +12:00
Zhi You Tan 72e2776b7e Fix the finish screen size #story[923] 2017-05-25 16:41:59 +12:00
Kusal Ekanayake 49e4c92da6 Merge branch 'develop' 2017-05-25 16:40:24 +12:00
Kusal Ekanayake ba761e4951 Merge branch 'remove_observers' into 'develop'
Remove observers

Refactor for annotations and a few improvements here and there. Fix for several tracked issues and numerous other bug fixes.

See merge request !40
2017-05-25 16:36:43 +12:00
Calum c1aa1d8eae merged with dev 2017-05-25 16:32:25 +12:00
Calum 4231c3ccd8 Merge remote-tracking branch 'origin/develop' into remove_observers 2017-05-25 16:30:15 +12:00
Calum 65223ceaaf shifted annotation layers. Merged with dev. 2017-05-25 16:29:27 +12:00
Zhi You Tan 559a9f38c0 Merge remote-tracking branch 'origin/develop' into issue#8_create_finish_screen
# Conflicts:
#	src/main/java/seng302/controllers/CanvasController.java
#	src/main/java/seng302/models/stream/StreamParser.java
2017-05-25 16:12:44 +12:00
Michael Rausch 3bd8added4 Merge remote-tracking branch 'origin/develop' into develop 2017-05-25 14:56:11 +12:00
Michael Rausch ba527a1979 Merge remote-tracking branch 'origin/develop' into develop 2017-05-25 14:54:28 +12:00
Calum b73e4c89db Merge remote-tracking branch 'origin/develop' into remove_observers
# Conflicts:
#	src/main/java/seng302/controllers/CanvasController.java
#	src/main/java/seng302/controllers/RaceViewController.java
#	src/main/java/seng302/fxObjects/BoatGroup.java
#	src/main/java/seng302/fxObjects/MarkGroup.java
#	src/main/java/seng302/models/Yacht.java
2017-05-25 14:52:54 +12:00
Michael Rausch 945acb6071 Merge remote-tracking branch 'origin/develop' into develop 2017-05-25 13:57:07 +12:00
Zhi You Tan f163dfdd11 Removed a print statement 2017-05-25 13:14:36 +12:00
Zhi You Tan a1eda8d91d Fix boatPos in StreamParser.java being empty and affecting all the assessors 2017-05-25 12:58:11 +12:00
Zhi You Tan 5ed02a1fe1 Merge remote-tracking branch 'origin/develop' into issue#8_create_finish_screen
# Conflicts:
#	src/main/java/seng302/controllers/CanvasController.java
2017-05-25 12:32:10 +12:00
Zhi You Tan 66d4a4b958 Fix finish screen showing wrong ("-" as) position 2017-05-25 12:28:13 +12:00
Calum 0cd2867ac0 Made annotations more readable when overlapping. 2017-05-25 10:30:01 +12:00
Calum 4d29354797 Merge branch 'develop' into remove_observers
# Conflicts:
#	src/main/java/seng302/controllers/CanvasController.java
#	src/main/java/seng302/fxObjects/BoatGroup.java
#	src/main/java/seng302/models/stream/StreamParser.java
2017-05-25 10:25:54 +12:00
Calum 3085125f3e Merged with develop 2017-05-25 01:21:40 +12:00
Calum 5e26ad7c36 Merge remote-tracking branch 'origin/develop' into remove_observers
# Conflicts:
#	src/main/java/seng302/App.java
#	src/main/java/seng302/controllers/CanvasController.java
#	src/main/java/seng302/controllers/RaceViewController.java
#	src/main/java/seng302/models/Yacht.java
2017-05-25 01:12:10 +12:00
Calum 765ea06c3b Several tweaks and improvements to a annotations and other visual aspects of them program. Fixed bug causing minimization crashes.
#implement #refactor #issue[23]
2017-05-25 01:02:33 +12:00
Calum 14a7305a2d Made FPS marker not draw on canvas.
Have to revert the use of the observer pattern since there is no time to change how and when data is passed.
2017-05-24 17:17:06 +12:00
Zhi You Tan e7060d4b6f Finish screen will show when race finishes, added functionality to return to start screen when in finish screen, updated finishScreenView.fxml to have controller and also four corner anchors to fit to parent 2017-05-24 16:17:56 +12:00
Zhi You Tan 641039720e Merge remote-tracking branch 'origin/develop' into issue#8_create_finish_screen 2017-05-24 16:12:37 +12:00
Michael Rausch 6f132f1e38 Merge remote-tracking branch 'origin/develop' into develop 2017-05-24 15:22:30 +12:00
Michael Rausch a1e8d29b9c Merge remote-tracking branch 'origin/develop' into develop 2017-05-24 14:36:04 +12:00
Zhi You Tan c449da2916 [WIP] created finishScreenView.fxml, finishScreenViewController.java 2017-05-24 14:24:14 +12:00
Calum d22d758757 Fix issues caused by not updating the time since last mark value frequently. BoatAnnotations now has an update() function that must be called somewhat regularly. 2017-05-24 03:23:02 +12:00
Calum acbde5aad8 Moved boat annotations into their own class. Implemented observer pattern.
Observer pattern appears to have caused issues with updating Text objects.
Made annotations look nicer. Kinda.

#refactor
2017-05-24 03:09:11 +12:00
Michael Rausch e26f2af93d Merge branch 'develop' of https://eng-git.canterbury.ac.nz/seng302-2017/team-13 into develop 2017-05-22 13:30:48 +12:00
Michael Rausch 6a6ed3ed44 Server sends mark locations to test
- Added a timer to send boat location messages containing the mark locations to test the receiver

#story[891]
2017-05-18 13:32:24 +12:00
374 changed files with 23002 additions and 7766 deletions
+4 -1
View File
@@ -7,7 +7,6 @@
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
@@ -180,3 +179,7 @@ local.properties
.recommenders/
Makefile
infer-out/
infer.txt
log.log
+1 -1
View File
@@ -23,5 +23,5 @@ Haoming Yin <hyi25@uclive.ac.nz> <haoming.y@icloud.com>
Peter Galloway <ptg19@uclive.ac.nz> Peter <ptg19@uclive.ac.nz>
Zhi You Tan <zyt10@uclive.ac.nz> zyt10 <zyt10@uclive.ac.nz>
Zhi You Tan <zyt10@uclive.ac.nz> Ryan Tan <ryan_zhiyou@hotmail.com>
Alistair McIntyre <ajm412@uclive.ac.nz> alistairjmcintyre <alistairjmcintyre@gmail.com>
Alistair McIntyre <ajm412@uclive.ac.nz> <alistairjmcintyre@gmail.com>
Calum <cir27@uclive.ac.nz> cir27 <cir27@uclive.ac.nz>
+1 -1
View File
@@ -9,7 +9,7 @@ prints out event details, including time, involved boats and legs.
- Configuration file
We decided to store the team information including team names and boat velocity, as well as race configuration setting in external file.
We decided to store the team information including team names and boat currentVelocity, as well as race configuration setting in external file.
To read external files, "Json-simple" library has been used to parse information.
By using this library, we did not have to write our json parser and benefited from the flexibility of json files.
+1 -1
View File
@@ -8,7 +8,7 @@ You can specify a config file using the using the -f flag, for example 'java -ja
## The config file
The teams/boats are specified in the config file under 'teams', each team requires a team name, and a velocity (in meters per second).
The teams/boats are specified in the config file under 'teams', each team requires a team name, and a currentVelocity (in meters per second).
The 'time-scale' option lets you change how long the race takes to complete. A time-scale of 1.0 is normal speed, 2.0 is 2x etc.
@@ -0,0 +1 @@
bc00cae65d030845973151123fd0f2b1
@@ -0,0 +1 @@
de6c72cb03b2216bbe03ac7b882f0c146fb76bc8
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>lib.com.interactivemesh</groupId>
<artifactId>jimColModelImporter</artifactId>
<version>0.7</version>
</project>
@@ -0,0 +1 @@
8fc884a64856917671745720acc6048c
@@ -0,0 +1 @@
4b35131587917ed1a16acb1eff8cd7a213a26edc
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>lib.com.interactivemesh</groupId>
<artifactId>jimColModelImporter</artifactId>
<versioning>
<release>0.7</release>
<versions>
<version>0.7</version>
</versions>
<lastUpdated>20170912024010</lastUpdated>
</versioning>
</metadata>
@@ -0,0 +1 @@
3132c3f88de1a942ac37930b8cdaa764
@@ -0,0 +1 @@
20847be06b0d11b70f1fbfb1527c5efee4e9f49e
@@ -0,0 +1 @@
deec04fc74e1115465598d342810df18
@@ -0,0 +1 @@
ea31eabe6384ae965cd8180920f7ba0248717313
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>lib.com.interactivemesh</groupId>
<artifactId>jimStlMeshImporter</artifactId>
<version>0.7</version>
</project>
@@ -0,0 +1 @@
82a485ac9a76d6587b1b23b7fbd8f5a0
@@ -0,0 +1 @@
2bac29a6598a88b2f115b72433181c13fc6201d2
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>lib.com.interactivemesh</groupId>
<artifactId>jimStlMeshImporter</artifactId>
<versioning>
<release>0.7</release>
<versions>
<version>0.7</version>
</versions>
<lastUpdated>20170912024122</lastUpdated>
</versioning>
</metadata>
@@ -0,0 +1 @@
cad88c5c501f771bc8d1fc085decb3c4
@@ -0,0 +1 @@
c6cd4fae002dbbe4246c8eac4b35de07d921fd51
+93
View File
@@ -11,6 +11,7 @@
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
@@ -36,6 +37,84 @@
<version>2.7.13</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-junit</artifactId>
<version>1.2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-java -->
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>1.2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.26-incubating</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.lwjgl/lwjgl -->
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>de.javagl</groupId>
<artifactId>obj</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>com.interactivemesh</groupId>
<artifactId>jimStlMeshImporter</artifactId>
<version>0.7</version>
</dependency>
<dependency>
<groupId>com.interactivemesh</groupId>
<artifactId>jimColModelImporter</artifactId>
<version>0.7</version>
</dependency>
<dependency>
<groupId>com.jfoenix</groupId>
<artifactId>jfoenix</artifactId>
<version>1.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.jmdns/jmdns -->
<dependency>
<groupId>javax.jmdns</groupId>
<artifactId>jmdns</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.fxyz3d</groupId>
<artifactId>fxyz3d</artifactId>
<version>0.1.1</version>
</dependency>
</dependencies>
<build>
@@ -118,4 +197,18 @@
</plugin>
</plugins>
</reporting>
<repositories>
<repository>
<id>lib</id>
<name>third party libraries</name>
<url>file://${basedir}/lib</url>
</repository>
<repository>
<id>Homer-Core</id>
<name>Homer-core-repo</name>
<url>https://nexus.arcsmed.at/content/repositories/homer.core</url>
</repository>
</repositories>
</project>
+98 -58
View File
@@ -1,82 +1,122 @@
package seng302;
import ch.qos.logback.classic.Level;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import seng302.models.PolarTable;
import seng302.models.stream.StreamParser;
import seng302.models.stream.StreamReceiver;
import seng302.server.ServerThread;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.discoveryServer.DiscoveryServer;
import seng302.visualiser.controllers.ViewManager;
import java.util.Timer;
import java.util.TimerTask;
public class App extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
PolarTable.parsePolarFile(getClass().getResource("/config/acc_polars.csv").getFile());
private static Logger logger = LoggerFactory.getLogger(App.class);
private static boolean isRunningAsCache = false;
Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml"));
primaryStage.setTitle("RaceVision");
primaryStage.setScene(new Scene(root, 1530, 960));
primaryStage.setMaxWidth(1530);
primaryStage.setMaxHeight(960);
// primaryStage.setMaximized(true);
public static void parseArgs(String[] args) throws ParseException {
Options options = new Options();
CommandLineParser parser = new DefaultParser();
CommandLine cmd;
primaryStage.show();
primaryStage.setOnCloseRequest(e -> {
StreamParser.appClose();
StreamReceiver.noMoreBytes();
System.exit(0);
});
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory
.getLogger(Logger.ROOT_LOGGER_NAME);
options.addOption("debugLevel", true, "Set the application debug level");
options.addOption("runAsDiscoveryServer", false, "Run as a discovery server");
options.addOption("discoveryDevMode", false, "Use a local discovery server");
cmd = parser.parse(options, args);
}
public static void main(String[] args) {
StreamReceiver sr = null;
new ServerThread("Racevision Test Server");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (args.length == 1 && args[0].equals("-standalone")) {
if (cmd.hasOption("runAsDiscoveryServer")){
isRunningAsCache = true;
rootLogger.setLevel(Level.ALL);
return;
}
if (args.length == 3 && args[0].equals("-server")) {
if (cmd.hasOption("discoveryDevMode")) {
DiscoveryServer.DISCOVERY_SERVER = "localhost";
}
sr = new StreamReceiver(args[1], Integer.valueOf(args[2]), "RaceStream");
if (cmd.hasOption("debugLevel")) {
} else if (args.length == 2 && args[0].equals("-server")) {
switch (args[1]) {
case "internal":
sr = new StreamReceiver("localhost", 4949, "RaceStream");
break;
case "staffserver":
sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream");
break;
case "official":
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
break;
switch (cmd.getOptionValue("debugLevel")) {
case "DEBUG":
rootLogger.setLevel(Level.DEBUG);
break;
case "ALL":
rootLogger.setLevel(Level.ALL);
break;
case "WARNING":
rootLogger.setLevel(Level.WARN);
break;
case "ERROR":
rootLogger.setLevel(Level.ERROR);
break;
case "INFO":
rootLogger.setLevel(Level.INFO);
case "TRACE":
rootLogger.setLevel(Level.TRACE);
default:
rootLogger.setLevel(Level.ALL);
}
} else {
rootLogger.setLevel(Level.WARN);
}
}
@Override
public void start(Stage primaryStage) throws Exception {
ViewManager.getInstance().initialiseSplashScreen(primaryStage);
}
private static void runDiscoveryServer() throws Exception {
while (true){
try {
new DiscoveryServer();
}
catch (Exception ignored){
;
}
}
//Change the StreamReceiver in this else block to change the default data source.
else{
sr = new StreamReceiver("localhost", 4949, "RaceStream");
}
public static void main(String[] args) throws Exception {
/*
* Do not trust Java to do garbage collection
*/
new Timer().schedule(new TimerTask() {
@Override
public void run() {
System.gc();
}
}, 0, 1_000);
try {
parseArgs(args);
} catch (ParseException e) {
logger.error("Could not parse command line arguments");
}
sr.start();
StreamParser streamParser = new StreamParser("StreamParser");
streamParser.start();
launch(args);
if (!isRunningAsCache){
launch(args);
}
else{
runDiscoveryServer();
}
}
}
-63
View File
@@ -1,63 +0,0 @@
package seng302;
import javafx.geometry.Point2D;
/**
* A Class for performing geometric calculations on the canvas
* Created by wmu16 on 24/05/17.
*/
public final class GeometryUtils {
/**
* Performs the line function on two points of a line and a test point to test which side of the line that point is
* on. If the return value is
* return 1, then the point is on one side of the line,
* return -1 then the point is on the other side of the line
* return 0 then the point is exactly on the line.
* @param linePoint1 One point of the line
* @param linePoint2 Second point of the line
* @param testPoint The point to test with this line
* @return A return value indicating which side of the line the point is on
*/
public static Integer lineFunction(Point2D linePoint1, Point2D linePoint2, Point2D testPoint) {
Double x = testPoint.getX();
Double y = testPoint.getY();
Double x1 = linePoint1.getX();
Double y1 = linePoint1.getY();
Double x2 = linePoint2.getX();
Double y2 = linePoint2.getY();
Double result = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1); //Line function
if (result > 0) {
return 1;
}
else if (result < 0) {
return -1;
}
else {
return 0;
}
}
/**
* Given a point and a vector (angle and vector length) Will create a new point, that vector away from the origin
* point
* @param originPoint The point with which to use as the base for our vector addition
* @param angleInDeg (DEGREES) The angle at which our new point is being created (in degrees!)
* @param vectorLength The length out on this angle from the origin point to create the new point
* @return a Point2D
*/
public static Point2D makeArbitraryVectorPoint(Point2D originPoint, Double angleInDeg, Double vectorLength) {
Double endPointX = originPoint.getX() + vectorLength * Math.cos(Math.toRadians(angleInDeg));
Double endPointY = originPoint.getY() + vectorLength * Math.sin(Math.toRadians(angleInDeg));
return new Point2D(endPointX, endPointY);
}
}
@@ -1,523 +0,0 @@
package seng302.controllers;
import javafx.animation.AnimationTimer;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import seng302.models.BoatGroup;
import seng302.models.Colors;
import seng302.models.Yacht;
import seng302.models.map.Boundary;
import seng302.models.map.CanvasMap;
import seng302.models.mark.*;
import seng302.models.stream.StreamParser;
import seng302.models.stream.XMLParser;
import seng302.models.stream.XMLParser.RaceXMLObject.Limit;
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
import seng302.models.stream.packets.BoatPositionPacket;
import seng302.server.simulator.GeoUtility;
import seng302.server.simulator.mark.Position;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.PriorityBlockingQueue;
/**
* Created by ptg19 on 15/03/17.
* Modified by Haoming Yin (hyi25) on 20/3/2017.
*/
public class CanvasController {
@FXML
private AnchorPane canvasPane;
private RaceViewController raceViewController;
private ResizableCanvas canvas;
private Group group;
private GraphicsContext gc;
private ImageView mapImage;
private final int BUFFER_SIZE = 50;
private final int PANEL_WIDTH = 1260; // it should be 1280 but, minors 40 to cancel the bias.
private final int PANEL_HEIGHT = 960;
private final int CANVAS_WIDTH = 720;
private final int CANVAS_HEIGHT = 720;
private boolean horizontalInversion = false;
private double distanceScaleFactor;
private ScaleDirection scaleDirection;
private Mark minLatPoint;
private Mark minLonPoint;
private Mark maxLatPoint;
private Mark maxLonPoint;
private double referencePointX;
private double referencePointY;
private double metersPerPixelX;
private double metersPerPixelY;
private List<MarkGroup> markGroups = new ArrayList<>();
private List<BoatGroup> boatGroups = new ArrayList<>();
//FRAME RATE
private Double frameRate = 60.0;
private final long[] frameTimes = new long[30];
private int frameTimeIndex = 0;
private boolean arrayFilled = false;
public AnimationTimer timer;
private enum ScaleDirection {
HORIZONTAL,
VERTICAL
}
public void setup(RaceViewController raceViewController){
this.raceViewController = raceViewController;
}
public void initialize() {
raceViewController = new RaceViewController();
canvas = new ResizableCanvas();
group = new Group();
// create image view for map, bind panel size to image
mapImage = new ImageView();
canvasPane.getChildren().add(mapImage);
mapImage.fitWidthProperty().bind(canvasPane.widthProperty());
mapImage.fitHeightProperty().bind(canvasPane.heightProperty());
canvasPane.getChildren().add(canvas);
canvasPane.getChildren().add(group);
// Bind canvas size to stack pane size.
canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH));
canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT));
}
public void initializeCanvas (){
gc = canvas.getGraphicsContext2D();
gc.setGlobalAlpha(0.5);
fitMarksToCanvas();
drawGoogleMap();
// TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml
initializeBoats();
initializeMarks();
timer = new AnimationTimer() {
private int UPDATE_FPM_PERIOD = 50; // update FPM label every 50 frames
private int updateFPMCounter = 100;
@Override
public void handle(long now) {
//fps stuff
long oldFrameTime = frameTimes[frameTimeIndex] ;
frameTimes[frameTimeIndex] = now ;
frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length ;
if (frameTimeIndex == 0) {
arrayFilled = true ;
}
long elapsedNanos;
if (arrayFilled) {
elapsedNanos = now - oldFrameTime ;
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
if (updateFPMCounter++ > UPDATE_FPM_PERIOD) {
updateFPMCounter = 0;
drawFps(frameRate.intValue());
}
raceViewController.updateSparkLine();
}
updateGroups();
if (StreamParser.isRaceFinished()) {
this.stop();
}
}
};
}
/**
* First find the top right and bottom left points' geo locations, then retrieve
* map from google to display on image view. - Haoming 22/5/2017
*/
private void drawGoogleMap() {
findMetersPerPixel();
Point2D topLeftPoint = findScaledXY(maxLatPoint.getLatitude(), minLonPoint.getLongitude());
// distance from top left extreme to panel origin (top left corner)
double distanceFromTopLeftToOrigin = Math.sqrt(Math.pow(topLeftPoint.getX() * metersPerPixelX, 2) + Math.pow(topLeftPoint.getY() * metersPerPixelY, 2));
// angle from top left extreme to panel origin
double bearingFromTopLeftToOrigin = Math.toDegrees(Math.atan2(-topLeftPoint.getX(), topLeftPoint.getY()));
// the top left extreme
Position topLeftPos = new Position(maxLatPoint.getLatitude(), minLonPoint.getLongitude());
Position originPos = GeoUtility.getGeoCoordinate(topLeftPos, bearingFromTopLeftToOrigin, distanceFromTopLeftToOrigin);
// distance from origin corner to bottom right corner of the panel
double distanceFromOriginToBottomRight = Math.sqrt(Math.pow(PANEL_HEIGHT* metersPerPixelY, 2) + Math.pow(PANEL_WIDTH * metersPerPixelX, 2));
double bearingFromOriginToBottomRight = Math.toDegrees(Math.atan2(PANEL_WIDTH, -PANEL_HEIGHT));
Position bottomRightPos = GeoUtility.getGeoCoordinate(originPos, bearingFromOriginToBottomRight, distanceFromOriginToBottomRight);
Boundary boundary = new Boundary(originPos.getLat(), bottomRightPos.getLng(), bottomRightPos.getLat(), originPos.getLng());
CanvasMap canvasMap = new CanvasMap(boundary);
mapImage.setImage(canvasMap.getMapImage());
}
/**
* Adds border marks to the canvas, taken from the XML file
*
* NOTE: This is quite confusing as objects are grabbed from the XMLParser such as Mark and CompoundMark which are
* named the same as those in the model package but are, however not the same, so they do not have things such as
* a type and must be derived from the number of marks in a compound mark etc..
*/
private void addRaceBorder() {
XMLParser.RaceXMLObject raceXMLObject = StreamParser.getXmlObject().getRaceXML();
ArrayList<Limit> courseLimits = raceXMLObject.getCourseLimit();
gc.setStroke(Color.DARKBLUE);
gc.setLineWidth(3);
double[] xBoundaryPoints = new double[courseLimits.size()];
double[] yBoundaryPoints = new double[courseLimits.size()];
for (int i = 0; i < courseLimits.size() - 1; i++) {
Limit thisPoint1 = courseLimits.get(i);
SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID(), thisPoint1.getSeqID());
Limit thisPoint2 = courseLimits.get(i+1);
SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID(), thisPoint2.getSeqID());
Point2D borderPoint1 = findScaledXY(thisMark1);
Point2D borderPoint2 = findScaledXY(thisMark2);
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
borderPoint2.getX(), borderPoint2.getY());
xBoundaryPoints[i] = borderPoint1.getX();
yBoundaryPoints[i] = borderPoint1.getY();
}
Limit thisPoint1 = courseLimits.get(courseLimits.size()-1);
SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID(), thisPoint1.getSeqID());
Limit thisPoint2 = courseLimits.get(0);
SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID(), thisPoint2.getSeqID());
Point2D borderPoint1 = findScaledXY(thisMark1);
Point2D borderPoint2 = findScaledXY(thisMark2);
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
borderPoint2.getX(), borderPoint2.getY());
xBoundaryPoints[courseLimits.size()-1] = borderPoint1.getX();
yBoundaryPoints[courseLimits.size()-1] = borderPoint1.getY();
// gc.setFill(Color.LIGHTBLUE);
// gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length);
}
private void updateGroups(){
for (BoatGroup boatGroup : boatGroups) {
// some raceObjects will have multiple ID's (for instance gate marks)
//checking if the current "ID" has any updates associated with it
if (StreamParser.boatLocations.containsKey(boatGroup.getRaceId())) {
if (boatGroup.isStopped()) {
updateBoatGroup(boatGroup);
}
}
boatGroup.move();
}
for (MarkGroup markGroup : markGroups) {
for (Long id : markGroup.getRaceIds()) {
if (StreamParser.markLocations.containsKey(id)) {
updateMarkGroup(id, markGroup);
}
}
}
checkForCourseChanges();
}
private void checkForCourseChanges() {
if (StreamParser.isNewRaceXmlReceived()){
gc.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
drawGoogleMap();
addRaceBorder();
}
}
private void updateBoatGroup(BoatGroup boatGroup) {
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.boatLocations.get(boatGroup.getRaceId());
// giving the movementQueue a 5 packet buffer to account for slightly out of order packets
if (movementQueue.size() > 0){
try {
BoatPositionPacket positionPacket = movementQueue.take();
Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
double heading = 360.0 / 0xffff * positionPacket.getHeading();
boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), positionPacket.getTimeValid(), frameRate, boatGroup.getRaceId());
} catch (InterruptedException e){
e.printStackTrace();
}
// }
}
}
void updateMarkGroup (long raceId, MarkGroup markGroup) {
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.markLocations.get(raceId);
if (movementQueue.size() > 0){
try {
BoatPositionPacket positionPacket = movementQueue.take();
Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
markGroup.moveMarkTo(p2d.getX(), p2d.getY(), raceId);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
/**
* Draws all the boats.
*/
private void initializeBoats() {
Map<Integer, Yacht> boats = StreamParser.getBoats();
Group boatAnnotations = new Group();
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML().getParticipants();
ArrayList<Integer> participantIDs = new ArrayList<>();
for (Participant p : participants) {
participantIDs.add(p.getsourceID());
}
for (Yacht boat : boats.values()) {
if (participantIDs.contains(boat.getSourceID())) {
boat.setColour(Colors.getColor());
BoatGroup boatGroup = new BoatGroup(boat, boat.getColour());
boatGroups.add(boatGroup);
boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations());
}
}
group.getChildren().add(boatAnnotations);
group.getChildren().addAll(boatGroups);
}
private void initializeMarks() {
List<Mark> allMarks = StreamParser.getXmlObject().getRaceXML().getNonDupCompoundMarks();
for (Mark mark : allMarks) {
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
SingleMark sMark = (SingleMark) mark;
MarkGroup markGroup = new MarkGroup(sMark, findScaledXY(sMark));
markGroups.add(markGroup);
} else {
GateMark gMark = (GateMark) mark;
MarkGroup markGroup = new MarkGroup(gMark, findScaledXY(gMark.getSingleMark1()), findScaledXY(gMark.getSingleMark2())); //should be 2 objects in the list.
markGroups.add(markGroup);
}
}
group.getChildren().addAll(markGroups);
}
class ResizableCanvas extends Canvas {
ResizableCanvas() {
// Redraw canvas when size changes.
widthProperty().addListener(evt -> draw());
heightProperty().addListener(evt -> draw());
}
private void draw() {
double width = getWidth();
double height = getHeight();
GraphicsContext gc = getGraphicsContext2D();
gc.clearRect(0, 0, width, height);
}
@Override
public boolean isResizable() {
return true;
}
@Override
public double prefWidth(double height) {
return getWidth();
}
@Override
public double prefHeight(double width) {
return getHeight();
}
}
private void drawFps(int fps){
if (raceViewController.isDisplayFps()){
gc.clearRect(5, 5, 60, 30);
gc.setFont(new Font(16));
gc.setLineWidth(4);
gc.setGlobalAlpha(0.75);
gc.fillText(fps + " FPS", 5, 20);
gc.setGlobalAlpha(0.5);
} else {
gc.clearRect(5,5,60,30);
}
}
/**
* Calculates x and y location for every marker that fits it to the canvas the race will be drawn on.
*/
private void fitMarksToCanvas() {
//Check is called once to avoid unnecessarily change the course limits once the race is running
StreamParser.isNewRaceXmlReceived();
findMinMaxPoint();
double minLonToMaxLon = scaleRaceExtremities();
calculateReferencePointLocation(minLonToMaxLon);
//givePointsXY();
addRaceBorder();
}
/**
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the marker with the leftmost
* marker, rightmost marker, southern most marker and northern most marker respectively.
*/
private void findMinMaxPoint() {
List<Limit> sortedPoints = new ArrayList<>();
for (Limit limit : StreamParser.getXmlObject().getRaceXML().getCourseLimit()) {
sortedPoints.add(limit);
}
sortedPoints.sort(Comparator.comparingDouble(Limit::getLat));
Limit minLatMark = sortedPoints.get(0);
Limit maxLatMark = sortedPoints.get(sortedPoints.size()-1);
minLatPoint = new SingleMark(minLatMark.toString(), minLatMark.getLat(), minLatMark.getLng(), minLatMark.getSeqID(), minLatMark.getSeqID());
maxLatPoint = new SingleMark(maxLatMark.toString(), maxLatMark.getLat(), maxLatMark.getLng(), maxLatMark.getSeqID(), minLatMark.getSeqID());
sortedPoints.sort(Comparator.comparingDouble(Limit::getLng));
//If the course is on a point on the earth where longitudes wrap around.
Limit minLonMark = sortedPoints.get(0);
Limit maxLonMark = sortedPoints.get(sortedPoints.size()-1);
minLonPoint = new SingleMark(minLonMark.toString(), minLonMark.getLat(), minLonMark.getLng(), minLonMark.getSeqID(), minLonMark.getSeqID());
maxLonPoint = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID(), minLonMark.getSeqID());
if (maxLonPoint.getLongitude() - minLonPoint.getLongitude() > 180) {
horizontalInversion = true;
}
}
/**
* Calculates the location of a reference point, this is always the point with minimum latitude, in relation to the
* canvas.
*
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to maximum longitude.
*/
private void calculateReferencePointLocation (double minLonToMaxLon) {
Mark referencePoint = minLatPoint;
double referenceAngle;
if (scaleDirection == ScaleDirection.HORIZONTAL) {
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
referencePointX = BUFFER_SIZE + distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, maxLatPoint));
referencePointY = CANVAS_HEIGHT - (BUFFER_SIZE + BUFFER_SIZE);
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
referencePointY = referencePointY / 2;
referencePointY += BUFFER_SIZE;
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
} else {
referencePointY = CANVAS_HEIGHT - BUFFER_SIZE;
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
referencePointX = BUFFER_SIZE;
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
referencePointX += ((CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
}
if(horizontalInversion) {
referencePointX = CANVAS_WIDTH - BUFFER_SIZE - (referencePointX - BUFFER_SIZE);
}
}
/**
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns it to distanceScaleFactor
* Returns the max horizontal distance of the map.
*/
private double scaleRaceExtremities () {
double vertAngle = Math.abs(Mark.calculateHeadingRad(minLatPoint, maxLatPoint));
double vertDistance = Math.cos(vertAngle) * Mark.calculateDistance(minLatPoint, maxLatPoint);
double horiAngle = Mark.calculateHeadingRad(minLonPoint, maxLonPoint);
if (horiAngle <= (Math.PI / 2))
horiAngle = (Math.PI / 2) - horiAngle;
else
horiAngle = horiAngle - (Math.PI / 2);
double horiDistance = Math.cos(horiAngle) * Mark.calculateDistance(minLonPoint, maxLonPoint);
double vertScale = (CANVAS_HEIGHT - (BUFFER_SIZE + BUFFER_SIZE)) / vertDistance;
if ((horiDistance * vertScale) > (CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE))) {
distanceScaleFactor = (CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE)) / horiDistance;
scaleDirection = ScaleDirection.HORIZONTAL;
} else {
distanceScaleFactor = vertScale;
scaleDirection = ScaleDirection.VERTICAL;
}
return horiDistance;
}
private Point2D findScaledXY (Mark unscaled) {
return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude());
}
public Point2D findScaledXY (double unscaledLat, double unscaledLon) {
double distanceFromReference;
double angleFromReference;
int xAxisLocation = (int) referencePointX;
int yAxisLocation = (int) referencePointY;
angleFromReference = Mark.calculateHeadingRad(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon);
distanceFromReference = Mark.calculateDistance(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
} else if (angleFromReference >= 0) {
angleFromReference = angleFromReference - Math.PI / 2;
xAxisLocation += (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
yAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
angleFromReference = Math.abs(angleFromReference);
xAxisLocation -= (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
} else {
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
xAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
yAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
}
if(horizontalInversion) {
xAxisLocation = CANVAS_WIDTH - BUFFER_SIZE - (xAxisLocation - BUFFER_SIZE);
}
return new Point2D(xAxisLocation, yAxisLocation);
}
/**
* Find the number of meters per pixel.
*/
private void findMetersPerPixel () {
Point2D p1, p2;
Mark m1, m2;
double theta, distance, dx, dy, dHorizontal, dVertical;
m1 = new SingleMark("m1", maxLatPoint.getLatitude(), minLonPoint.getLongitude(), 1, 0);
m2 = new SingleMark("m2", minLatPoint.getLatitude(), maxLonPoint.getLongitude(), 2, 0);
p1 = findScaledXY(m1);
p2 = findScaledXY(m2);
theta = Mark.calculateHeadingRad(m1, m2);
distance = Mark.calculateDistance(m1, m2);
dHorizontal = Math.abs(Math.sin(theta) * distance);
dVertical = Math.abs(Math.cos(theta) * distance);
dx = Math.abs(p1.getX() - p2.getX());
dy = Math.abs(p1.getY() - p2.getY());
metersPerPixelX = dHorizontal / dx;
metersPerPixelY = dVertical / dy;
}
List<BoatGroup> getBoatGroups() {
return boatGroups;
}
List<MarkGroup> getMarkGroups() {
return markGroups;
}
}
@@ -1,39 +0,0 @@
package seng302.controllers;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import seng302.models.stream.StreamParser;
public class Controller implements Initializable {
@FXML
private AnchorPane contentPane;
private void setContentPane(String jfxUrl) {
try {
contentPane.getChildren().removeAll();
contentPane.getChildren().clear();
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
contentPane.getChildren()
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
} catch (javafx.fxml.LoadException e) {
System.err.println(e.getCause());
} catch (IOException e) {
System.err.println(e);
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
setContentPane("/views/StartScreenView.fxml");
StreamParser.boatLocations.clear();
}
}
@@ -1,685 +0,0 @@
package seng302.controllers;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Point2D;
import javafx.geometry.Side;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Slider;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import javafx.util.StringConverter;
import seng302.GeometryUtils;
import seng302.controllers.annotations.Annotation;
import seng302.controllers.annotations.ImportantAnnotationController;
import seng302.controllers.annotations.ImportantAnnotationDelegate;
import seng302.controllers.annotations.ImportantAnnotationsState;
import seng302.models.*;
import seng302.models.mark.GateMark;
import seng302.models.mark.Mark;
import seng302.models.mark.MarkGroup;
import seng302.models.mark.SingleMark;
import seng302.models.stream.StreamParser;
import seng302.models.stream.XMLParser;
import java.io.IOException;
import java.util.*;
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
import java.util.stream.Collectors;
/**
* Created by ptg19 on 29/03/17.
*/
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
@FXML
private LineChart raceSparkLine;
@FXML
private NumberAxis sparklineYAxis;
@FXML
private VBox positionVbox;
@FXML
private CheckBox toggleFps;
@FXML
private Text timerLabel;
@FXML
private AnchorPane contentAnchorPane;
@FXML
private Text windArrowText, windDirectionText;
@FXML
private Slider annotationSlider;
@FXML
private Button selectAnnotationBtn;
@FXML
private ComboBox boatSelectionComboBox;
@FXML
private CanvasController includedCanvasController;
private static ArrayList<Yacht> startingBoats = new ArrayList<>();
private boolean displayFps;
private Timeline timerTimeline;
private Stage stage;
private static HashMap<Integer, Series<String, Double>> sparkLineData = new HashMap<>();
private static ArrayList<Yacht> racingBoats = new ArrayList<>();
private ImportantAnnotationsState importantAnnotations;
private Yacht selectedBoat;
public void initialize() {
// Load a default important annotation state
importantAnnotations = new ImportantAnnotationsState();
//Formatting the y axis of the sparkline
raceSparkLine.getYAxis().setRotate(180);
raceSparkLine.getYAxis().setTickLabelRotation(180);
raceSparkLine.getYAxis().setTranslateX(-5);
raceSparkLine.getYAxis().setAutoRanging(false);
sparklineYAxis.setTickMarkVisible(false);
startingBoats = new ArrayList<>(StreamParser.getBoats().values());
includedCanvasController.setup(this);
includedCanvasController.initializeCanvas();
initializeUpdateTimer();
initialiseFPSCheckBox();
initialiseAnnotationSlider();
initialiseBoatSelectionComboBox();
includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
}
/**
* The important annotations have been changed, update this view
*
* @param importantAnnotationsState The current state of the selected annotations
*/
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
this.importantAnnotations = importantAnnotationsState;
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
}
/**
* Loads the "select annotations" view in a new window
*/
private void loadSelectAnnotationView() {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
Stage stage = new Stage();
// Set controller
ImportantAnnotationController controller = new ImportantAnnotationController(this,
stage);
fxmlLoader.setController(controller);
// Load FXML and set CSS
fxmlLoader
.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
stage.show();
controller.loadState(importantAnnotations);
} catch (IOException e) {
e.printStackTrace();
}
}
private void initialiseFPSCheckBox() {
displayFps = true;
toggleFps.selectedProperty().addListener(
(observable, oldValue, newValue) -> displayFps = !displayFps);
}
private void initialiseAnnotationSlider() {
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
@Override
public String toString(Double n) {
if (n == 0) {
return "None";
}
if (n == 1) {
return "Important";
}
if (n == 2) {
return "All";
}
return "All";
}
@Override
public Double fromString(String s) {
switch (s) {
case "None":
return 0d;
case "Important":
return 1d;
case "All":
return 2d;
default:
return 2d;
}
}
});
annotationSlider.valueProperty().addListener((obs, oldval, newVal) ->
setAnnotations((int) annotationSlider.getValue()));
annotationSlider.setValue(2);
}
/**
* Used to add any new boats into the race that may have started late or not have had data received yet
*/
void updateSparkLine(){
// Collect the racing boats that aren't already in the chart
ArrayList<Yacht> sparkLineCandidates = startingBoats.stream().filter(yacht -> !sparkLineData.containsKey(yacht.getSourceID())
&& yacht.getPosition() != null & yacht.getPosition() != "-").collect(Collectors.toCollection(ArrayList::new));
// Obtain the qualifying boats to set the max on the Y axis
racingBoats = startingBoats.stream().filter(yacht ->
yacht.getPosition() != null & yacht.getPosition() != "-").collect(Collectors.toCollection(ArrayList::new));
sparklineYAxis.setUpperBound(racingBoats.size() + 1);
// Create a new data series for new boats
sparkLineCandidates.stream().filter(yacht -> yacht.getPosition() != null).forEach(yacht -> {
Series<String, Double> yachtData = new Series<>();
yachtData.setName(yacht.getBoatName());
yachtData.getData().add(new XYChart.Data<>(Integer.toString(yacht.getLegNumber()), 1 + racingBoats.size() - Double.parseDouble(yacht.getPosition())));
sparkLineData.put(yacht.getSourceID(), yachtData);
});
// Lambda function to sort the series in order of leg (later legs shown more to the right)
List<XYChart.Series<String, Double>> positions = new ArrayList<>(sparkLineData.values());
Collections.sort(positions, (o1, o2) -> {
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
if (leg2 < leg1){
return 1;
} else {
return -1;
}
});
// Adds the new data series to the sparkline (and set the colour of the series)
raceSparkLine.setCreateSymbols(false);
positions.stream().filter(spark -> !raceSparkLine.getData().contains(spark)).forEach(spark -> {
raceSparkLine.getData().add(spark);
spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
});
}
/**
* Updates the yachts sparkline of the desired boat and using the new leg number
* @param yacht The yacht to be updated on the sparkline
* @param legNumber the leg number that the position will be assigned to
*/
public static void updateYachtPositionSparkline(Yacht yacht, Integer legNumber){
XYChart.Series<String, Double> positionData = sparkLineData.get(yacht.getSourceID());
positionData.getData().add(new XYChart.Data<>(Integer.toString(legNumber), 1 + racingBoats.size() - Double.parseDouble(yacht.getPosition())));
}
/**
* gets the rgb string of the boats colour to use for the chart via css
* @param boatName boat passed in to get the boats colour
* @return the colour as an rgb string
*/
private String getBoatColorAsRGB(String boatName){
Color color = Color.WHITE;
for (Yacht yacht: startingBoats){
if (Objects.equals(yacht.getBoatName(), boatName)){
color = yacht.getColour();
}
}
if (color == null){
return String.format( "#%02X%02X%02X",255,255,255);
}
return String.format( "#%02X%02X%02X",
(int)( color.getRed() * 255 ),
(int)( color.getGreen() * 255 ),
(int)( color.getBlue() * 255 ) );
}
/**
* Initalises a timer which updates elements of the RaceView such as wind direction, boat
* orderings etc.. which are dependent on the info from the stream parser constantly.
* Updates of each of these attributes are called ONCE EACH SECOND
*/
private void initializeUpdateTimer() {
timerTimeline = new Timeline();
timerTimeline.setCycleCount(Timeline.INDEFINITE);
// Run timer update every second
timerTimeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1),
event -> {
updateRaceTime();
updateWindDirection();
updateOrder();
updateBoatSelectionComboBox();
})
);
// Start the timer
timerTimeline.playFromStart();
}
/**
* Iterates over all corners until ones SeqID matches with the boats current leg number.
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
* Returns null if no next mark found.
* @param bg The BoatGroup to find the next mark of
* @return The next Mark or null if none found
*/
private Mark getNextMark(BoatGroup bg) {
Integer legNumber = bg.getBoat().getLegNumber();
List<XMLParser.RaceXMLObject.Corner> markSequence = StreamParser.getXmlObject().getRaceXML().getCompoundMarkSequence();
if (legNumber == 0) {
return null;
} else if (legNumber == markSequence.size() - 1) {
return null;
}
for (XMLParser.RaceXMLObject.Corner corner : markSequence) {
if (legNumber + 2 == corner.getSeqID()) {
Integer thisCompoundMarkID = corner.getCompoundMarkID();
for (Mark mark : StreamParser.getXmlObject().getRaceXML().getAllCompoundMarks()) {
if (mark.getCompoundMarkID() == thisCompoundMarkID) {
return mark;
}
}
}
}
return null;
}
/**
* Updates the wind direction arrow and text as from info from the StreamParser
*/
private void updateWindDirection() {
windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection()));
windArrowText.setRotate(StreamParser.getWindDirection());
}
/**
* Updates the clock for the race
*/
private void updateRaceTime() {
if (StreamParser.isRaceFinished()) {
timerLabel.setFill(Color.RED);
timerLabel.setText("Race Finished!");
} else {
timerLabel.setText(getTimeSinceStartOfRace());
}
}
/**
* Grabs the boats currently in the race as from the StreamParser and sets them to be selectable
* in the boat selection combo box
*/
private void updateBoatSelectionComboBox() {
ObservableList<Yacht> observableBoats = FXCollections
.observableArrayList(StreamParser.getBoatsPos().values());
boatSelectionComboBox.setItems(observableBoats);
}
/**
* Updates the order of the boats as from the StreamParser and sets them in the boat order
* section
*/
private void updateOrder() {
positionVbox.getChildren().clear();
positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// list of racing boat id
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
.getParticipants();
ArrayList<Integer> participantIDs = new ArrayList<>();
for (Participant p : participants) {
participantIDs.add(p.getsourceID());
}
if (StreamParser.isRaceStarted()) {
for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
if (boat.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
positionVbox.getChildren().add(textToAdd);
} else {
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
}
}
}
} else {
for (Yacht boat : StreamParser.getBoats().values()) {
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
}
}
}
}
private void updateLaylines(BoatGroup bg) {
Mark nextMark = getNextMark(bg);
Boolean isUpwind = null;
// Can only calc leg direction if there is a next mark and it is a gate mark
if (nextMark != null) {
if (nextMark instanceof GateMark) {
if (bg.isUpwindLeg(includedCanvasController, nextMark)) {
isUpwind = true;
} else {
isUpwind = false;
}
for(MarkGroup mg : includedCanvasController.getMarkGroups()) {
mg.removeLaylines();
if (mg.getMainMark().getId() == nextMark.getId()) {
SingleMark singleMark1 = ((GateMark) nextMark).getSingleMark1();
SingleMark singleMark2 = ((GateMark) nextMark).getSingleMark2();
Point2D markPoint1 = includedCanvasController.findScaledXY(singleMark1.getLatitude(), singleMark1.getLongitude());
Point2D markPoint2 = includedCanvasController.findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude());
HashMap<Double, Double> angleAndSpeed;
if (isUpwind) {
angleAndSpeed = PolarTable.getOptimalUpwindVMG(StreamParser.getWindSpeed());
} else {
angleAndSpeed = PolarTable.getOptimalDownwindVMG(StreamParser.getWindSpeed());
}
Double resultingAngle = angleAndSpeed.keySet().iterator().next();
Point2D boatCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
Point2D gateMidPoint = markPoint1.midpoint(markPoint2);
Integer lineFuncResult = GeometryUtils.lineFunction(boatCurrentPos, gateMidPoint, markPoint2);
Line rightLayline = new Line();
Line leftLayline = new Line();
if (lineFuncResult == 1) {
rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
} else if (lineFuncResult == -1) {
rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
}
leftLayline.setStrokeWidth(0.5);
leftLayline.setStroke(bg.getBoat().getColour());
rightLayline.setStrokeWidth(0.5);
rightLayline.setStroke(bg.getBoat().getColour());
bg.setLaylines(leftLayline, rightLayline);
mg.addLaylines(leftLayline, rightLayline);
}
}
}
}
}
private Point2D getPointRotation(Point2D ref, Double distance, Double angle){
Double newX = ref.getX() + (ref.getX() + distance -ref.getX())*Math.cos(angle) - (ref.getY() + distance -ref.getY())*Math.sin(angle);
Double newY = ref.getY() + (ref.getX() + distance -ref.getX())*Math.sin(angle) + (ref.getY() + distance -ref.getY())*Math.cos(angle);
return new Point2D(newX, newY);
}
public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
return line;
}
public Line makeRightLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle - layLineAngle);
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
return line;
}
/**
* Initialised the combo box with any boats currently in the race and adds the required listener
* for the combobox to take action upon selection
*/
private void initialiseBoatSelectionComboBox() {
updateBoatSelectionComboBox();
boatSelectionComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
//This listener is fired whenever the combo box changes. This means when the values are updated
//We dont want to set the selected value if the values are updated but nothing clicked (null)
if (newValue != null && newValue != selectedBoat) {
Yacht thisYacht = (Yacht) newValue;
setSelectedBoat(thisYacht);
}
});
}
/**
* Display the list of boats in the order they finished the race
*/
private void loadRaceResultView() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
try {
contentAnchorPane.getChildren().removeAll();
contentAnchorPane.getChildren().clear();
contentAnchorPane.getChildren().addAll((Pane) loader.load());
} catch (javafx.fxml.LoadException e) {
System.err.println(e.getCause());
} catch (IOException e) {
System.err.println(e);
}
}
/**
* Convert seconds to a string of the format mm:ss
*
* @param time the time in seconds
* @return a formatted string
*/
public String convertTimeToMinutesSeconds(int time) {
if (time < 0) {
return String.format("-%02d:%02d", (time * -1) / 60, (time * -1) % 60);
}
return String.format("%02d:%02d", time / 60, time % 60);
}
private String getTimeSinceStartOfRace() {
String timerString = "0:00";
if (StreamParser.getTimeSinceStart() > 0) {
String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60);
String timerSecond = Long.toString(StreamParser.getTimeSinceStart() % 60);
if (timerSecond.length() == 1) {
timerSecond = "0" + timerSecond;
}
timerString = "-" + timerMinute + ":" + timerSecond;
} else {
String timerMinute = Long.toString(-1 * StreamParser.getTimeSinceStart() / 60);
String timerSecond = Long.toString(-1 * StreamParser.getTimeSinceStart() % 60);
if (timerSecond.length() == 1) {
timerSecond = "0" + timerSecond;
}
timerString = timerMinute + ":" + timerSecond;
}
return timerString;
}
boolean isDisplayFps() {
return displayFps;
}
/**
* Display the important annotations for a specific BoatGroup
* @param bg The boat group to set the annotations for
*/
private void setBoatGroupImportantAnnotations(BoatGroup bg) {
if (importantAnnotations.getAnnotationState(Annotation.NAME)) {
bg.setTeamNameObjectVisible(true);
} else {
bg.setTeamNameObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.SPEED)) {
bg.setVelocityObjectVisible(true);
} else {
bg.setVelocityObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.TRACK)) {
bg.setLineGroupVisible(true);
} else {
bg.setLineGroupVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.WAKE)) {
bg.setWakeVisible(true);
} else {
bg.setWakeVisible(false);
}
//TODO fix boat annotations with new boatgroup
if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) {
bg.setEstTimeToNextMarkObjectVisible(true);
} else {
bg.setEstTimeToNextMarkObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) {
bg.setLegTimeObjectVisible(true);
} else {
bg.setLegTimeObjectVisible(false);
}
}
private void setAnnotations(Integer annotationLevel) {
switch (annotationLevel) {
// No Annotations
case 0:
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
bg.setTeamNameObjectVisible(false);
bg.setVelocityObjectVisible(false);
bg.setEstTimeToNextMarkObjectVisible(false);
bg.setLegTimeObjectVisible(false);
bg.setLineGroupVisible(false);
bg.setWakeVisible(false);
}
break;
// Important Annotations
case 1:
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
setBoatGroupImportantAnnotations(bg);
}
break;
// All Annotations
case 2:
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(true);
bg.setEstTimeToNextMarkObjectVisible(true);
bg.setLegTimeObjectVisible(true);
bg.setLineGroupVisible(true);
bg.setWakeVisible(true);
}
break;
}
}
/**
* Sets all the annotations of the selected boat to be visible and all others to be hidden
*
* @param yacht The yacht for which we want to view all annotations
*/
private void setSelectedBoat(Yacht yacht) {
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
//We need to iterate over all race groups to get the matching boat group belonging to this boat if we
//are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup.
if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
updateLaylines(bg);
bg.setIsSelected(true);
selectedBoat = yacht;
} else {
bg.setIsSelected(false);
}
}
}
void setStage(Stage stage) {
this.stage = stage;
}
Stage getStage() {
return stage;
}
/**
* Used for when the boat attempts to add data to the sparkline (first checks if the sparkline contains info on it)
* @param yachtId
* @return
*/
public static boolean sparkLineStatus(Integer yachtId) {
return sparkLineData.containsKey(yachtId);
}
}
@@ -1,188 +0,0 @@
package seng302.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import seng302.models.Yacht;
import seng302.models.stream.StreamParser;
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
public class StartScreenController implements Initializable {
@FXML
private GridPane gridPane;
@FXML
private Label timeTillLive;
@FXML
private Button streamButton;
@FXML
private Button switchToRaceViewButton;
@FXML
private TableView<Yacht> teamList;
@FXML
private TableColumn<Yacht, String> boatNameCol;
@FXML
private TableColumn<Yacht, String> shortNameCol;
@FXML
private TableColumn<Yacht, String> countryCol;
@FXML
private TableColumn<Yacht, String> posCol;
@FXML
private Label realTime;
private boolean switchedToRaceView = false;
private void setContentPane(String jfxUrl) {
try {
// get the main controller anchor pane (MainView.fxml)
AnchorPane contentPane = (AnchorPane) gridPane.getParent();
contentPane.getChildren().removeAll();
contentPane.getChildren().clear();
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
contentPane.getChildren()
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
} catch (javafx.fxml.LoadException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
gridPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
teamList.getStylesheets().add(getClass().getResource("/css/master.css").toString());
}
/**
* Running a timer to update the livestream status on welcome screen. Update interval is 1
* second.
*/
public void startStream() {
if (StreamParser.isStreamStatus()) {
streamButton.setVisible(false);
realTime.setVisible(true);
timeTillLive.setVisible(true);
timeTillLive.setTextFill(Color.GREEN);
timeTillLive.setText("Connecting...");
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> {
if (StreamParser.isRaceStarted()) {
if (!switchedToRaceView) {
switchToRaceView();
}
timer.cancel();
}
if (StreamParser.isRaceFinished()) {
realTime.setText(StreamParser.getCurrentTimeString());
timeTillLive.setTextFill(Color.RED);
timeTillLive.setText("Race finished! Waiting for new race...");
switchToRaceViewButton.setDisable(true);
} else if (StreamParser.getTimeSinceStart() > 0) {
realTime.setText(StreamParser.getCurrentTimeString());
updateTeamList();
timeTillLive.setTextFill(Color.RED);
switchToRaceViewButton.setDisable(false);
String timerMinute = Long
.toString(StreamParser.getTimeSinceStart() / 60);
String timerSecond = Long
.toString(StreamParser.getTimeSinceStart() % 60);
if (timerSecond.length() == 1) {
timerSecond = "0" + timerSecond;
}
String timerString = "-" + timerMinute + ":" + timerSecond;
timeTillLive.setText(timerString);
} else {
realTime.setText(StreamParser.getCurrentTimeString());
updateTeamList();
timeTillLive.setTextFill(Color.BLACK);
switchToRaceViewButton.setDisable(false);
String timerMinute = Long
.toString(-1 * StreamParser.getTimeSinceStart() / 60);
String timerSecond = Long
.toString(-1 * StreamParser.getTimeSinceStart() % 60);
if (timerSecond.length() == 1) {
timerSecond = "0" + timerSecond;
}
String timerString = timerMinute + ":" + timerSecond;
timeTillLive.setText(timerString);
}
});
}
}, 0, 1000);
} else {
timeTillLive.setText("Stream not available.");
timeTillLive.setTextFill(Color.RED);
}
}
public void switchToRaceView() {
StreamParser.boatLocations.clear();
switchedToRaceView = true;
setContentPane("/views/RaceView.fxml");
}
private void updateTeamList() {
ObservableList<Yacht> data = FXCollections.observableArrayList();
teamList.setItems(data);
boatNameCol.setCellValueFactory(
new PropertyValueFactory<>("boatName")
);
shortNameCol.setCellValueFactory(
new PropertyValueFactory<>("shortName")
);
countryCol.setCellValueFactory(
new PropertyValueFactory<>("country")
);
posCol.setCellValueFactory(
new PropertyValueFactory<>("position")
);
// check if the boat is racing
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
.getParticipants();
ArrayList<Integer> participantIDs = new ArrayList<>();
for (Participant p : participants) {
participantIDs.add(p.getsourceID());
}
// add boats to the start screen list
if (StreamParser.isRaceStarted()) { // if race is started, use StreamParser.getBoatsPos()
for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (participantIDs.contains(boat.getSourceID())) {
data.add(boat);
}
}
} else { // else use StreamParser.getBoats()
for (Yacht boat : StreamParser.getBoats().values()) {
if (participantIDs.contains(boat.getSourceID())) {
data.add(boat);
}
}
}
teamList.refresh();
}
}
@@ -0,0 +1,170 @@
package seng302.discoveryServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RoomCodeRequest;
import seng302.gameServer.messages.ServerRegistrationMessage;
import seng302.model.stream.packets.PacketType;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.util.ServerRepoStreamParser;
import seng302.discoveryServer.util.ServerTable;
import seng302.visualiser.ServerListener;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.Timer;
public class DiscoveryServer {
public static final String ANSI_GREEN = "\u001B[32m";
public static final String ANSI_YELLOW = "\u001B[33m";
public static final String ANSI_BLUE = "\u001B[34m";
public static final String ANSI_RESET = "\u001B[0m";
private static final int MAX_SERVER_TRIES = 10;
public static String DISCOVERY_SERVER = "party.sydney.srv.michaelrausch.nz";
private ServerTable serverTable;
public static final Integer PORT_NUMBER = 9969;
private ServerSocket serverSocket;
private final Logger logger = LoggerFactory.getLogger(DiscoveryServer.class);
private void displayHeader(){
String selectedColor = Arrays.asList(ANSI_BLUE, ANSI_GREEN, ANSI_YELLOW).get(new Random().nextInt(2));
System.out.println(selectedColor);
System.out.println(" .ccccc. \n" +
" .cc;'coooxkl;. \n" +
" .:c:::c:,,,,,;c;;,.'. \n" +
" .clc,',:,..:xxocc;'..c; \n" +
" .c:,';:ox:..:c,,,,,,...cd, \n" +
" .c:'.,oxxxxl::l:.,loll;..;ol. \n" +
" ;Oc..:xxxxxxxxx:.,llll,....oc \n" +
" .,;,',:loxxxxxxxxx:.,llll;.,,.'ld, \n" +
" .lo;..:xxxxxxxxxxxx:.'cllc,.:l:'cO; \n" +
" .:;...'cxxxxxxxxxxxxoc;,::,..cdl;;l' \n" +
" .cl;':,'';oxxxxxxdxxxxxx:....,cooc,cO; \n" +
" .,,,::;,lxoc:,,:lxxxxxxxxxxxo:,,;lxxl;'oNc \n" +
" .cdxo;':lxxxxxxc'';cccccoxxxxxxxxxxxxo,.;lc. " + ANSI_YELLOW + "Party-Parrots-At-Sea Discovery Server v1.0.0 (Release) " + selectedColor +"\n" +
" .loc'.'lxxxxxxxxocc;''''';ccoxxxxxxxxx:..oc \n" +
"olc,..',:cccccccccccc:;;;;;;;;:ccccccccc,.'c, \n" +
"Ol;......................................;l' ");
System.out.println(ANSI_RESET);
}
public DiscoveryServer() throws Exception {
displayHeader();
serverTable = new ServerTable();
try{
serverSocket = new ServerSocket(PORT_NUMBER);
}
catch(java.net.BindException e){
logger.error("FATAL - Could not bind socket, are you sure there isn't already an instance running?");
System.exit(1);
return;
}
logger.info("Started successfully - Now accepting connections");
try{
while (true){
Socket clientSocket = serverSocket.accept();
parseRequest(clientSocket);
clientSocket.close();
}
}
catch (Exception e){
close();
}
}
private void parseRequest(Socket clientSocket) throws Exception {
ServerRepoStreamParser parser = new ServerRepoStreamParser(clientSocket.getInputStream());
if (clientSocket.isConnected() && !clientSocket.isClosed()){
PacketType parsePacketResult = parser.parse();
switch (parsePacketResult){
case SERVER_REGISTRATION:
ServerListing listing = parser.getServerListing();
if (!serverTable.getAllServers().contains(listing)){
listing.setRoomCode(serverTable.getNextRoomCode().toString());
}
serverTable.addServer(listing);
Message serverRegMessage = new RoomCodeRequest(listing.getRoomCode());
clientSocket.getOutputStream().write(serverRegMessage.getBuffer());
break;
case ROOM_CODE_REQUEST:
String desiredRoomCode = parser.getRoomCode();
ServerListing serverListing;
if (desiredRoomCode.equals("0000")){
serverListing = getRandomFreeServer();
}
else {
serverListing = serverTable.getServerByRoomCode(desiredRoomCode);
}
Message response;
if (serverListing != null){
response = new ServerRegistrationMessage(serverListing.getServerName(), serverListing.getMapName(), serverListing.getAddress(), serverListing.getPortNumber(), 0, 0, desiredRoomCode);
}
else{
response = ServerRegistrationMessage.getEmptyRegistration();
}
clientSocket.getOutputStream().write(response.getBuffer());
break;
}
}
}
public ServerListing getRandomFreeServer() {
ServerListing serverToJoin;
List<ServerListing> servers = serverTable.getAllServers();
if (servers.size() <= 0){
return null;
}
if (servers.size() == 1){
return servers.get(0);
}
serverToJoin = servers.get(new Random().nextInt(servers.size()));
int tries = 0;
while (serverToJoin != null && serverToJoin.isMaxPlayersReached() && tries < MAX_SERVER_TRIES){
serverToJoin = servers.get(new Random().nextInt(servers.size()));
tries++;
}
if (serverToJoin != null && serverToJoin.isMaxPlayersReached()){
return null;
}
return serverToJoin;
}
public void close(){
try {
serverSocket.close();
} catch (IOException ignored) {
;
}
}
}
@@ -0,0 +1,195 @@
package seng302.discoveryServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.util.ServerRepoStreamParser;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RoomCodeRequest;
import seng302.gameServer.messages.ServerRegistrationMessage;
import seng302.model.stream.packets.PacketType;
import seng302.visualiser.controllers.ViewManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;
public class DiscoveryServerClient {
private final Integer UPDATE_INTERVAL_MS = 1000;
private static String roomCode = null;
private Timer serverListingUpdateTimer;
private Logger logger = LoggerFactory.getLogger(DiscoveryServerClient.class);
private String ip = "";
private Boolean isInInvalidState = false;
public DiscoveryServerClient() {
try {
ip = getInetIpAddr();
} catch (Exception e) {
failError();
}
}
public String getInetIp(){
return ip;
}
private void failError() {
isInInvalidState = true;
ViewManager.getInstance().showErrorSnackBar("You do not appear to be able to connect to the internet. Matchmaking will be unavailable.");
}
public boolean didFail(){
return isInInvalidState;
}
/**
* Register the server with the discovery server
* @param serverListing The listing to register
*/
public void register(ServerListing serverListing){
if (isInInvalidState) return;
if (serverListingUpdateTimer != null){
serverListingUpdateTimer.cancel();
serverListingUpdateTimer = null;
}
serverListingUpdateTimer = new Timer();
serverListingUpdateTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
sendRegistrationUpdate(serverListing);
} catch (Exception e) {
logger.debug("Could not update server listing");
}
}
}, 0, UPDATE_INTERVAL_MS);
}
/**
* Stop updating the server registration updates
*/
public void unregister(){
if (serverListingUpdateTimer != null)
serverListingUpdateTimer.cancel();
}
/**
* Gets the connection information for a server given a room code
*
* @param roomCode The room code to search for
* @return The ServerListing, or null if there was an error
* @throws Exception .
*/
public ServerListing getServerForRoomCode(String roomCode) throws Exception {
Socket socket = new Socket(DiscoveryServer.DISCOVERY_SERVER, DiscoveryServer.PORT_NUMBER);
ServerRepoStreamParser parser = new ServerRepoStreamParser(socket.getInputStream());
Message request = new RoomCodeRequest(roomCode); //roomCode);
socket.getOutputStream().write(request.getBuffer());
PacketType packetType = parser.parse();
if (packetType != PacketType.SERVER_REGISTRATION){
logger.debug("Wrong packet received in response to a room code request");
return null;
}
socket.close();
return parser.getServerListing();
}
public ServerListing getRandomServer() throws Exception {
Socket socket = new Socket(DiscoveryServer.DISCOVERY_SERVER, DiscoveryServer.PORT_NUMBER);
ServerRepoStreamParser parser = new ServerRepoStreamParser(socket.getInputStream());
Message request = new RoomCodeRequest("0000");
socket.getOutputStream().write(request.getBuffer());
PacketType packetType = parser.parse();
if (packetType != PacketType.SERVER_REGISTRATION){
logger.error("Incorrect packet type received");
return null;
}
socket.close();
ServerListing serverListing = parser.getServerListing();
if (serverListing == null || serverListing.equals(ServerRegistrationMessage.getEmptyRegistration())){
return null;
}
return serverListing;
}
/**
* Sends a registration update to the discovery server.
*
* @param serverListing The server listing to send
* @throws Exception IF there was an error sending the update
*/
private void sendRegistrationUpdate(ServerListing serverListing) throws Exception {
Socket socket = new Socket(DiscoveryServer.DISCOVERY_SERVER, DiscoveryServer.PORT_NUMBER);
ServerRepoStreamParser parser = new ServerRepoStreamParser(socket.getInputStream());
Message req = new ServerRegistrationMessage(serverListing);
socket.getOutputStream().write(req.getBuffer());
PacketType packetType = parser.parse();
if (packetType != PacketType.ROOM_CODE_REQUEST){
socket.close();
return;
}
String roomCode = parser.getRoomCode();
if (roomCode.length() != 0){
DiscoveryServerClient.roomCode = roomCode;
}
socket.close();
}
/**
* @return The last room code received by the client
*/
public static String getRoomCode(){
return roomCode;
}
public static String getInetIpAddr() throws Exception {
URL myIp = new URL("http://checkip.amazonaws.com");
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
myIp.openStream()));
String ip = in.readLine();
return ip;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
@@ -0,0 +1,50 @@
package seng302.discoveryServer.util;
import java.io.InputStream;
public class ReadableByteInputStream {
private InputStream is;
public ReadableByteInputStream(InputStream is){
this.is = is;
}
/**
* Get n bytes from the input stream
* @param n number of bytes
* @return the bytes read
* @throws Exception .
*/
public byte[] getBytes(int n) throws Exception {
byte[] bytes = new byte[n];
for (int i = 0; i < n; i++) {
bytes[i] = (byte) readByte();
}
return bytes;
}
/**
* Skip n bytes
* @param n number of bytes to skip
* @throws Exception
*/
public void skipBytes(long n) throws Exception {
for (int i = 0; i < n; i++) {
readByte();
}
}
/**
* Read the next byte from the stream
* @return The byte that was read
* @throws Exception .
*/
public int readByte() throws Exception {
int currentByte = is.read();
if (currentByte == -1) {
throw new Exception();
}
return currentByte;
}
}
@@ -0,0 +1,117 @@
package seng302.discoveryServer.util;
public class ServerListing {
public final static int SERVER_TTL_DEFAULT = 5;
private String serverName = "";
private String mapName = "";
private String address = "";
private int portNumber = 0;
private int capacity = 0;
private int players = 0;
private String roomCode = "";
private int ttl = SERVER_TTL_DEFAULT;
public ServerListing(String serverName, String mapName, String address, int portNumber, int capacity){
this.serverName = serverName;
this.mapName = mapName;
this.address = address;
this.portNumber = portNumber;
this.capacity = capacity;
}
public ServerListing setNumberOfPlayers(int players){
this.players = players;
return this;
}
public ServerListing setRoomCode(String roomCode){
this.roomCode = roomCode;
return this;
}
public void refreshTtl(){
ttl = SERVER_TTL_DEFAULT;
}
public void decrementTtl(){
ttl--;
}
public boolean hasTtlExpired(){
return ttl < 0;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!ServerListing.class.isAssignableFrom(obj.getClass())) {
return false;
}
final ServerListing other = (ServerListing) obj;
if (this.getPortNumber() != other.getPortNumber()){
return false;
}
if (!this.getMapName().equals(other.getMapName())){
return false;
}
if (!this.getServerName().equals(other.getServerName())){
return false;
}
if (this.getCapacity() != other.getCapacity()){
return false;
}
if (!this.getAddress().equals(other.getAddress())){
return false;
}
return true;
}
@Override
public int hashCode() {
return this.getServerName().hashCode() +
this.getAddress().hashCode() + this.getMapName().hashCode();
}
public String getRoomCode() {
return roomCode;
}
public int getPortNumber() {
return portNumber;
}
public String getMapName() {
return mapName;
}
public String getServerName() {
return serverName;
}
public int getCapacity() {
return capacity;
}
public String getAddress() {
return address;
}
public void setTtl(Integer ttl){
this.ttl = ttl;
}
public boolean isMaxPlayersReached() {
return players >= capacity;
}
}
@@ -0,0 +1,109 @@
package seng302.discoveryServer.util;
import seng302.gameServer.messages.Message;
import seng302.model.stream.packets.PacketType;
import java.io.InputStream;
import java.util.Arrays;
public class ServerRepoStreamParser {
private ReadableByteInputStream inputStream;
private String roomCode;
private String mapName;
private ServerListing serverListing;
public ServerRepoStreamParser(InputStream is){
inputStream = new ReadableByteInputStream(is);
}
public PacketType parse() throws Exception {
int sync1 = inputStream.readByte();
int sync2 = inputStream.readByte();
PacketType packetType = null;
if (sync1 == 0x47 && sync2 == 0x83) {
int type = inputStream.readByte();
inputStream.skipBytes(10);
long payloadLength = Message.bytesToLong(inputStream.getBytes(2));
byte[] payload = inputStream.getBytes((int) payloadLength);
inputStream.skipBytes(4);
packetType = PacketType.assignPacketType(type, payload);
switch (packetType) {
case ROOM_CODE_REQUEST:
roomCode = parseRoomCodeRequest(payload);
break;
case LOBBY_REQUEST:
mapName = parseLobbyRequest(payload);
case SERVER_REGISTRATION:
serverListing = parseServerRegistration(payload);
break;
}
}
return packetType;
}
private String parseLobbyRequest(byte[] payload) {
int mapNameLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 0 ,4));
return new String(Arrays.copyOfRange(payload, 4, 4+mapNameLength));
}
private String parseRoomCodeRequest(byte[] payload) {
int roomCodeLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 0 ,6));
return new String(Arrays.copyOfRange(payload, 6, 6+roomCodeLength));
}
public static ServerListing parseServerRegistration(byte[] payload) {
int nameLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 0, 6));
int mapNameLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 6, 12));
int addressLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 12, 18));
int roomCodeLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 18, 24));
int portNumber = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 24, 28));
int players = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 28, 32));
int capacity = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 32, 36));
int currentPos = 36;
int nextPos = currentPos + nameLength;
String serverName = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
currentPos = nextPos;
nextPos = currentPos + mapNameLength;
String mapName = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
currentPos = nextPos;
nextPos = currentPos + addressLength;
String address = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
currentPos = nextPos;
nextPos = currentPos + roomCodeLength;
String roomCode = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
ServerListing serverListing = new ServerListing(serverName, mapName, address, portNumber, capacity);
serverListing.setNumberOfPlayers(players);
serverListing.setRoomCode(roomCode);
return serverListing;
}
public String getRoomCode() {
return roomCode;
}
public String getMapName() {
return mapName;
}
public ServerListing getServerListing() {
return serverListing;
}
}
@@ -0,0 +1,97 @@
package seng302.discoveryServer.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class ServerTable {
private List<ServerListing> servers;
private int lastRoomCode = 4020;
private Logger logger = LoggerFactory.getLogger(ServerTable.class);
public ServerTable(){
servers = new ArrayList<>();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
updateServers();
}
}, 0, 1000);
}
/**
* Update the servers TTL values, and then remove expired servers
*/
private void updateServers() {
List<ServerListing> serversToRemove = new ArrayList<>();
for (ServerListing server : servers){
server.decrementTtl();
if (server.hasTtlExpired()){
logger.debug("Removed expired server - " + server.getServerName());
serversToRemove.add(server);
}
}
servers.removeAll(serversToRemove);
}
/**
* Add a server to the table
* @param server The server to add
*/
public void addServer(ServerListing server){
if (servers.contains(server)){
updateTtlForServer(server);
return;
}
logger.debug("Added new server - " + server.getServerName() + " at address: " + server.getAddress() + ":" + server.getPortNumber());
servers.add(server);
}
/**
* Update the TTL for a given server to the default TTL value
* @param server The server to update
*/
private void updateTtlForServer(ServerListing server) {
for (ServerListing serverListing : servers){
if (server.equals(serverListing)){
serverListing.refreshTtl();
}
}
}
/**
* @return All the servers in the table
*/
public List<ServerListing> getAllServers(){
return Collections.unmodifiableList(servers);
}
/**
* Get a server from the table given its room code
* @param roomCode The room code to search for
* @return The ServerListing of the found server, or null
* the server wasn't found
*/
public ServerListing getServerByRoomCode(String roomCode){
for (ServerListing serverListing : servers){
if (serverListing.getRoomCode().equals(roomCode)){
return serverListing;
}
}
return null;
}
/**
* @return The next available room code
*/
public Integer getNextRoomCode(){
lastRoomCode += 1;
return lastRoomCode;
}
}
@@ -0,0 +1,17 @@
package seng302.gameServer;
import seng302.model.Player;
public interface ClientConnectionDelegate {
/**
* A player has connected to the server
* @param serverToClientThread The player that has connected
*/
void clientConnected(ServerToClientThread serverToClientThread);
/**
* A player has disconnected from the server
* @param player The player that has disconnected
*/
void clientDisconnected(Player player);
}
@@ -0,0 +1,24 @@
package seng302.gameServer;
/**
* An enum describing the states of the game
* Created by wmu16 on 11/07/17.
*/
public enum GameStages {
LOBBYING(0),
PRE_RACE(1),
RACING(2),
FINISHED(3),
CANCELLED(4);
private long code;
GameStages(long code) {
this.code = code;
}
public long getCode(){
return code;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,90 @@
package seng302.gameServer;
import java.io.IOException;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.model.Player;
import seng302.gameServer.messages.Heartbeat;
import seng302.gameServer.messages.Message;
/**
* Send Heartbeat messages to connected player at a specified interval
* Will call .clientDisconnected on the delegate when a heartbeat message
* cannot be sent to a player
*/
public class HeartbeatThread implements Runnable {
private Logger logger = LoggerFactory.getLogger(HeartbeatThread.class);
private final int HEARTBEAT_PERIOD = 200;
private ClientConnectionDelegate delegate;
private Integer seqNum;
private Stack<Player> disconnectedPlayers;
public HeartbeatThread(ClientConnectionDelegate delegate){
this.delegate = delegate;
seqNum = 0;
disconnectedPlayers = new Stack<>();
Thread thread = new Thread(this, "HeartBeat");
thread.start();
}
/**
* A player has lost connection to the server
* The player is added to a stack so that the delegate
* can be notified
*
* @param player The player that has disconnected
*/
private void playerLostConnection(Player player){
disconnectedPlayers.push(player);
}
/**
* Sends a heartbeat message to each connected player
* The delegate is notified if a player has disconnected
*/
private void sendHeartbeatToAllPlayers(){
try {
Message heartbeat = new Heartbeat(seqNum);
for (Player player : GameState.getPlayers()) {
if (!player.getSocket().isConnected()) {
playerLostConnection(player);
}
try {
player.getSocket().getOutputStream().write(heartbeat.getBuffer());
} catch (IOException e) {
playerLostConnection(player);
}
}
updateDelegate();
seqNum++;
} catch (NullPointerException ne) {
logger.debug("Socket closed between checking for connection and sending heartbeat");
}
}
/**
* Notifies the delegate about
* each disconnected player
*/
private void updateDelegate() {
while (!disconnectedPlayers.empty()){
delegate.clientDisconnected(disconnectedPlayers.pop());
}
}
public void run(){
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
sendHeartbeatToAllPlayers();
}
}, 0, HEARTBEAT_PERIOD);
}
}
@@ -0,0 +1,355 @@
package seng302.gameServer;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.Message;
import seng302.model.GeoPoint;
import seng302.model.Player;
import seng302.model.PolarTable;
import seng302.model.ServerYacht;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.GeoUtility;
/**
* A class describing the overall server, which creates and collects server threads for each client
* Created by wmu16 on 13/07/17.
*/
public class MainServerThread implements Runnable, ClientConnectionDelegate {
private static final int PORT = 4942;
private static int selectedPort = PORT;
private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
private boolean terminated;
private boolean hasStarted = false;
private ServerSocket serverSocket = null;
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
private RaceXMLData raceXMLData;
private RegattaXMLData regattaXMLData;
public MainServerThread() {
new GameState();
try {
serverSocket = new ServerSocket(0);
selectedPort = serverSocket.getLocalPort();
} catch (IOException e) {
logger.trace("IO error in server thread handler upon trying to make new server socket",
0);
}
terminated = false;
Thread thread = new Thread(this, "MainServer");
thread.start();
}
private void startAdvertisingServer() {
Integer capacity = GameState.getCapacity();
Integer numPlayers = GameState.getNumberOfPlayers();
Integer spacesLeft = capacity - numPlayers;
// No spaces left on server
if (spacesLeft < 1) {
return;
}
// Start advertising server
try {
ServerAdvertiser.getInstance()
.setMapName(regattaXMLData.getCourseName())
.setCapacity(capacity)
.setNumberOfPlayers(numPlayers - 1)
.registerGame(selectedPort, regattaXMLData.getRegattaName());
} catch (IOException e) {
logger.warn("Could not register server");
}
}
private void startServer() {
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
GameState.setRace(raceXMLData);
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
startAdvertisingServer();
GameState.addMessageEventListener(this::broadcastMessage);
sendSetupMessages();
}
public void run() {
new HeartbeatThread(this);
new ServerListenThread(serverSocket, this);
hasStarted = true;
//You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
while (!terminated) {
if (GameState.getPlayerHasLeftFlag()) {
for (ServerToClientThread stc : serverToClientThreads) {
if (!stc.isSocketOpen()) {
GameState.getYachts().remove(stc.getSourceId());
sendSetupMessages();
try {
stc.getSocket().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
GameState.setPlayerHasLeftFlag(false);
}
try {
Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND);
} catch (InterruptedException e) {
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
}
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
.getCustomizationFlag()) {
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
sendSetupMessages();
GameState.resetCustomizationFlag();
}
if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
sendBoatLocations();
}
//RACING
if (GameState.getCurrentStage() == GameStages.RACING) {
sendBoatLocations();
}
//FINISHED
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
broadcastMessage(MessageFactory.getRaceStatusMessage());
try {
Thread.sleep(
1000); //Hackish fix to make sure all threads have sent closing RaceStatus
terminate();
} catch (InterruptedException ie) {
logger.trace("Thread interrupted while waiting to terminate clients", 1);
}
}
}
try {
synchronized (this) {
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
serverToClientThread.terminate();
}
}
serverSocket.close();
} catch (IOException e) {
System.out.println("IO error in server thread handler upon closing socket");
}
}
private void sendBoatLocations() {
for (ServerYacht serverYacht : GameState.getYachts().values()) {
broadcastMessage(MessageFactory.getBoatLocationMessage(serverYacht));
}
}
private void sendSetupMessages() {
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
broadcastMessage(MessageFactory.getRaceXML());
broadcastMessage(MessageFactory.getRegattaXML());
broadcastMessage(MessageFactory.getBoatXML());
}
private void broadcastMessage(Message message) {
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
serverToClientThread.sendMessage(message);
}
}
/**
* A client has tried to connect to the server
*
* @param serverToClientThread The player that connected
*/
@Override
public void clientConnected(ServerToClientThread serverToClientThread) {
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
if (serverToClientThreads.size() == 0) { //Sets first client as host.
serverToClientThread.setAsHost();
serverToClientThread.raceXMLProperty().addListener((obs, oldVal, race) -> {
if (race != null) {
raceXMLData = race;
}
if (regattaXMLData != null) {
startServer();
}
});
serverToClientThread.regattaXMLProperty().addListener((obs, oldVal, regatta) -> {
if (regatta != null) {
regattaXMLData = regatta;
}
if (raceXMLData != null) {
startServer();
}
});
}
serverToClientThreads.add(serverToClientThread);
try {
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
} catch (IOException e) {
logger.warn("Couldn't update advertisement");
}
while (regattaXMLData == null && raceXMLData == null) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
serverToClientThread.addConnectionListener(this::sendSetupMessages);
serverToClientThread.addDisconnectListener(this::clientDisconnected);
}
/**
* A player has left the game, remove the player from the GameState
*
* @param player The player that left
*/
@Override
public void clientDisconnected(Player player) {
logger.debug("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
GameState.removeYacht(player.getYacht().getSourceId());
GameState.removePlayer(player);
ServerToClientThread closedConnection = null;
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
if (serverToClientThread.getSocket() == player.getSocket()) {
closedConnection = serverToClientThread;
} else if (GameState.getCurrentStage() != GameStages.RACING) {
serverToClientThread.sendSetupMessages();
}
}
serverToClientThreads.remove(closedConnection);
try {
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
} catch (IOException e) {
logger.warn("Couldn't update advertisement");
}
if (closedConnection != null) {
closedConnection.terminate();
}
}
public void startGame() {
try {
ServerAdvertiser.getInstance().unregister();
} catch (IOException e) {
logger.warn("Error unregistering server");
}
initialiseBoatPositions();
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
broadcastMessage(MessageFactory.getRaceStatusMessage());
if (GameState.getCurrentStage() == GameStages.PRE_RACE
|| GameState.getCurrentStage() == GameStages.LOBBYING) {
broadcastMessage(MessageFactory.getRaceStartStatusMessage());
}
}
}, 0, 500);
}
public void terminate() {
terminated = true;
}
/**
* Initialise boats to specific spaced out geopoints behind starting line.
*/
private void initialiseBoatPositions() {
final double DISTANCE_TO_START = 75d;
final double YACHT_SEPARATION = 20d;
//Length of start line
double startLineLength = GeoUtility.getDistance(
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
);
//How many yachts can fit along the start line
int spacesAlongLine = (int) Math.round(startLineLength / YACHT_SEPARATION);
//Angle of start line
double startMarkToMarkAngle = GeoUtility.getBearing(
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
);
//angle from first mark to the start
double angleToStart = GeoUtility.getBearing(
GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint(),
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint()
);
double angleFromStart = GeoUtility.getBearing(
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
);
GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
angleToStart, DISTANCE_TO_START
);
List<ServerYacht> randomisedYachts = new ArrayList<>(GameState.getYachts().values());
Collections.shuffle(randomisedYachts);
while (randomisedYachts.size() > 0) {
int numYachtsInLine =
spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size()
: spacesAlongLine;
double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2;
GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate(
startingPoint, startMarkToMarkAngle + 180, yachtSpace
);
for (int i = 0; i < numYachtsInLine; i++) {
randomisedYachts.get(0).setHeading(angleFromStart);
randomisedYachts.get(0).setLocation(firstYachtPoint);
firstYachtPoint = GeoUtility.getGeoCoordinate(
firstYachtPoint, startMarkToMarkAngle, yachtSpace
);
randomisedYachts.remove(0);
}
startingPoint = GeoUtility.getGeoCoordinate(
startingPoint, angleToStart, DISTANCE_TO_START
);
}
}
public boolean hasStarted() {
return hasStarted;
}
public int getPortNumber() {
return selectedPort;
}
}
@@ -0,0 +1,225 @@
package seng302.gameServer;
import java.util.ArrayList;
import java.util.List;
import seng302.gameServer.messages.BoatLocationMessage;
import seng302.gameServer.messages.BoatSubMessage;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.RaceStartNotificationType;
import seng302.gameServer.messages.RaceStartStatusMessage;
import seng302.gameServer.messages.RaceStatus;
import seng302.gameServer.messages.RaceStatusMessage;
import seng302.gameServer.messages.RaceType;
import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType;
import seng302.gameServer.messages.YachtEventCodeMessage;
import seng302.gameServer.messages.YachtEventType;
import seng302.model.Player;
import seng302.model.ServerYacht;
import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.XMLGenerator;
/**
* A Class for interfacing between the data we have in the GameState to the messages we need to send
* through the MainServerThread.
*
* WARNING DO NOT USE THIS CLASS IF GAMESTATE HAS NOT BEEN INSTANTIATED. (Main Server has not started)
* // TODO: 29/08/17 wmu16 - Make GameState non static to fix this ¯\_(ツ)_/¯
* Created by wmu16 on 29/08/17.
*/
/*
Ideally this class would be created with an instance of the GameState (I tried implementing this for
a bit) but it was too difficult to properly make GameState non static without doing some proper
re working. To do later.
*/
public class MessageFactory {
private static XMLGenerator xmlGenerator = new XMLGenerator();
private static XMLMessage race;
private static XMLMessage regatta;
private static XMLMessage boats;
public static void updateXMLGenerator(RaceXMLData race, RegattaXMLData regatta) {
xmlGenerator.setRegattaTemplate(
new RegattaXMLTemplate(
regatta.getRegattaName(),
regatta.getCourseName(),
regatta.getCentralLat(),
regatta.getCentralLng()
)
);
xmlGenerator.setRaceTemplate(
new RaceXMLTemplate(
new ArrayList<>(),
new ArrayList<>(),
race.getMarkSequence(),
race.getCourseLimit(),
new ArrayList<>(race.getCompoundMarks().values()),
GameState.getCapacity(), true
)
);
String xmlStr = xmlGenerator.getRaceAsXml();
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
xmlStr = xmlGenerator.getRegattaAsXml();
MessageFactory.regatta = new XMLMessage(xmlStr, XMLMessageSubType.REGATTA, xmlStr.length());
xmlStr = xmlGenerator.getBoatsAsXml();
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
}
public static void updateBoats(List<ServerYacht> yachts) {
xmlGenerator.getRace().setBoats(yachts);
String xmlStr = xmlGenerator.getBoatsAsXml();
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
}
public static void updateTokens(List<Token> tokens) {
xmlGenerator.getRace().setTokens(tokens);
String xmlStr = xmlGenerator.getRaceAsXml();
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
}
public static RaceStartStatusMessage getRaceStartStatusMessage() {
return new RaceStartStatusMessage(
1,
GameState.getStartTime(),
1,
RaceStartNotificationType.SET_RACE_START_TIME);
}
public static RaceStatusMessage getRaceStatusMessage() {
// variables taken from GameServerThread
List<BoatSubMessage> boatSubMessages = new ArrayList<>();
RaceStatus raceStatus;
for (Player player : GameState.getPlayers()) {
ServerYacht y = player.getYacht();
BoatSubMessage m = new BoatSubMessage(y.getSourceId(), y.getBoatStatus(),
y.getLegNumber(),
0, 0, 1234L,
1234L);
boatSubMessages.add(m);
}
long timeTillStart = System.currentTimeMillis() - GameState.getStartTime();
if (GameState.getCurrentStage() == GameStages.LOBBYING) {
raceStatus = RaceStatus.PRESTART;
} else if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
raceStatus = RaceStatus.PRESTART;
if (timeTillStart > GameState.WARNING_TIME) {
raceStatus = RaceStatus.WARNING;
}
if (timeTillStart > GameState.PREPATORY_TIME) {
raceStatus = RaceStatus.PREPARATORY;
}
} else {
raceStatus = RaceStatus.STARTED;
}
return new RaceStatusMessage(1, raceStatus, GameState.getStartTime(),
GameState.getWindDirection(),
GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(),
RaceType.MATCH_RACE, 1, boatSubMessages);
}
public static BoatLocationMessage getBoatLocationMessage(ServerYacht yacht) {
return new BoatLocationMessage(
yacht.getSourceId(),
0, // TODO: 29/08/17 wmu16 - Work out what to do with seqNo. Currently not used
yacht.getLocation().getLat(),
yacht.getLocation().getLng(),
yacht.getHeading(),
yacht.getCurrentVelocity().longValue());
}
public static XMLMessage getRaceXML() {
return race;
}
public static XMLMessage getRegattaXML() {
return regatta;
}
public static XMLMessage getBoatXML() {
return boats;
}
public static YachtEventCodeMessage makeCollisionMessage(ServerYacht serverYacht) {
return new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION);
}
/**
* Constructs a message to be sent out whenever a yacht picks up a boost
*
* @param serverYacht The yacht that has picked up a power up
* @param token The token which they picked up
* @return The corresponding YachtEventCodeMessage
*/
public static YachtEventCodeMessage makePickupMessage(ServerYacht serverYacht, Token token) {
YachtEventType yachtEventType = null;
switch (token.getTokenType()) {
case BOOST:
yachtEventType = YachtEventType.TOKEN_VELOCITY;
break;
case HANDLING:
yachtEventType = YachtEventType.TOKEN_HANDLING;
break;
case WIND_WALKER:
yachtEventType = YachtEventType.TOKEN_WIND_WALKER;
break;
case BUMPER:
yachtEventType = YachtEventType.TOKEN_BUMPER;
break;
case RANDOM:
yachtEventType = YachtEventType.TOKEN_RANDOM;
break;
}
return new YachtEventCodeMessage(serverYacht.getSourceId(), yachtEventType);
}
/**
* Constructs a message representing a certain buff / debuff for a given yacht. For now this is
* just for the bumper debuff so the affected boat is aware that it has been crashed. This could
* however be extended to render affects for all boats given a certain debuff.
*
* @param yacht The yacht affected by some status
* @param token The token indicating what status they have
* @return A YachtEventCodeMessage
*/
public static YachtEventCodeMessage makeStatusEffectMessage(ServerYacht yacht,
TokenType token) {
YachtEventType yachtEventType = null;
switch (token) {
case BUMPER:
yachtEventType = YachtEventType.BUMPER_CRASH;
break;
}
return new YachtEventCodeMessage(yacht.getSourceId(), yachtEventType);
}
/**
* Constructs a message to be sent out when a given yacht powers down (From a boost of any type)
*
* @param yacht The yacht that is powering down
* @return A YachtEventCodeMessage representing this action
*/
public static YachtEventCodeMessage makePowerDownMessage(ServerYacht yacht) {
return new YachtEventCodeMessage(yacht.getSourceId(), YachtEventType.POWER_DOWN);
}
public static ChatterMessage makeChatterMessage(Integer messageType, String message) {
return new ChatterMessage(messageType, "SERVER: " + message);
}
}
@@ -0,0 +1,187 @@
package seng302.gameServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.discoveryServer.DiscoveryServerClient;
import seng302.discoveryServer.util.ServerListing;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.Hashtable;
/**
* Advertises the game server on the local network
*/
public class ServerAdvertiser {
/*
Our service name & protocol
This must be in the format _Service._Proto.Name as per http://www.ietf.org/rfc/rfc2782.txt
Where Service is unique on the network, and protocol is usually _tcp.
The pseudo-domain 'local.' must end in a full-stop. This is used to indicate that
the lookup should be performed using an IP multicast query on the local IP network.
Read this before changing any of the following values
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/NetServices/Articles/domainnames.html#//apple_ref/doc/uid/TP40002460-SW1
*/
private static String SERVICE = "_partyatsea";
private static String PROTOCOL = "_tcp";
public static String SERVICE_TYPE = SERVICE + "." + PROTOCOL + ".local.";
private static ServerAdvertiser instance = null;
private static JmDNS jmdnsInstance = null;
private ServiceInfo serviceInfo; // Note: Whenever this is changed, our service will be re-registered on the network.
private DiscoveryServerClient repositoryClient;
private Hashtable<String ,String> props;
private Logger logger = LoggerFactory.getLogger(ServerAdvertiser.class);
private ServerAdvertiser() throws IOException{
jmdnsInstance = JmDNS.create(InetAddress.getByName(getLocalHostIp()));
repositoryClient = new DiscoveryServerClient();
props = new Hashtable<>();
props.put("map", "");
props.put("spacesLeft", "0");
props.put("capacity", "0");
props.put("players", "0");
}
/**
* Get an instance of the ServerAdvertiser, create an instance if there isn't already one
* @return A ServerAdvertiser Instance
* @throws IOException If there was an exception creating the instance
*/
public static ServerAdvertiser getInstance() throws IOException {
if (instance == null){
instance = new ServerAdvertiser();
}
return instance;
}
/**
* Set the map name and broadcast an update on the network
* @param mapName The new map name
* @return The current ServerAdvertiser instance
*/
public ServerAdvertiser setMapName(String mapName){
props.replace("map", mapName);
if (serviceInfo != null){
serviceInfo.setText(props);
}
return instance;
}
/**
* Set the number of players on the server and broadcast an update on the network
* @param numPlayers The number of players on the server
* @return The current ServerAdvertiser instance
*/
public ServerAdvertiser setNumberOfPlayers(Integer numPlayers){
props.replace("players", numPlayers.toString());
if (serviceInfo != null){
serviceInfo.setText(props);
}
return instance;
}
/**
* Set the max capacity of the server and broadcast an update on the network
* @param capacity The maximum capacity of the server
* @return The current ServerAdvertiser instance
*/
public ServerAdvertiser setCapacity(Integer capacity){
props.replace("capacity", capacity.toString());
if (serviceInfo != null){
serviceInfo.setText(props);
}
return instance;
}
/**
* Register this service on the network
*
* Note: other parameters (map name/spaces left etc) are set after the
* service has been registered
* @param portNo The servers port number
* @param serverName The servers name
*/
public void registerGame(Integer portNo, String serverName) {
serviceInfo = ServiceInfo.create(SERVICE_TYPE, serverName, portNo, 0, 0, props);
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
try {
jmdnsInstance.registerService(serviceInfo);
} catch (IOException e) {
logger.warn("Failed to register service info");
}
}
}, 0);
ServerListing serverListing = new ServerListing(serverName, props.get("map"), new DiscoveryServerClient().getInetIp(), portNo, Integer.parseInt(props.get("capacity")));
repositoryClient.register(serverListing);
}
/**
* Unregister the service
*/
public void unregister(){
if (serviceInfo != null)
jmdnsInstance.unregisterService(serviceInfo);
repositoryClient.unregister();
}
/**
* Gets the local host ip address.
*
* @return the localhost ip address
*/
public static String getLocalHostIp() {
String ipAddress = null;
try {
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
while (e.hasMoreElements()) {
NetworkInterface ni = e.nextElement();
if (ni.isLoopback())
continue;
if(ni.isPointToPoint())
continue;
if(ni.isVirtual())
continue;
Enumeration<InetAddress> addresses = ni.getInetAddresses();
while(addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if(address instanceof Inet4Address) { // skip all ipv6
ipAddress = address.getHostAddress();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (ipAddress == null) {
System.out.println("[HOST] Cannot obtain local host ip address.");
}
return ipAddress;
}
}
@@ -0,0 +1,101 @@
package seng302.gameServer;
public class ServerDescription {
private Integer capacity;
private String address;
private Integer portNum;
private String serverName;
private String mapName;
private Integer numPlayers;
private Long lastUpdated;
private Long lastRefreshed;
private static Long EXPIRY_INTERVAL = 5000L;
public ServerDescription(String serverName, String mapName, Integer numPlayers, Integer capacity, String address, Integer portNum){
this.serverName = serverName;
this.mapName = mapName;
this.numPlayers = numPlayers;
this.address = address;
this.portNum = portNum;
this.capacity = capacity;
lastUpdated = System.currentTimeMillis();
}
public String getName() {
return serverName;
}
public String getMapName() {
return mapName;
}
public Integer portNumber() {
return portNum;
}
public String getAddress(){
return address;
}
public Integer getNumPlayers() {
return numPlayers;
}
public Integer getCapacity(){
return capacity;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!ServerDescription.class.isAssignableFrom(obj.getClass())) {
return false;
}
final ServerDescription other = (ServerDescription) obj;
if (!this.getAddress().equals(other.getAddress()) ) {
return false;
}
if (!this.portNumber().equals(other.portNumber())){
return false;
}
if (!this.getMapName().equals(other.getMapName())){
return false;
}
if (!this.getName().equals(other.getName())){
return false;
}
if (!this.getCapacity().equals(other.getCapacity())){
return false;
}
return true;
}
@Override
public int hashCode() {
return this.getName().hashCode() + this.getAddress().hashCode() +
this.portNumber().hashCode() + this.getMapName().hashCode();
}
public Boolean hasExpired(){
return System.currentTimeMillis() - lastUpdated > EXPIRY_INTERVAL;
}
public Boolean serverShouldBeRemoved() {
if (lastRefreshed == null) return false;
return System.currentTimeMillis() - lastRefreshed > EXPIRY_INTERVAL;
}
public void hasBeenRefreshed(){
lastRefreshed = System.currentTimeMillis();
}
}
@@ -0,0 +1,45 @@
package seng302.gameServer;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* A class for a thread to listen to connections
* Created by wmu16 on 11/07/17.
*/
public class ServerListenThread implements Runnable {
private ServerSocket serverSocket;
private ClientConnectionDelegate delegate;
public ServerListenThread(ServerSocket serverSocket, ClientConnectionDelegate delegate){
this.serverSocket = serverSocket;
this.delegate = delegate;
Thread thread = new Thread(this, "ServerListen");
thread.start();
}
/**
* Listens for a connection and upon finding one, creates a Player object and adds it to the universal GameState
*/
private void acceptConnection() {
try {
Socket thisClient = serverSocket.accept();
if (thisClient != null && GameState.getCurrentStage().equals(GameStages.LOBBYING)) {
ServerToClientThread thisConnection = new ServerToClientThread(thisClient);
delegate.clientConnected(thisConnection);
} else {
thisClient.close();
}
} catch (IOException e) {
e.getMessage();
}
}
public void run(){
while (serverSocket != null && !serverSocket.isClosed()){
acceptConnection();
}
}
}
@@ -0,0 +1,46 @@
package seng302.gameServer;
import java.util.Arrays;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.ClientType;
import seng302.gameServer.messages.CustomizeRequestType;
import seng302.gameServer.messages.Message;
import seng302.model.stream.packets.StreamPacket;
public class ServerPacketParser {
public static BoatAction extractBoatAction(StreamPacket packet) {
byte[] payload = packet.getPayload();
int messageVersionNo = payload[0];
long actionTypeValue = Message.bytesToLong(Arrays.copyOfRange(payload, 0, 1));
return BoatAction.getType((int) actionTypeValue);
}
public static ClientType extractClientType(StreamPacket packet){
byte[] payload = packet.getPayload();
long value = Message.bytesToLong(Arrays.copyOfRange(payload, 0, 1));
return ClientType.getClientType((int) value);
}
public static CustomizeRequestType extractCustomizationType(StreamPacket packet) {
byte[] payload = packet.getPayload();
long type = Message.bytesToLong(Arrays.copyOfRange(payload, 4, 5));
return CustomizeRequestType.getRequestType((int) type);
}
public static ChatterMessage extractChatterText(byte[] payload) {
return new ChatterMessage(
payload[1], new String(Arrays.copyOfRange(payload, 3, payload.length))
);
}
public static ChatterMessage extractChatterText(StreamPacket packet) {
byte[] payload = packet.getPayload();
return new ChatterMessage(
payload[1], new String(Arrays.copyOfRange(payload, 3, payload.length))
);
}
}
@@ -0,0 +1,334 @@
package seng302.gameServer;
import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.*;
import org.w3c.dom.Document;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.ClientType;
import seng302.gameServer.messages.CustomizeRequestType;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RegistrationResponseMessage;
import seng302.gameServer.messages.RegistrationResponseStatus;
import seng302.model.Player;
import seng302.model.ServerYacht;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.StreamParser;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
/**
* A class describing a single connection to a Client for the purposes of sending and receiving on
* its own thread. All server threads created and owned by the server thread handler which can
* trigger client updates on its threads Created by wmu16 on 13/07/17.
*/
public class ServerToClientThread implements Runnable {
/**
* Called to notify listeners when this thread receives a connection correctly.
*/
@FunctionalInterface
interface ConnectionListener {
void notifyConnection ();
}
// TODO: 17/08/17 this is only temporary disconnects should be handled consistently
@FunctionalInterface
interface DisconnectListener {
void notifyDisconnect (Player player);
}
private Logger logger = LoggerFactory.getLogger(ServerToClientThread.class);
private Thread thread;
private InputStream is;
private OutputStream os;
private Socket socket;
private ByteArrayOutputStream crcBuffer;
private Integer seqNo;
private Integer sourceId;
private ClientType clientType;
private Boolean isRegistered = false;
private Boolean isHost = false;
private XMLGenerator xmlGenerator;
private List<ConnectionListener> connectionListeners = new ArrayList<>();
private DisconnectListener disconnectListener;
private Player player;
private SimpleObjectProperty<RaceXMLData> raceXMLProperty = new SimpleObjectProperty<>();
private SimpleObjectProperty<RegattaXMLData> regattaXMLProperty = new SimpleObjectProperty<>();
public ServerToClientThread(Socket socket) {
this.socket = socket;
seqNo = 0;
try{
is = socket.getInputStream();
os = socket.getOutputStream();
} catch (IOException e) {
return;
}
thread = new Thread(this, "ServerToClient");
thread.start();
}
public Integer getSourceId() {
return sourceId;
}
private void setUpPlayer(){
String shortName = "P" + sourceId;
String longName = "Player " + sourceId;
ServerYacht yacht = new ServerYacht(
BoatMeshType.DINGHY, sourceId, sourceId.toString(), shortName, longName, "NZ");
player = new Player(socket, yacht);
GameState.addYacht(sourceId, yacht);
GameState.addPlayer(player);
}
private void completeRegistration(ClientType clientType) throws IOException {
// Fail if not a player
if (!clientType.equals(ClientType.PLAYER)){
RegistrationResponseMessage responseMessage = new RegistrationResponseMessage(0, RegistrationResponseStatus.FAILURE_GENERAL);
os.write(responseMessage.getBuffer());
return;
}
if (GameState.getPlayers().size() >= GameState.getCapacity()){
RegistrationResponseMessage responseMessage = new RegistrationResponseMessage(0, RegistrationResponseStatus.FAILURE_FULL);
os.write(responseMessage.getBuffer());
return;
}
Integer sourceId = GameState.getUniquePlayerID();
RegistrationResponseMessage responseMessage = new RegistrationResponseMessage(sourceId, RegistrationResponseStatus.SUCCESS_PLAYING);
this.clientType = clientType;
this.sourceId = sourceId;
isRegistered = true;
os.write(responseMessage.getBuffer());
setUpPlayer();
for (ConnectionListener listener : connectionListeners) {
listener.notifyConnection();
}
}
public void run() {
int sync1;
int sync2;
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
while (socket.isConnected() && !socket.isClosed()) {
try {
crcBuffer = new ByteArrayOutputStream();
sync1 = readByte();
sync2 = readByte();
//checking if it is the start of the packet
if (sync1 == 0x47 && sync2 == 0x83) {
int type = readByte();
//No. of milliseconds since Jan 1st 1970
long timeStamp = Message.bytesToLong(getBytes(6));
skipBytes(4);
long payloadLength = Message.bytesToLong(getBytes(2));
byte[] payload = getBytes((int) payloadLength);
Checksum checksum = new CRC32();
checksum.update(crcBuffer.toByteArray(), 0, crcBuffer.size());
long computedCrc = checksum.getValue();
long packetCrc = Message.bytesToLong(getBytes(4));
if (computedCrc == packetCrc) {
StreamPacket packet = new StreamPacket(type, payloadLength, timeStamp, payload);
switch (PacketType.assignPacketType(type, payload)) {
case BOAT_ACTION:
BoatAction actionType = ServerPacketParser.extractBoatAction(packet);
GameState.updateBoat(sourceId, actionType);
break;
case RACE_REGISTRATION_REQUEST:
ClientType requestedType = ServerPacketParser
.extractClientType(packet);
completeRegistration(requestedType);
break;
case CHATTER_TEXT:
ChatterMessage chatterMessage = ServerPacketParser
.extractChatterText(packet);
GameState.processChatter(chatterMessage, isHost);
break;
case RACE_CUSTOMIZATION_REQUEST:
Long sourceID = Message.bytesToLong(
Arrays.copyOfRange(payload, 0, 3)
);
CustomizeRequestType requestType = ServerPacketParser
.extractCustomizationType(packet);
GameState.customizePlayer(sourceID, requestType,
Arrays.copyOfRange(payload, 6, payload.length)
);
GameState.setCustomizationFlag();
// TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes.
break;
case RACE_XML:
Document document = StreamParser.extractXmlMessage(packet);
raceXMLProperty.set(
XMLParser.parseRace(document)
);
GameState.setMaxPlayers(XMLParser.getMaxPlayers(document));
GameState.setTokensEnabled(XMLParser.tokensEnabled(document));
break;
case REGATTA_XML:
regattaXMLProperty.set(
XMLParser.parseRegatta(
StreamParser.extractXmlMessage(packet)
)
);
break;
}
} else {
logger.warn("Packet has been dropped", 1);
}
}
} catch (Exception e) {
closeSocket();
GameState.setPlayerHasLeftFlag(true);
return;
}
}
GameState.setPlayerHasLeftFlag(true);
logger.warn("Closed serverToClientThread" + thread, 1);
}
public void sendSetupMessages() {
sendMessage(MessageFactory.getRegattaXML());
sendMessage(MessageFactory.getBoatXML());
sendMessage(MessageFactory.getRaceXML());
}
private void closeSocket() {
try {
socket.close();
} catch (IOException e) {
System.out.println("IO error in server thread upon trying to close socket");
}
}
public Boolean isSocketOpen() {
return !socket.isClosed();
}
private int readByte() throws Exception {
int currentByte = -1;
try {
currentByte = is.read();
crcBuffer.write(currentByte);
} catch (SocketException se) {
disconnectListener.notifyDisconnect(this.player);
} catch (IOException e) {
disconnectListener.notifyDisconnect(this.player);
logger.warn("Socket read failed", 1);
}
if (currentByte == -1) {
throw new Exception();
}
return currentByte;
}
private byte[] getBytes(int n) throws Exception {
byte[] bytes = new byte[n];
for (int i = 0; i < n; i++) {
bytes[i] = (byte) readByte();
}
return bytes;
}
private void skipBytes(long n) throws Exception {
for (int i = 0; i < n; i++) {
readByte();
}
}
public void sendMessage(Message message) {
try {
os.write(message.getBuffer());
} catch (SocketException e) {
logger.warn("Player " + sourceId + " side socket disconnected", 1);
} catch (IOException e) {
logger.warn("Message send failed", 1);
}
}
private int getSeqNo() {
seqNo++;
return seqNo;
}
public Thread getThread() {
return thread;
}
public Socket getSocket() {
return socket;
}
public void addConnectionListener(ConnectionListener listener) {
connectionListeners.add(listener);
}
public void removeConnectionListener(ConnectionListener listener) {
connectionListeners.remove(listener);
}
public void terminate () {
try {
socket.close();
} catch (IOException ioe) {
logger.warn("IOException attempting to terminate serverToClientThread " + this.thread);
}
}
public void addDisconnectListener(DisconnectListener disconnectListener) {
this.disconnectListener = disconnectListener;
}
public void setAsHost() {
isHost = true;
}
public SimpleObjectProperty<RaceXMLData> raceXMLProperty() {
return raceXMLProperty;
}
public SimpleObjectProperty<RegattaXMLData> regattaXMLProperty() {
return regattaXMLProperty;
}
}
@@ -0,0 +1,41 @@
package seng302.gameServer.messages;
import java.util.HashMap;
import java.util.Map;
/**
* Created by kre39 on 12/07/17.
*/
public enum BoatAction {
VMG(1),
SAILS_IN(2),
SAILS_OUT(3),
TACK_GYBE(4),
UPWIND(5),
DOWNWIND(6),
MAINTAIN_HEADING(7),
CONTINUOUSLY_TURNING(8),
DEFAULT_TURNING(9);
private final int type;
private static final Map<Integer, BoatAction> intToTypeMap = new HashMap<>();
static {
for (BoatAction type : BoatAction.values()) {
intToTypeMap.put(type.getValue(), type);
}
}
BoatAction(int type){
this.type = type;
}
public static BoatAction getType(int value) {
return intToTypeMap.get(value);
}
public int getValue() {
return this.type;
}
}
@@ -0,0 +1,29 @@
package seng302.gameServer.messages;
/**
* Created by kre39 on 12/07/17.
*/
public class BoatActionMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
private final int MESSAGE_SIZE = 5;
private BoatAction actionType;
public BoatActionMessage(BoatAction actionType, int sourceId) {
this.actionType = actionType;
setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id
allocateBuffer();
writeHeaderToBuffer();
// Write message fields
putInt(actionType.getValue(), 1);
putInt(sourceId, 4);
writeCRC();
rewind();
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
}
@@ -1,9 +1,7 @@
package seng302.server.messages;
import java.io.IOException;
import java.nio.channels.SocketChannel;
package seng302.gameServer.messages;
public class BoatLocationMessage extends Message {
private final int MESSAGE_SIZE = 56;
private long messageVersionNumber;
@@ -31,6 +29,7 @@ public class BoatLocationMessage extends Message {
/**
* Describes the location, altitude and sensor data from the boat.
*
* @param sourceId ID of the boat
* @param sequenceNum Sequence number of the message
* @param latitude The boats latitude
@@ -38,8 +37,8 @@ public class BoatLocationMessage extends Message {
* @param heading The boats heading
* @param boatSpeed The boats speed
*/
public BoatLocationMessage(int sourceId, int sequenceNum, double latitude, double longitude, double heading, long boatSpeed){
boatSpeed /= 10;
public BoatLocationMessage(int sourceId, int sequenceNum, double latitude, double longitude,
double heading, long boatSpeed) {
messageVersionNumber = 1;
time = System.currentTimeMillis();
this.sourceId = sourceId;
@@ -53,7 +52,7 @@ public class BoatLocationMessage extends Message {
this.roll = 0;
this.boatSpeed = boatSpeed;
this.COG = 2;
this.SOG = boatSpeed ;
this.SOG = boatSpeed;
this.apparentWindSpeed = 0;
this.apparentWindAngle = 0;
this.trueWindSpeed = 0;
@@ -64,74 +63,10 @@ public class BoatLocationMessage extends Message {
this.rudderAngle = 0;
setHeader(new Header(MessageType.BOAT_LOCATION, 1, (short) getSize()));
}
/**
* Convert binary latitude or longitude to floating point number
* @param binaryPackedLatLon Binary packed lat OR lon
* @return Floating point lat/lon
*/
public static double binaryPackedToLatLon(long binaryPackedLatLon){
return (double)binaryPackedLatLon * 180.0 / 2147483648.0;
}
/**
* Convert binary packed heading to floating point number
* @param binaryPackedHeading Binary packed heading
* @return heading as a decimal
*/
public static double binaryPackedHeadingToDouble(long binaryPackedHeading){
return (double)binaryPackedHeading * 360.0 / 65536.0;
}
/**
* Convert binary packed wind angle to floating point number
* @param binaryPackedWindAngle Binary packed wind angle
* @return wind angle as a decimal
*/
public static double binaryPackedWindAngleToDouble(long binaryPackedWindAngle){
return (double)binaryPackedWindAngle*180.0/32768.0;
}
/**
* Convert a latitude or longitude to a binary packed long
* @param latLon A floating point latitude/longitude
* @return A binary packed lat/lon
*/
public static long latLonToBinaryPackedLong(double latLon){
return (long)((536870912 * latLon) / 45);
}
/**
* Convert a heading to a binary packed long
* @param heading A floating point heading
* @return A binary packed heading
*/
public static long headingToBinaryPackedLong(double heading){
return (long)((8192*heading)/45);
}
/**
* Convert a wind angle to a binary packed long
* @param windAngle Floating point wind angle
* @return A binary packed wind angle
*/
public static long windAngleToBinaryPackedLong(double windAngle){
return (long)((8192*windAngle)/45);
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
@Override
public void send(SocketChannel outputStream) throws IOException{
allocateBuffer();
writeHeaderToBuffer();
long headingToSend = (long)((heading/360.0) * 65535.0);
long headingToSend = (long) ((heading / 360.0) * 65535.0);
putByte((byte) messageVersionNumber);
putInt(time, 6);
@@ -158,7 +93,70 @@ public class BoatLocationMessage extends Message {
writeCRC();
rewind();
}
outputStream.write(getBuffer());
/**
* Convert binary latitude or longitude to floating point number
*
* @param binaryPackedLatLon Binary packed lat OR lon
* @return Floating point lat/lon
*/
public static double binaryPackedToLatLon(long binaryPackedLatLon) {
return (double) binaryPackedLatLon * 180.0 / 2147483648.0;
}
/**
* Convert binary packed heading to floating point number
*
* @param binaryPackedHeading Binary packed heading
* @return heading as a decimal
*/
public static double binaryPackedHeadingToDouble(long binaryPackedHeading) {
return (double) binaryPackedHeading * 360.0 / 65536.0;
}
/**
* Convert binary packed wind angle to floating point number
*
* @param binaryPackedWindAngle Binary packed wind angle
* @return wind angle as a decimal
*/
public static double binaryPackedWindAngleToDouble(long binaryPackedWindAngle) {
return (double) binaryPackedWindAngle * 180.0 / 32768.0;
}
/**
* Convert a latitude or longitude to a binary packed long
*
* @param latLon A floating point latitude/longitude
* @return A binary packed lat/lon
*/
public static long latLonToBinaryPackedLong(double latLon) {
return (long) ((536870912 * latLon) / 45);
}
/**
* Convert a heading to a binary packed long
*
* @param heading A floating point heading
* @return A binary packed heading
*/
public static long headingToBinaryPackedLong(double heading) {
return (long) ((8192 * heading) / 45);
}
/**
* Convert a wind angle to a binary packed long
*
* @param windAngle Floating point wind angle
* @return A binary packed wind angle
*/
public static long windAngleToBinaryPackedLong(double windAngle) {
return (long) ((8192 * windAngle) / 45);
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* The current status of a boat
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
import java.nio.ByteBuffer;
@@ -0,0 +1,46 @@
package seng302.gameServer.messages;
/**
* Created by kre39 on 20/07/17.
*/
public class ChatterMessage extends Message {
private final long MESSAGE_VERSION_NUMBER = 1;
private final int MESSAGE_SIZE = 3;
private int message_type;
private int message_size = 21;
private String message;
public ChatterMessage(int message_type, String message) {
byte[] byteMessage = message.getBytes();
this.message_type = message_type;
this.message_size = byteMessage.length;
this.message = message;
setHeader(new Header(MessageType.CHATTER_TEXT, 1, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
putByte((byte) MESSAGE_VERSION_NUMBER);
putInt(message_type, 1);
putInt(message_size, 1);
putBytes(byteMessage);
writeCRC();
rewind();
}
@Override
public int getSize() {
return MESSAGE_SIZE + message_size;
}
public String getMessage() {
return message;
}
public int getMessageType() {
return message_type;
}
}
@@ -0,0 +1,33 @@
package seng302.gameServer.messages;
public enum ClientType {
SPECTATOR(0x00),
PLAYER(0x01),
CONTROL_TUTORIAL(0x02),
GHOST_MODE(0x03);
private int type;
ClientType(int type){
this.type = type;
}
public int getCode(){
return type;
}
public static ClientType getClientType(int typeCode){
switch (typeCode){
case 0x00:
return SPECTATOR;
case 0x01:
return PLAYER;
case 0x02:
return CONTROL_TUTORIAL;
case 0x03:
return GHOST_MODE;
default:
return PLAYER;
}
}
}
@@ -0,0 +1,35 @@
package seng302.gameServer.messages;
// TODO: 14/08/17 ajm412: this may eventually need adjusting due to conforming to the agreed spec.
public class CustomizeRequestMessage extends Message {
private static int MESSAGE_LENGTH = 6;
//Message fields
private CustomizeRequestType customizeType;
private Integer payloadLength;
public CustomizeRequestMessage(CustomizeRequestType customizeType, double sourceID,
byte[] payload) {
payloadLength = payload.length;
setHeader(new Header(MessageType.CUSTOMIZATION_REQUEST, 1, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
putInt((int) sourceID, 4);
putInt((int) customizeType.getType(), 2);
putBytes(payload);
writeCRC();
rewind();
}
@Override
public int getSize() {
return MESSAGE_LENGTH + payloadLength; // placeholder
}
}
@@ -0,0 +1,31 @@
package seng302.gameServer.messages;
// TODO: 14/08/17 ajm412: this may eventually need adjusting due to conforming to the agreed spec.
public enum CustomizeRequestType {
NAME(0x00),
COLOR(0x01),
SHAPE(0x02);
private int type;
CustomizeRequestType(int type) {
this.type = type;
}
int getType() {
return this.type;
}
public static CustomizeRequestType getRequestType(int typeCode) {
switch (typeCode) {
case 0x00:
return NAME;
case 0x01:
return COLOR;
case 0x02:
return SHAPE;
default:
return null;
}
}
}
@@ -0,0 +1,28 @@
package seng302.gameServer.messages;
/**
* Created by ajm412 on 14/08/17.
*/
public class CustomizeResponseMessage extends Message {
private static int MESSAGE_LENGTH = 2;
public CustomizeResponseMessage(CustomizeResponseType responseType) {
setHeader(new Header(MessageType.CUSTOMIZATION_RESPONSE, 1, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
putInt(responseType.getType(), 2);
writeCRC();
rewind();
}
@Override
public int getSize() {
return MESSAGE_LENGTH; // placeholder
}
}
@@ -0,0 +1,34 @@
package seng302.gameServer.messages;
// TODO: 14/08/17 ajm412: this may eventually need adjusting due to conforming to the agreed spec.
public enum CustomizeResponseType {
SUCCESS(0x00),
FAILURE(0x01),
FAILURE_MALFORMED_DATA(0x02),
FAILURE_INCOMPATIBLE(0x03);
private int type;
CustomizeResponseType(int type) {
this.type = type;
}
int getType() {
return this.type;
}
public static CustomizeResponseType getResponseType(int typeCode) {
switch (typeCode) {
case 0x00:
return SUCCESS;
case 0x01:
return FAILURE;
case 0x02:
return FAILURE_MALFORMED_DATA;
case 0x03:
return FAILURE_INCOMPATIBLE;
default:
return null;
}
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
public enum DeviceType {
UNKNOWN(0),
@@ -1,9 +1,6 @@
package seng302.server.messages;
package seng302.gameServer.messages;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Collections;
public class Header {
// From API spec
@@ -43,10 +40,21 @@ public class Header {
buff.position(buffPos);
}
/**
* Reset the buffer
*/
public void reset(){
buffPos = 0;
buff.clear();
buff.position(buffPos);
}
/**
* @return a ByteBuffer containing the message header
*/
public ByteBuffer getByteBuffer(){
reset();
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte1).array(), syncByte1);
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte2).array(), syncByte2);
@@ -1,32 +1,13 @@
package seng302.server.messages;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
import java.util.zip.CRC32;
package seng302.gameServer.messages;
public class Heartbeat extends Message {
private final int MESSAGE_SIZE = 4;
private int seqNo;
/**
* Heartbeat from the AC35 Streaming data spec
* @param seqNo Increment every time a message is sent
*/
public Heartbeat(int seqNo){
this.seqNo = seqNo;
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
@Override
public void send(SocketChannel outputStream) throws IOException {
setHeader(new Header(MessageType.HEARTBEAT, 0x01, (short) getSize()));
allocateBuffer();
@@ -36,7 +17,11 @@ public class Heartbeat extends Message {
writeCRC();
rewind();
outputStream.write(getBuffer());
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
}
@@ -1,10 +1,4 @@
package seng302.server.messages;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
package seng302.gameServer.messages;
public class MarkRoundingMessage extends Message{
private final long MESSAGE_VERSION_NUMBER = 1;
@@ -18,13 +12,21 @@ public class MarkRoundingMessage extends Message{
private RoundingSide roundingSide;
private long markId;
/**
* This message is sent when a boat passes a mark, start line, or finish line
* The purpose of this is to record the time when yachts cross marks
* @param ackNumber ackNumber
* @param raceId raceId
* @param sourceId boatSourceId
* @param roundingBoatStatus roundingBoatStatus
* @param roundingSide roundingSide
* @param markId markId
* @param markType .
*/
public MarkRoundingMessage(int ackNumber, int raceId, int sourceId, RoundingBoatStatus roundingBoatStatus,
RoundingSide roundingSide, int markId){
this.time = System.currentTimeMillis() / 1000L;
RoundingSide roundingSide, MarkType markType, int markId) {
this.time = System.currentTimeMillis();
this.ackNumber = ackNumber;
this.raceId = raceId;
this.sourceId = sourceId;
@@ -33,15 +35,6 @@ public class MarkRoundingMessage extends Message{
this.markId = markId;
setHeader(new Header(MessageType.MARK_ROUNDING, 1, (short) getSize()));
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
@Override
public void send(SocketChannel outputStream) throws IOException {
allocateBuffer();
writeHeaderToBuffer();
@@ -52,11 +45,15 @@ public class MarkRoundingMessage extends Message{
putInt((int) sourceId, 4);
putByte((byte) boatStatus.getCode());
putByte((byte) roundingSide.getCode());
putByte((byte) markType.getCode());
putByte((byte) markId);
writeCRC();
rewind();
}
outputStream.write(getBuffer());
@Override
public int getSize() {
return MESSAGE_SIZE;
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* Types of marks boats can round
@@ -1,9 +1,7 @@
package seng302.server.messages;
package seng302.gameServer.messages;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.zip.CRC32;
@@ -33,11 +31,6 @@ public abstract class Message {
*/
public abstract int getSize();
/**
* Send the message as through the outputStream
*/
public abstract void send(SocketChannel outputStream) throws IOException;
/**
* Allocate byte buffer to correct size
*/
@@ -45,6 +38,7 @@ public abstract class Message {
buffer = ByteBuffer.allocate(Header.getSize() + getSize() + CRC_SIZE);
buffer.order(ByteOrder.LITTLE_ENDIAN);
bufferPosition = 0;
buffer.position(bufferPosition);
}
/**
@@ -161,10 +155,16 @@ public abstract class Message {
}
/**
* @return The current buffer
* @return The current buffer as a byte array
*/
public ByteBuffer getBuffer(){
return buffer;
public byte[] getBuffer(){
byte[] bytes = buffer.array();
// buffer.reset();
// buffer.clear();
// buffer = null;
return bytes;
}
/**
@@ -178,7 +178,7 @@ public abstract class Message {
* Convert an integer to an array of bytes
* @param val The value to add
* @param len The width of the integer in the buffer
* @return
* @return A byte array to be sent
*/
public static byte[] intToByteArray(long val, int len){
int index = 0;
@@ -193,6 +193,26 @@ public abstract class Message {
return data;
}
/**
* takes an array of up to 7 bytes in little endian format and
* returns a positive long constructed from the input bytes
*
* @param bytes the bytes to be converted to long
* @return a positive long if there is less than 8 bytes -1 otherwise
*/
public static long bytesToLong(byte[] bytes){
long partialLong = 0;
int index = 0;
for (byte b: bytes){
if (index > 6){
return -1;
}
partialLong = partialLong | (b & 0xFFL) << (index * 8);
index++;
}
return partialLong;
}
/**
* Reverse an array of bytes
* @param data The byte[] to reverse
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* Enum containing the types of messages
@@ -16,7 +16,16 @@ public enum MessageType {
BOAT_LOCATION(37),
MARK_ROUNDING(38),
COURSE_WIND(44),
AVERAGE_WIND(47);
AVERAGE_WIND(47),
BOAT_ACTION(100),
REGISTRATION_REQUEST(101),
REGISTRATION_RESPONSE(102),
CUSTOMIZATION_REQUEST(103),
CUSTOMIZATION_RESPONSE(104),
REPO_REGISTRATION_REQUEST(201),
ROOM_CODE_REQUEST(202),
LOBBY_REQUEST(203);
private int code;
@@ -31,4 +40,6 @@ public enum MessageType {
int getCode(){
return this.code;
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* The types of race start status messages
@@ -1,10 +1,4 @@
package seng302.server.messages;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
package seng302.gameServer.messages;
public class RaceStartStatusMessage extends Message {
private final int MESSAGE_SIZE = 20;
@@ -32,15 +26,6 @@ public class RaceStartStatusMessage extends Message {
this.raceId = raceId;
setHeader(new Header(MessageType.RACE_START_STATUS, 1, (short) getSize()));
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
@Override
public void send(SocketChannel outputStream) throws IOException {
allocateBuffer();
writeHeaderToBuffer();
@@ -53,7 +38,11 @@ public class RaceStartStatusMessage extends Message {
writeCRC();
rewind();
outputStream.write(getBuffer());
}
@Override
public int getSize() {
return MESSAGE_SIZE;
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* The current status of the race
@@ -1,7 +1,5 @@
package seng302.server.messages;
package seng302.gameServer.messages;
import java.io.IOException;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.zip.CRC32;
@@ -9,12 +7,14 @@ public class RaceStatusMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.RACE_STATUS;
private final int MESSAGE_VERSION = 2; //Always set to 1
private final int MESSAGE_BASE_SIZE = 24;
private final double windDirFactor = 0x4000 / 90;
private long currentTime;
private long raceId;
private RaceStatus raceStatus;
private long expectedStartTime;
private WindDirection raceWindDirection;
private double raceWindDirection;
private long windSpeed;
private long numBoatsInRace;
private RaceType raceType;
@@ -33,13 +33,13 @@ public class RaceStatusMessage extends Message{
* @param sourceId The source of this message
* @param boats A list of boat status sub messages
*/
public RaceStatusMessage(long raceId, RaceStatus raceStatus, long expectedStartTime, WindDirection raceWindDirection,
public RaceStatusMessage(long raceId, RaceStatus raceStatus, long expectedStartTime, double raceWindDirection,
long windSpeed, long numBoatsInRace, RaceType raceType, long sourceId, List<BoatSubMessage> boats){
currentTime = System.currentTimeMillis();
this.raceId = raceId;
this.raceStatus = raceStatus;
this.expectedStartTime = expectedStartTime;
this.raceWindDirection = raceWindDirection;
this.raceWindDirection = raceWindDirection * windDirFactor+100.0;
this.windSpeed = windSpeed;
this.numBoatsInRace = numBoatsInRace;
this.raceType = raceType;
@@ -47,22 +47,6 @@ public class RaceStatusMessage extends Message{
crc = new CRC32();
setHeader(new Header(MESSAGE_TYPE, (int) sourceId, (short) getSize()));
}
/**
* @return the size of this message in bytes
*/
@Override
public int getSize() {
return MESSAGE_BASE_SIZE + (20 * ((int) numBoatsInRace));
}
/**
* Send this message as a stream of bytes
* @param outputStream The output stream to send the message
*/
@Override
public void send(SocketChannel outputStream) throws IOException {
allocateBuffer();
writeHeaderToBuffer();
@@ -71,7 +55,7 @@ public class RaceStatusMessage extends Message{
putInt((int) raceId, 4);
putByte((byte) raceStatus.getCode());
putInt(expectedStartTime, 6);
putInt((int) raceWindDirection.getCode(), 2);
putInt((int) this.raceWindDirection, 2);
putInt((int) windSpeed, 2);
putByte((byte) numBoatsInRace);
putByte((byte) raceType.getCode());
@@ -82,7 +66,14 @@ public class RaceStatusMessage extends Message{
writeCRC();
rewind();
outputStream.write(getBuffer());
}
/**
* @return the size of this message in bytes
*/
@Override
public int getSize() {
return MESSAGE_BASE_SIZE + (20 * ((int) numBoatsInRace));
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* Enum containing the types of races
@@ -0,0 +1,22 @@
package seng302.gameServer.messages;
public class RegistrationRequestMessage extends Message {
private static int MESSAGE_LENGTH = 2;
public RegistrationRequestMessage(ClientType type, int clientID){
setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
putInt(type.getCode(), 2);
writeCRC();
}
@Override
public int getSize() {
return MESSAGE_LENGTH;
}
}
@@ -0,0 +1,20 @@
package seng302.gameServer.messages;
public class RegistrationResponseMessage extends Message{
public RegistrationResponseMessage(int clientSourceID, RegistrationResponseStatus status){
setHeader(new Header(MessageType.REGISTRATION_RESPONSE, 1, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
putInt(clientSourceID, 4);
putInt(status.getCode(), 1);
writeCRC();
}
@Override
public int getSize() {
return 5;
}
}
@@ -0,0 +1,44 @@
package seng302.gameServer.messages;
public enum RegistrationResponseStatus {
SUCCESS_SPECTATING(0x00),
SUCCESS_PLAYING(0x01),
SUCCESS_TUTORIAL(0x02),
SUCCESS_GHOSTING(0x03),
FAILURE_GENERAL(0x10),
FAILURE_FULL(0x11);
private int code;
RegistrationResponseStatus(int code){
this.code = code;
}
/**
* Get the message code (From the API Spec)
* @return the message code
*/
int getCode(){
return this.code;
}
public static RegistrationResponseStatus getResponseStatus(int typeCode){
switch (typeCode){
case 0x00:
return SUCCESS_SPECTATING;
case 0x01:
return SUCCESS_PLAYING;
case 0x02:
return SUCCESS_TUTORIAL;
case 0x03:
return SUCCESS_GHOSTING;
case 0x10:
return FAILURE_GENERAL;
case 0x11:
return FAILURE_FULL;
default:
return FAILURE_GENERAL;
}
}
}
@@ -0,0 +1,24 @@
package seng302.gameServer.messages;
public class RoomCodeRequest extends Message{
private int size = 0;
@Override
public int getSize() {
return size;
}
public RoomCodeRequest(String roomCode){
size = roomCode.length() + 6;
setHeader(new Header(MessageType.ROOM_CODE_REQUEST, 0x01, (short)getSize()));
allocateBuffer();
writeHeaderToBuffer();
putInt(roomCode.length(), 6);
putBytes(roomCode.getBytes());
writeCRC();
rewind();
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* The status of a boat rounding a mark
@@ -0,0 +1,52 @@
package seng302.gameServer.messages;
/**
* The side the boat rounded the mark
*/
public enum RoundingSide {
UNKNOWN(0, "Unknown"),
PORT(1, "Port"),
STARBOARD(2, "Stbd"),
SP(3, "SP"),
PS(4, "PS");
private long code;
private String name;
RoundingSide(long code, String name) {
this.code = code;
this.name = name;
}
public long getCode(){
return code;
}
public String getName() {
return name;
}
public static RoundingSide getRoundingSide(String identifier) {
RoundingSide roundingSide = UNKNOWN;
switch (identifier) {
case "Unknown":
roundingSide = UNKNOWN;
break;
case "Port":
roundingSide = PORT;
break;
case "Stbd":
roundingSide = STARBOARD;
break;
case "SP":
roundingSide = SP;
break;
case "PS":
roundingSide = PS;
break;
}
return roundingSide;
}
}
@@ -0,0 +1,64 @@
package seng302.gameServer.messages;
import seng302.discoveryServer.util.ServerListing;
public class ServerRegistrationMessage extends Message {
private int size;
public ServerRegistrationMessage(ServerListing serverListing) {
String serverName = serverListing.getServerName();
String mapName = serverListing.getMapName();
String address = serverListing.getAddress();
int port = serverListing.getPortNumber();
int players = serverListing.getPortNumber();
int capacity = serverListing.getCapacity();
String roomCode = serverListing.getRoomCode();
createMessage(serverName, mapName, address, port, players, capacity, roomCode);
}
public static ServerRegistrationMessage getEmptyRegistration() {
return new ServerRegistrationMessage("","","",0,0,0,"");
}
@Override
public int getSize() {
return size;
}
public ServerRegistrationMessage(String serverName, String mapName, String address, int port, int players, int capacity, String roomCode){
createMessage(serverName, mapName, address, port, players, capacity, roomCode);
}
private void createMessage(String serverName, String mapName, String address, int port, int players, int capacity, String roomCode){
size = serverName.getBytes().length + mapName.length() + address.length() + roomCode.length() + 36;
setHeader(new Header(MessageType.REPO_REGISTRATION_REQUEST, 0x01, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
int nameLength = serverName.length();
int mapNameLength = mapName.length();
int addressLength = address.length();
int roomCodeLength = roomCode.length();
// Put fields here
putInt(nameLength, 6);
putInt(mapNameLength, 6);
putInt(addressLength, 6);
putInt(roomCodeLength, 6);
putInt(port, 4);
putInt(players, 4);
putInt(capacity, 4);
putBytes(serverName.getBytes());
putBytes(mapName.getBytes());
putBytes(address.getBytes());
putBytes(roomCode.getBytes());
writeCRC();
rewind();
}
}
@@ -1,12 +1,4 @@
package seng302.server.messages;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
import java.util.zip.CRC32;
package seng302.gameServer.messages;
public class XMLMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE;
@@ -25,6 +17,7 @@ public class XMLMessage extends Message{
* XML Message from the AC35 Streaming data spec
* @param content The XML content
* @param type The XML Message Sub Type
* @param sequenceNum sequenceNum
*/
public XMLMessage(String content, XMLMessageSubType type, long sequenceNum){
this.content = content;
@@ -35,20 +28,6 @@ public class XMLMessage extends Message{
sequence = sequenceNum;
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
}
/**
* @return The length of this message
*/
public int getSize(){
return MESSAGE_SIZE + content.length();
}
/**
* Send this message as a stream of bytes
* @param outputStream The output stream to send the message
*/
public void send(SocketChannel outputStream) throws IOException {
allocateBuffer();
writeHeaderToBuffer();
@@ -63,7 +42,12 @@ public class XMLMessage extends Message{
writeCRC();
rewind();
}
outputStream.write(getBuffer());
/**
* @return The length of this message
*/
public int getSize(){
return MESSAGE_SIZE + content.length();
}
}
@@ -1,4 +1,4 @@
package seng302.server.messages;
package seng302.gameServer.messages;
/**
* Enum containing the types of XML messages
@@ -0,0 +1,52 @@
package seng302.gameServer.messages;
/**
* Created by zyt10 on 10/08/17.
*/
public class YachtEventCodeMessage extends Message {
private final MessageType MESSAGE_TYPE = MessageType.YACHT_EVENT_CODE;
private final int MESSAGE_VERSION = 1; //Always set to 1
private final int MESSAGE_SIZE = 22;
// Message fields
private long timeStamp;
private long ack = 0x00; //Unused
private int raceId;
private int destSourceId;
private int incidentId;
private int eventId;
public YachtEventCodeMessage(Integer subjectId, YachtEventType yachtEventType) {
timeStamp = System.currentTimeMillis() / 1000L;
ack = 0;
raceId = 1;
destSourceId = subjectId; // collision boat source id
incidentId = 0;
eventId = yachtEventType.getCode();
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
// Write message fields
putUnsignedByte((byte) MESSAGE_VERSION);
putInt((int) timeStamp, 6);
putInt((int) ack, 2);
putInt((int) raceId, 4);
putInt((int) destSourceId, 4);
putInt((int) incidentId, 4);
putInt((int) eventId, 1);
writeCRC();
rewind();
}
/**
* @return The length of this message
*/
public int getSize() {
return MESSAGE_SIZE;
}
}
@@ -0,0 +1,26 @@
package seng302.gameServer.messages;
/**
* Enum for different event types for the yacht
*/
public enum YachtEventType {
COLLISION(33),
TOKEN_VELOCITY(34),
TOKEN_BUMPER(35),
TOKEN_HANDLING(36),
TOKEN_WIND_WALKER(37),
TOKEN_RANDOM(38),
POWER_DOWN(39),
BUMPER_CRASH(40);
private int code;
YachtEventType(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
@@ -0,0 +1,386 @@
package seng302.model;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Timer;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.ReadOnlyLongProperty;
import javafx.beans.property.ReadOnlyLongWrapper;
import javafx.scene.paint.Color;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.model.token.TokenType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
/**
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
* not used anymore.
*/
public class ClientYacht extends Observable {
@FunctionalInterface
public interface YachtLocationListener {
void notifyLocation(ClientYacht clientYacht, double lat, double lon, double heading,
Boolean sailsIn, double velocity);
}
@FunctionalInterface
public interface MarkRoundingListener {
void notifyRounding(ClientYacht yacht, int legNumber);
}
@FunctionalInterface
public interface ColorChangeListener {
void notifyColorChange(ClientYacht yacht);
}
//This notifies RaceViewController so it can display icon - wmu16
@FunctionalInterface
public interface PowerUpListener {
void notifyPowerUp(ClientYacht yacht, TokenType tokenType);
}
//This notifies RaceViewController so it can remove token icon - wmu16
@FunctionalInterface
public interface PowerDownListener {
void notifyPowerDown(ClientYacht yacht);
}
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
private BoatMeshType boatType;
private Integer sourceId;
private String hullID; //matches HullNum in the XML spec.
private String shortName;
private String boatName;
private String country;
private Integer position;
private TokenType powerUp;
private Long estimateTimeAtFinish;
private Boolean sailIn = true;
private Integer currentMarkSeqID = 0;
private Long markRoundTime;
private Long timeTillNext;
private Double heading;
private Integer legNumber = 0;
private GeoPoint location;
private Integer boatStatus;
private Double currentVelocity;
Timer t;
private BoatObject boatObject;
private List<YachtLocationListener> locationListeners = new ArrayList<>();
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
private List<PowerUpListener> powerUpListeners = new ArrayList<>();
private List<PowerDownListener> powerDownListeners = new ArrayList<>();
private List<ColorChangeListener> colorChangeListeners = new ArrayList<>();
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
private ReadOnlyDoubleWrapper headingProperty = new ReadOnlyDoubleWrapper();
private Color colour;
public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) {
this.boatType = boatType;
this.sourceId = sourceId;
this.hullID = hullID;
this.shortName = shortName;
this.boatName = boatName;
this.country = country;
this.location = new GeoPoint(57.670341, 11.826856);
this.heading = 120.0; //In degrees
this.headingProperty.set(this.heading);
this.currentVelocity = 0d;
this.boatStatus = 1;
this.colour = Color.rgb(0, 0, 0, 1.0);
}
/**
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
* rounding package.
*/
@Override
public void addObserver(Observer o) {
super.addObserver(o);
}
public BoatMeshType getBoatType() {
return boatType;
}
public Integer getSourceId() {
//@TODO Remove and merge with Creating Game Loop
if (sourceId == null) {
return 0;
}
return sourceId;
}
public String getHullID() {
if (hullID == null) {
return "";
}
return hullID;
}
public String getShortName() {
return shortName;
}
public String getBoatName() {
return boatName;
}
public String getCountry() {
if (country == null) {
return "";
}
return country;
}
public Integer getBoatStatus() {
return boatStatus;
}
public void setBoatStatus(Integer boatStatus) {
this.boatStatus = boatStatus;
}
public Integer getLegNumber() {
return legNumber;
}
public void setLegNumber(Integer legNumber) {
this.legNumber = legNumber;
}
public void setEstimateTimeTillNextMark(Long estimateTimeTillNextMark) {
timeTillNext = estimateTimeTillNextMark;
}
public String getEstimateTimeAtFinish() {
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
return format.format(estimateTimeAtFinish);
}
public void setEstimateTimeAtFinish(Long estimateTimeAtFinish) {
this.estimateTimeAtFinish = estimateTimeAtFinish;
}
public Integer getPlacing() {
return placingProperty.get();
}
public void setPlacing(Integer position) {
placingProperty.set(position);
}
public ReadOnlyIntegerProperty placingProperty() {
return placingProperty.getReadOnlyProperty();
}
public void updateVelocityProperty(double velocity) {
this.velocityProperty.set(velocity);
}
public void setMarkRoundingTime(Long markRoundingTime) {
this.markRoundTime = markRoundingTime;
}
public ReadOnlyDoubleProperty getVelocityProperty() {
return velocityProperty.getReadOnlyProperty();
}
public ReadOnlyLongProperty timeTillNextProperty() {
return timeTillNextProperty.getReadOnlyProperty();
}
public Long getTimeTillNext() {
return timeTillNext;
}
public Long getMarkRoundTime() {
return markRoundTime;
}
public GeoPoint getLocation() {
return location;
}
public Integer getPosition() {
return position;
}
public void setPosition(Integer position) {
this.position = position;
}
/**
* Powers down the boat and notifies the raceViewController to display
*/
public void powerDown() {
this.powerUp = null;
for (PowerDownListener listener : powerDownListeners) {
listener.notifyPowerDown(this);
}
}
/**
* powers up the boat and notifies the raceViewController to display
*
* @param tokenType The type of token that this boat is being powered up with
*/
public void setPowerUp(TokenType tokenType) {
this.powerUp = tokenType;
for (PowerUpListener listener : powerUpListeners) {
listener.notifyPowerUp(this, tokenType);
}
}
public TokenType getPowerUp() {
return powerUp;
}
public void toggleSail() {
sailIn = !sailIn;
}
//// TODO: 15/08/17 asd
/**
* Sets the current location of the boat in lat and long whilst preserving the last location
*
* @param lat Latitude
* @param lng Longitude
*/
public void setLocation(Double lat, Double lng) {
location.setLat(lat);
location.setLng(lng);
}
public Double getHeading() {
return heading;
}
public void setHeading(Double heading) {
this.heading = heading;
System.out.println(heading);
setHeadingProperty();
}
@Override
public String toString() {
return boatName;
}
public void updateTimeSinceLastMarkProperty(long timeSinceLastMark) {
this.timeSinceLastMarkProperty.set(timeSinceLastMark);
}
public ReadOnlyLongProperty timeSinceLastMarkProperty() {
return timeSinceLastMarkProperty.getReadOnlyProperty();
}
public void setTimeTillNext(Long timeTillNext) {
this.timeTillNext = timeTillNext;
}
public Color getColour() {
return colour;
}
public void setColour(Color colour) {
this.colour = colour;
for (ColorChangeListener listener : colorChangeListeners) {
listener.notifyColorChange(this);
}
}
public void updateLocation(double lat, double lng, double heading, double velocity) {
setLocation(lat, lng);
this.heading = heading;
setHeadingProperty();
this.currentVelocity = velocity;
updateVelocityProperty(velocity);
for (YachtLocationListener yll : locationListeners) {
yll.notifyLocation(this, lat, lng, heading, sailIn, velocity);
}
}
private void setHeadingProperty() {
headingProperty.set(heading);
}
public void addLocationListener(YachtLocationListener listener) {
locationListeners.add(listener);
}
public void addMarkRoundingListener(MarkRoundingListener listener) {
markRoundingListeners.add(listener);
}
public void addPowerUpListener(PowerUpListener listener) {
powerUpListeners.add(listener);
}
public void addPowerDownListener(PowerDownListener listener) {
powerDownListeners.add(listener);
}
public void addColorChangeListener(ColorChangeListener listener) {
colorChangeListeners.add(listener);
}
public void removeMarkRoundingListener(MarkRoundingListener listener) {
markRoundingListeners.remove(listener);
}
public boolean getSailIn () {
return sailIn;
}
public void roundMark(long markRoundTime, long timeSinceLastMark) {
this.markRoundTime = markRoundTime;
timeSinceLastMarkProperty.set(timeSinceLastMark);
legNumber++;
for (MarkRoundingListener listener : markRoundingListeners) {
listener.notifyRounding(this, legNumber);
}
}
public Double getCurrentVelocity() {
return currentVelocity;
}
public void setBoatObject(BoatObject newBoatObject) {
this.boatObject = newBoatObject;
}
public BoatObject getBoatObject() {
return this.boatObject;
}
public ReadOnlyDoubleWrapper getHeadingProperty() {
return headingProperty;
}
}
+14
View File
@@ -0,0 +1,14 @@
package seng302.model;
import javafx.scene.paint.Color;
/**
* Enum for generating colours.
*/
public enum Colors {
RED, PERU, GOLD, GREEN, BLUE, PURPLE, DEEPPINK, GRAY;
public static Color getColor(Integer index) {
return Color.valueOf(values()[index].toString());
}
}
@@ -0,0 +1,87 @@
package seng302.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javafx.scene.input.KeyCode;
public class GameKeyBind {
private static GameKeyBind instance;
private Map<KeyCode, KeyAction> keyToActionMap;
private Map<KeyAction, KeyCode> actionToKeyMap;
private Boolean continuouslyTurning;
private GameKeyBind() {
setToDefault();
}
public void setToDefault() {
actionToKeyMap = new HashMap<>();
keyToActionMap = new HashMap<>();
continuouslyTurning = false;
// default key bindings
ArrayList<KeyCode> keys = new ArrayList<>();
keys.add(KeyCode.Z);
keys.add(KeyCode.X);
keys.add(KeyCode.SPACE);
keys.add(KeyCode.SHIFT);
keys.add(KeyCode.ENTER);
keys.add(KeyCode.PAGE_UP);
keys.add(KeyCode.PAGE_DOWN);
keys.add(KeyCode.F1);
keys.add(KeyCode.D);
keys.add(KeyCode.A);
keys.add(KeyCode.W);
keys.add(KeyCode.S);
for (int i = 0; i < 12; i++) {
actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i));
keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1));
}
}
public static GameKeyBind getInstance() {
if (instance == null) {
instance = new GameKeyBind();
}
return instance;
}
public KeyCode getKeyCode(KeyAction keyAction) {
return instance.actionToKeyMap.get(keyAction);
}
public KeyAction getKeyAction(KeyCode keyCode) {
return instance.keyToActionMap.get(keyCode);
}
/**
* Binds a key to a key action
*
* @return true if successfully bind
*/
public boolean bindKeyToAction(KeyCode keyCode, KeyAction keyAction) {
if (instance.keyToActionMap.containsKey(keyCode)) {
// if the key has been bound to other action, return false
return false;
} else {
instance.keyToActionMap.put(keyCode, keyAction); // add key -> action
KeyCode oldKeyCode = instance.actionToKeyMap
.get(keyAction); // get old key for the action
instance.keyToActionMap.remove(oldKeyCode); // remove the old key -> action
instance.actionToKeyMap
.replace(keyAction, keyCode); // replace the old key by the newer one
return true;
}
}
public void toggleTurningMode() {
continuouslyTurning = !continuouslyTurning;
}
public Boolean isContinuouslyTurning() {
return continuouslyTurning;
}
}
@@ -1,18 +1,18 @@
package seng302.server.simulator.mark;
package seng302.model;
public class Position {
/**
* A class represent Geo location (latitude, lnggitude).
* Created by Haoming on 15/5/2017
*/
public class GeoPoint {
double lat, lng;
private double lat, lng;
public Position(double lat, double lng) {
public GeoPoint(double lat, double lng) {
this.lat = lat;
this.lng = lng;
}
public String toString() {
return String.format("Position at lat:%f lng:%f.", lat, lng);
}
public double getLat() {
return lat;
}
@@ -28,4 +28,9 @@ public class Position {
public void setLng(double lng) {
this.lng = lng;
}
@Override
public String toString() {
return "lat: " + lat + " lng: " + lng;
}
}
@@ -0,0 +1,40 @@
package seng302.model;
import java.util.HashMap;
import java.util.Map;
public enum KeyAction {
ZOOM_IN(1),
ZOOM_OUT(2),
VMG(3),
SAILS_STATE(4),
TACK_GYBE(5),
UPWIND(6),
DOWNWIND(7),
VIEW(8),
RIGHT(9),
LEFT(10),
FORWARD(11),
BACKWARD(12);
private final int type;
private static final Map<Integer, KeyAction> intToTypeMap = new HashMap<>();
static {
for (KeyAction type : KeyAction.values()) {
intToTypeMap.put(type.getValue(), type);
}
}
KeyAction(int type) {
this.type = type;
}
public static KeyAction getType(int value) {
return intToTypeMap.get(value);
}
public int getValue() {
return this.type;
}
}
+23
View File
@@ -0,0 +1,23 @@
package seng302.model;
/**
* Stores data on the border of a race
*/
public class Limit extends GeoPoint {
private Integer seqID;
public Limit(Integer seqID, Double lat, Double lng) {
super(lat, lng);
this.seqID = seqID;
}
public Integer getSeqID() {
return seqID;
}
@Override
public String toString(){
return "Limit = {seqID=" + seqID + ", lat=" + getLat() + ", lng=" + getLng() + "}";
}
}
+68
View File
@@ -0,0 +1,68 @@
package seng302.model;
import java.net.Socket;
/**
* A Class defining a player and their respective details in the game as held by the model
* Created by wmu16 on 10/07/17.
*/
public class Player {
private Socket socket;
private ServerYacht yacht;
private Integer lastMarkPassed;
public Player(Socket socket, ServerYacht yacht) {
this.socket = socket;
this.yacht = yacht;
}
public Socket getSocket() {
return socket;
}
public Integer getLastMarkPassed() {
return lastMarkPassed;
}
public void setLastMarkPassed(Integer lastMarkPassed) {
this.lastMarkPassed = lastMarkPassed;
}
public ServerYacht getYacht() {
return yacht;
}
@Override
public String toString() {
String playerAddress = null;
if (socket == null){
return "Disconnected Player";
}
playerAddress = socket.getRemoteSocketAddress().toString();
return playerAddress;
}
@Override
public boolean equals(Object obj) {
if (obj == null){
return false;
}
if (!(obj instanceof Player)){
return false;
}
return ((Player) obj).socket.equals(socket);
}
@Override
public int hashCode(){
return socket.hashCode();
}
}
@@ -1,8 +1,12 @@
package seng302.models;
package seng302.model;
import java.io.*;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* A static class for parsing and storing the polars. Will parse the whole polar table and also store the optimised
@@ -15,6 +19,7 @@ public final class PolarTable {
private static HashMap<Double, HashMap<Double, Double>> polarTable;
private static HashMap<Double, HashMap<Double, Double>> upwindOptimal;
private static HashMap<Double, HashMap<Double, Double>> downwindOptimal;
private static Double optimalAngle;
private static int upTwaIndex;
private static int dnTwaIndex;
@@ -24,18 +29,20 @@ public final class PolarTable {
* Iterates through each row of the polar table, in pairs, to extract the row into a hashmap of angle to boat speed.
* These angle boatspeed hashmaps are then added to an outer hashmap at the end of wind speed key to each row hashmap
* as a value
* @param file containing the polar csv information
* @param polarFile polarFile to be parsed
*/
public static void parsePolarFile(String file) {
public static void parsePolarFile(InputStream polarFile) {
polarTable = new HashMap<>();
upwindOptimal = new HashMap<>();
downwindOptimal = new HashMap<>();
String line;
String line = null;
String check;
Boolean isHeaderLine = true;
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
while ((line = br.readLine()) != null) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) {
while ((check = br.readLine()) != null) {
line = check;
String[] thisLine = line.split(",");
//Initial line in file
@@ -64,14 +71,38 @@ public final class PolarTable {
upwindOptimal.put(thisWindSpeed, thisUpWindPolar);
downwindOptimal.put(thisWindSpeed, thisDnWindPolar);
}
}
getMaxSpeedAngle(line);
} catch (IOException e) {
e.printStackTrace();
System.out.println("[PolarTable] IO exception");
}
}
/**
* Passes the final line of the polar table and iterates over the speeds for each
* angle, velocity pair to find the angle that produces the highest velocity
*
* @param line The last line of the polar file
*/
private static void getMaxSpeedAngle(String line) {
String[] theLastLine = line.split(",");
Double maxWindVal = Double.parseDouble(theLastLine[0]);
Double optimalAngle = Double.parseDouble(theLastLine[1]);
Double maxSpeed = Double.parseDouble(theLastLine[2]);
for (Map.Entry<Double, Double> entry : polarTable.get(maxWindVal).entrySet()) {
if (entry.getValue() > maxSpeed) {
maxSpeed = entry.getValue();
optimalAngle = entry.getKey();
}
}
PolarTable.optimalAngle = optimalAngle;
}
/**
* Parses the header line of a polar file
@@ -83,14 +114,18 @@ public final class PolarTable {
String thisItem = thisLine[i];
if (thisItem.toLowerCase().startsWith("uptwa")) {
upTwaIndex = i;
}
else if (thisItem.toLowerCase().startsWith("dntwa")) {
} else if (thisItem.toLowerCase().startsWith("dntwa")) {
dnTwaIndex = i;
}
}
}
public static Double getOptimalAngle() {
return optimalAngle;
}
/**
* @return The entire polar table
*/
@@ -122,7 +157,7 @@ public final class PolarTable {
*/
public static HashMap<Double, Double> getOptimalUpwindVMG(Double thisWindSpeed) {
Double polarWindSpeed = getClosestMatch(thisWindSpeed);
Double polarWindSpeed = getClosestWindSpeedInPolar(thisWindSpeed);
return upwindOptimal.get(polarWindSpeed);
}
@@ -134,30 +169,47 @@ public final class PolarTable {
*/
public static HashMap<Double, Double> getOptimalDownwindVMG(Double thisWindSpeed) {
Double polarWindSpeed = getClosestMatch(thisWindSpeed);
Double polarWindSpeed = getClosestWindSpeedInPolar(thisWindSpeed);
return downwindOptimal.get(polarWindSpeed);
}
private static Double getClosestMatch(Double thisWindSpeed) {
public static Double getBoatSpeed(Double thisWindSpeed, Double thisHeading) {
ArrayList<Double> windValues = new ArrayList<>(polarTable.keySet());
Double polarWindSpeed = getClosestWindSpeedInPolar(thisWindSpeed);
Double polarAngle = getClosestAngleInPolar(polarTable.get(polarWindSpeed), thisHeading);
Double lowerVal = windValues.get(0);
Double upperVal = windValues.get(1);
for(int i = 0; i < windValues.size() - 1; i++) {
lowerVal = windValues.get(i);
upperVal = windValues.get(i+1);
if (thisWindSpeed <= upperVal) {
break;
}
}
Double lowerDiff = Math.abs(lowerVal - thisWindSpeed);
Double upperDiff = Math.abs(upperVal - thisWindSpeed);
return (lowerDiff <= upperDiff) ? lowerVal : upperVal;
return polarTable.get(polarWindSpeed).get(polarAngle);
}
public static Double getClosestWindSpeedInPolar(Double thisWindSpeed) {
Double smallestDif = Double.POSITIVE_INFINITY;
Double closestWind = 0d;
for (Double polarWindSpeed : polarTable.keySet()) {
Double difference = Math.abs(polarWindSpeed - thisWindSpeed);
if (difference < smallestDif) {
smallestDif = difference;
closestWind = polarWindSpeed;
}
}
return closestWind;
}
public static Double getClosestAngleInPolar(HashMap<Double, Double> thisWindSpeedPolar, Double thisHeading) {
Double smallestDif = Double.POSITIVE_INFINITY;
Double closestAngle = 0d;
for (Double polarAngle : thisWindSpeedPolar.keySet()) {
Double difference = Math.abs(polarAngle - thisHeading);
if (difference < smallestDif) {
smallestDif = difference;
closestAngle = polarAngle;
}
}
return closestAngle;
}
}
+137
View File
@@ -0,0 +1,137 @@
package seng302.model;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TimeZone;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import seng302.model.stream.parser.RaceStartData;
import seng302.model.stream.parser.RaceStatusData;
import seng302.utilities.Sounds;
/**
* Class for storing race data that does not relate to specific vessels or marks such as time or wind.
* Calculates the state of critical race attributes when relevant data is added.
*/
public class RaceState {
@FunctionalInterface
public interface CollisionListener {
void notifyCollision(GeoPoint location);
}
// private final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
private final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
private ReadOnlyDoubleWrapper windSpeed = new ReadOnlyDoubleWrapper();
private ReadOnlyDoubleWrapper windDirection = new ReadOnlyDoubleWrapper();
private long serverSystemTime;
private long expectedStartTime;
private boolean raceRunning = false;
private boolean gunFired = false;
private boolean raceFinished = false;
long timeTillStart;
private ObservableList<ClientYacht> playerPositions;
private List<ClientYacht> collisions = new ArrayList<>();
private List<CollisionListener> collisionListeners = new ArrayList<>();
public RaceState() {
playerPositions = FXCollections.observableArrayList();
}
public void updateState (RaceStatusData data) {
this.windSpeed.set(data.getWindSpeed());
this.windDirection.set(data.getWindDirection());
this.serverSystemTime = data.getCurrentTime();
this.expectedStartTime = data.getExpectedStartTime();
this.raceRunning = data.isRaceStarted();
}
public void setTimeZone (TimeZone timeZone) {
DATE_TIME_FORMAT.setTimeZone(timeZone);
}
public void updateState (RaceStartData data) {
this.timeTillStart = data.getRaceStartTime();
}
public String getRaceTimeStr () {
long raceTime = serverSystemTime - expectedStartTime;
if (raceTime < 0) {
return "-" + DATE_TIME_FORMAT.format(-1 * (raceTime - 1000));
} else {
if (!gunFired) {
gunFired = true;
Sounds.playCapGunSound();
}
return DATE_TIME_FORMAT.format(serverSystemTime - expectedStartTime);
}
}
public long getTimeTillStart () {
return (expectedStartTime - serverSystemTime);
}
public double getWindSpeed() {
return windSpeed.doubleValue();
}
public ReadOnlyDoubleProperty windSpeedProperty() {
return windSpeed.getReadOnlyProperty();
}
public ReadOnlyDoubleProperty windDirectionProperty() {
return windDirection.getReadOnlyProperty();
}
public long getRaceTime() {
return serverSystemTime;
}
public boolean isRaceStarted () {
return raceRunning;
}
public void setRaceStarted(Boolean value) {
this.raceRunning = value;
}
public void setBoats(Collection<ClientYacht> clientYachts) {
playerPositions.setAll(clientYachts);
}
public void sortPlayers() {
playerPositions.sort((yacht1, yacht2) -> Integer.compare(yacht2.getLegNumber(),
yacht1.getLegNumber()));
}
public ObservableList<ClientYacht> getPlayerPositions() {
return playerPositions;
}
public void storeCollision(ClientYacht yacht) {
collisions.add(yacht);
for (CollisionListener collisionListener : collisionListeners) {
collisionListener.notifyCollision(yacht.getLocation());
}
}
public void addCollisionListener(CollisionListener collisionListener) {
collisionListeners.add(collisionListener);
}
public void removeCollisionListener(CollisionListener collisionListener) {
collisionListeners.remove(collisionListener);
}
public void setRaceFinished() {
raceFinished = true;
}
public Boolean getRaceFinished() {
return raceFinished;
}
}
@@ -0,0 +1,122 @@
package seng302.model;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javafx.geometry.Point2D;
import seng302.utilities.GeoUtility;
/**
* Contains information on a scaled lat lon point for use with mapping geographical elements to a 2d plane.
*/
public class ScaledPoint extends GeoPoint {
public enum ScaleDirection {
HORIZONTAL,
VERTICAL
}
private double x, y, scaleFactor;
private ScaleDirection scaleDirection;
private ScaledPoint(double lat, double lng, double x, double y, double scaleFactor, ScaleDirection direction) {
super(lat, lng);
this.x = x;
this.y = y;
this.scaleFactor = scaleFactor;
this.scaleDirection = direction;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getScaleFactor() {
return scaleFactor;
}
public ScaleDirection getScaleDirection() {
return scaleDirection;
}
public Point2D findScaledXY(GeoPoint unscaled) {
return findScaledXY(unscaled.getLat(), unscaled.getLng());
}
public Point2D findScaledXY(double unscaledLat, double unscaledLon) {
double distanceFromReference;
double angleFromReference;
double xReference = this.getX();
double yReference = this.getY();
angleFromReference = GeoUtility.getBearingRad(
this, new GeoPoint(unscaledLat, unscaledLon)
);
distanceFromReference = GeoUtility.getDistance(
this, new GeoPoint(unscaledLat, unscaledLon)
);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
} else if (angleFromReference >= 0) {
angleFromReference = angleFromReference - Math.PI / 2;
xReference += scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
angleFromReference = Math.abs(angleFromReference);
xReference -= scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
} else {
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
xReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
}
return new Point2D(xReference, yReference);
}
public static ScaledPoint makeScaledPoint(double width, double height,
List<? extends GeoPoint> points, boolean centered) {
double referencePointX, referencePointY, scaleFactor, lat, lng;
ScaleDirection scaleDirection;
points = new ArrayList<>(points);
points.sort(Comparator.comparingDouble(GeoPoint::getLat));
GeoPoint minLatPoint = points.get(0);
GeoPoint maxLatPoint = points.get(points.size() - 1);
points.sort(Comparator.comparingDouble(GeoPoint::getLng));
GeoPoint minLonPoint = points.get(0);
GeoPoint maxLonPoint = points.get(points.size() - 1);
referencePointX = centered ? 0 : width / 2;
referencePointY = centered ? 0 : height / 2;
lat = (maxLatPoint.getLat() - minLatPoint.getLat()) / 2 + minLatPoint.getLat();
lng = (maxLonPoint.getLng() - minLonPoint.getLng()) / 2 + minLonPoint.getLng();
GeoPoint ref = new GeoPoint(lat, lng);
double vertDistance = GeoUtility.getDistance(
ref, new GeoPoint(ref.getLat(), maxLonPoint.getLng())
) * 2.1;
double horiDistance = GeoUtility.getDistance(
ref, new GeoPoint(maxLatPoint.getLat(), ref.getLng())
) * 2.1;
double vertScale = height / vertDistance;
if (horiDistance * vertScale > width) {
scaleFactor = width / horiDistance;
scaleDirection = ScaleDirection.HORIZONTAL;
} else {
scaleFactor = vertScale;
scaleDirection = ScaleDirection.VERTICAL;
}
return new ScaledPoint(lat, lng, referencePointX, referencePointY, scaleFactor, scaleDirection);
}
}
@@ -0,0 +1,498 @@
package seng302.model;
import java.util.HashMap;
import javafx.scene.paint.Color;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.GameState;
import seng302.gameServer.messages.BoatStatus;
import seng302.model.mark.Mark;
import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
* not used anymore.
*/
public class ServerYacht {
private Logger logger = LoggerFactory.getLogger(ServerYacht.class);
//Boat info
private BoatMeshType boatType;
private Double turnStep = 5.0;
private Double boatTypeSpeedMultiplier = 1.0;
private Double boatTypeTurnStepMultiplier = 1.0;
private Double boatTypeAccelerationMultiplier = 1.0;
private Integer sourceId;
private String hullID; //matches HullNum in the XML spec.
private String shortName;
private String boatName;
private String country;
private BoatStatus boatStatus;
private Color boatColor;
//Location
private Double lastHeading;
private Boolean sailIn;
private Double heading;
private GeoPoint lastLocation;
private GeoPoint location;
private Double currentVelocity;
private Boolean isAuto;
private Double autoHeading;
private Integer legNumber;
//Mark Rounding
private Integer currentMarkSeqID;
private Boolean hasEnteredRoundingZone;
private Mark closestCurrentMark;
private Boolean hasPassedLine;
private Boolean hasPassedThroughGate;
//PowerUp
private TokenType powerUp;
private Long powerUpStartTime;
private Double powerUpSpeedMultiplier;
private Integer powerUpHandlingMultiplier;
//turning mode
private Boolean continuouslyTurning;
public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) {
setBoatType(boatType);
this.boatStatus = BoatStatus.PRESTART;
this.sourceId = sourceId;
this.hullID = hullID;
this.shortName = shortName;
this.boatName = boatName;
this.country = country;
this.sailIn = false;
this.isAuto = false;
this.location = new GeoPoint(57.67046, 11.83751);
this.lastLocation = location;
this.heading = 120.0; //In degrees
this.currentVelocity = 0d; //in mms-1
this.currentMarkSeqID = 0;
this.legNumber = 0;
this.boatColor = Colors.getColor(sourceId - 1);
this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
this.hasEnteredRoundingZone = false;
this.hasPassedLine = false;
this.hasPassedThroughGate = false;
this.continuouslyTurning = false;
}
/**
* Changes the boats current currentVelocity by a set amount, positive or negative
*
* @param velocityChange The ammount to change the currentVelocity by, in mms-1
*/
public void changeVelocity(Double velocityChange) {
currentVelocity += velocityChange;
}
/**
* Updates the boat to a new GeoPoint whilst preserving the last location
*
* @param secondsElapsed The seconds elapsed since the last update of this yacht
*/
public void updateLocation(Double secondsElapsed) {
lastLocation = location;
location = GeoUtility.getGeoCoordinate(location, heading, currentVelocity * secondsElapsed);
}
public void setLocation(GeoPoint geoPoint) {
location = geoPoint;
}
/**
* Powers up a yacht with a given yacht, only after powering it down first to avoid double power
* ups
*
* @param powerUp The given power up
*/
public void powerUp(TokenType powerUp) {
powerDown();
switch (powerUp) {
case BOOST:
powerUpSpeedMultiplier = GameState.VELOCITY_BOOST_MULTIPLIER;
break;
case HANDLING:
powerUpHandlingMultiplier = GameState.HANDLING_BOOST_MULTIPLIER;
break;
}
this.powerUp = powerUp;
powerUpStartTime = System.currentTimeMillis();
}
/**
* Powers down a yacht, returning its power multipliers back to 1
*/
public void powerDown() {
this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
}
public Long getPowerUpStartTime() {
return powerUpStartTime;
}
public TokenType getPowerUp() {
return powerUp;
}
/**
* Adjusts the heading of the boat by a given amount, while recording the boats last heading.
*
* @param amount the amount by which to adjust the boat heading.
*/
public void adjustHeading(Double amount) {
Double newVal = heading + amount * powerUpHandlingMultiplier * boatTypeTurnStepMultiplier;
lastHeading = heading;
heading = (double) Math.floorMod(newVal.longValue(), 360L);
}
/**
* Swaps the boats direction from one side of the wind to the other.
* @param windDirection .
*/
public void tackGybe(Double windDirection) {
if (isAuto) {
disableAutoPilot();
} else {
Double normalizedHeading = normalizeHeading();
Double newVal = (-2 * normalizedHeading) + heading;
Double newHeading = (double) Math.floorMod(newVal.longValue(), 360L);
setAutoPilot(newHeading);
}
}
/**
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
*
* @param newHeading The heading to move the boat towards.
*/
private void setAutoPilot(Double newHeading) {
isAuto = true;
autoHeading = newHeading;
}
/**
* Disables the auto pilot function.
*/
public void disableAutoPilot() {
isAuto = false;
}
/**
* Moves the boat towards the given heading when the auto pilot was set. Disables the auto pilot
* in the event that the boat is within the range of 1 turn step of its goal.
*/
public void runAutoPilot() {
if (isAuto) {
turnTowardsHeading(autoHeading);
if (Math.abs(heading - autoHeading)
<= turnStep*1.5) {
isAuto = false;
setHeading(autoHeading);
}
}
}
public void toggleSailIn() {
sailIn = !sailIn;
}
public void turnUpwind() {
disableAutoPilot();
Double normalizedHeading = normalizeHeading();
if (continuouslyTurning) {
adjustHeading(turnStep);
} else {
if (normalizedHeading == 0) {
if (lastHeading < 180) {
adjustHeading(-turnStep);
} else {
adjustHeading(turnStep);
}
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(turnStep);
} else {
adjustHeading(-turnStep);
}
} else if (normalizedHeading < 180) {
adjustHeading(-turnStep);
} else {
adjustHeading(turnStep);
}
}
}
public void turnDownwind() {
disableAutoPilot();
Double normalizedHeading = normalizeHeading();
if (continuouslyTurning) {
adjustHeading(-turnStep);
} else {
if (normalizedHeading == 0) {
if (lastHeading < 180) {
adjustHeading(turnStep);
} else {
adjustHeading(-turnStep);
}
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(-turnStep);
} else {
adjustHeading(turnStep);
}
} else if (normalizedHeading < 180) {
adjustHeading(turnStep);
} else {
adjustHeading(-turnStep);
}
}
}
/**
* Takes the VMG from the polartable for upwind or downwind depending on the boats direction,
* and uses this to calculate a heading to move the yacht towards.
*/
public void turnToVMG() {
if (isAuto) {
disableAutoPilot();
} else {
Double normalizedHeading = normalizeHeading();
Double optimalHeading;
HashMap<Double, Double> optimalPolarMap;
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
} else {
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
}
optimalHeading = optimalPolarMap.keySet().iterator().next();
if (normalizedHeading > 180) {
optimalHeading = 360 - optimalHeading;
}
// Take optimal heading and turn into a boat heading rather than a wind heading.
optimalHeading =
(optimalHeading + GameState.getWindDirection()) % 360;
setAutoPilot(optimalHeading);
}
}
/**
* Takes a given heading and rotates the boat towards that heading. This does not care about
* being upwind or downwind, just which direction will reach a given heading faster.
*
* @param newHeading The heading to turn the yacht towards.
*/
private void turnTowardsHeading(Double newHeading) {
Double newVal = heading - newHeading;
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
adjustHeading(turnStep / 5);
} else {
adjustHeading(-turnStep / 5);
}
}
/**
* Returns a heading normalized for the wind direction. Heading direction into the wind is 0,
* directly away is 180.
*
* @return The normalized heading accounting for wind direction.
*/
private Double normalizeHeading() {
Double normalizedHeading = heading - GameState.windDirection;
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
return normalizedHeading;
}
public Integer getSourceId() {
//@TODO Remove and merge with Creating Game Loop
if (sourceId == null) {
return 0;
}
return sourceId;
}
// TODO: 15/08/17 This method is implicitly called from the XML generator for boats DO NOT DELETE
public String getHullID() {
if (hullID == null) {
return "";
}
return hullID;
}
// TODO: 15/08/17 This method is implicitly called from the XML generator for boats DO NOT DELETE
public String getShortName() {
return shortName;
}
public String getBoatName() {
return boatName;
}
public String getCountry() {
if (country == null) {
return "";
}
return country;
}
public void setBoatName(String name) {
boatName = name;
shortName = name.split(" ")[0];
}
public GeoPoint getLocation() {
return location;
}
public Double getHeading() {
return heading;
}
public void setHeading(Double heading) {
this.heading = heading;
}
public Boolean getSailIn() {
return sailIn;
}
@Override
public String toString() {
return boatName;
}
public Double getCurrentVelocity() {
return currentVelocity;
}
public void setCurrentVelocity(Double currentVelocity) {
this.currentVelocity = currentVelocity;
}
public Integer getCurrentMarkSeqID() {
return currentMarkSeqID;
}
public GeoPoint getLastLocation() {
return lastLocation;
}
public Mark getClosestCurrentMark() {
return closestCurrentMark;
}
public void setClosestCurrentMark(Mark closestCurrentMark) {
this.closestCurrentMark = closestCurrentMark;
}
public void setHasEnteredRoundingZone(Boolean hasEnteredRoundingZone) {
this.hasEnteredRoundingZone = hasEnteredRoundingZone;
}
public void setHasPassedLine(Boolean hasPassedLine) {
this.hasPassedLine = hasPassedLine;
}
public void setHasPassedThroughGate(Boolean hasPassedThroughGate) {
this.hasPassedThroughGate = hasPassedThroughGate;
}
public BoatStatus getBoatStatus() {
return boatStatus;
}
public void setBoatStatus(BoatStatus boatStatus) {
this.boatStatus = boatStatus;
}
public void incrementMarkSeqID() {
currentMarkSeqID++;
}
public Boolean hasEnteredRoundingZone() {
return hasEnteredRoundingZone;
}
public Boolean hasPassedThroughGate() {
return hasPassedThroughGate;
}
public Boolean hasPassedLine() {
return hasPassedLine;
}
public void incrementLegNumber() {
legNumber++;
}
public Integer getLegNumber() {
return legNumber;
}
public void setBoatColor(Color color) {
this.boatColor = color;
}
public Color getBoatColor() {
return boatColor;
}
public void setBoatType(BoatMeshType boatType) {
this.boatTypeAccelerationMultiplier = boatType.accelerationMultiplier;
this.boatTypeSpeedMultiplier = boatType.maxSpeedMultiplier;
this.boatTypeTurnStepMultiplier = boatType.turnStep;
this.boatType = boatType;
}
public Double getBoatTypeSpeedMultiplier() {
return boatTypeSpeedMultiplier;
}
public Double getBoatTypeAccelerationMultiplier() {
return boatTypeAccelerationMultiplier;
}
public BoatMeshType getBoatType() {
return boatType;
}
public void setContinuouslyTurning(Boolean continuouslyTurning) {
this.continuouslyTurning = continuouslyTurning;
}
public Double getPowerUpSpeedMultiplier() {
return powerUpSpeedMultiplier;
}
public void setPowerUpSpeedMultiplier(Double powerUpSpeedMultiplier) {
this.powerUpSpeedMultiplier = powerUpSpeedMultiplier;
}
public Integer getPowerUpHandlingMultiplier() {
return powerUpHandlingMultiplier;
}
public void setPowerUpHandlingMultiplier(Integer powerUpHandlingMultiplier) {
this.powerUpHandlingMultiplier = powerUpHandlingMultiplier;
}
}
@@ -0,0 +1,129 @@
package seng302.model.mark;
import java.util.Collections;
import java.util.List;
import seng302.gameServer.messages.RoundingSide;
import seng302.model.GeoPoint;
import seng302.utilities.GeoUtility;
public class CompoundMark {
private int compoundMarkId;
private String name;
private List<Mark> marks;
private GeoPoint midPoint;
public CompoundMark(int markID, String name, List<Mark> marks) {
this.compoundMarkId = markID;
this.name = name;
this.marks = Collections.unmodifiableList(marks);
if (marks.size() > 1) {
this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1));
} else {
this.midPoint = marks.get(0);
}
}
/**
* Prints out compoundMark's info and its marks, good for testing
* @return a string showing its details
*/
@Override
public String toString(){
String info = String.format(
"CompoundMark: %d (%s), [%s", compoundMarkId, name, marks.get(0).toString()
);
if (marks.size() > 1) {
info += String.format(", %s", marks.get(1).toString());
}
return info + "]";
}
public int getId() {
return compoundMarkId;
}
public void setId (int markID) {
this.compoundMarkId = markID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setRoundingSide(RoundingSide roundingSide) {;
switch (roundingSide) {
case SP:
getSubMark(1).setRoundingSide(RoundingSide.STARBOARD);
getSubMark(2).setRoundingSide(RoundingSide.PORT);
break;
case PS:
getSubMark(1).setRoundingSide(RoundingSide.PORT);
getSubMark(2).setRoundingSide(RoundingSide.STARBOARD);
break;
case PORT:
getSubMark(1).setRoundingSide(RoundingSide.PORT);
break;
case STARBOARD:
getSubMark(1).setRoundingSide(RoundingSide.STARBOARD);
break;
}
}
/**
* Returns the mark contained in the compound mark. Marks are numbered 1 to n;
* @param singleMarkId the id of the desired mark contained in this compound mark.
* @return the desired mark. Returns null if the ID is not in range (1, NUM_MARKS)
*/
public Mark getSubMark(int singleMarkId) {
try {
return marks.get(singleMarkId - 1);
} catch (IndexOutOfBoundsException e) {
return null;
}
}
/**
* NOTE: This is a 'dirty' mid point as it is simply calculated as an xy point would be.
* NO CHECKING FOR LAT / LNG WRAPPING IS DONE IN CREATION OF THIS MIDPOINT
*
* @return GeoPoint of the midpoint of the two marks, or the one mark if there is only one
*/
public GeoPoint getMidPoint() {
return midPoint;
}
/**
* Returns whether or not this CompoundMark is a Gate. It is generally cleaner to program to a
* specific singleMark or the list of marks.
*
* @return True if the compound mark is a gate, false otherwise.
*/
public boolean isGate () {
return marks.size() > 1;
}
/**
* Returns the list of marks in the compoundMark
*
* @return All marks contained in this mark.
*/
public List<Mark> getMarks () {
return marks;
}
@Override
public int hashCode() {
int hash = 0;
for (Mark mark : marks) {
hash += Double.hashCode(mark.getSourceID()) + Double.hashCode(mark.getLat())
+ Double.hashCode(mark.getLng()) + mark.getName().hashCode();
}
return hash + getName().hashCode() + Integer.hashCode(getId());
}
}
@@ -0,0 +1,41 @@
package seng302.model.mark;
/**
* Stores the data for the cornering of a mark.
*/
public class Corner {
private Integer seqID;
private Integer compoundMarkID;
private String rounding;
private Integer zoneSize;
public Corner(Integer seqID, Integer compoundMarkID, String rounding, Integer zoneSize) {
this.seqID = seqID;
this.compoundMarkID = compoundMarkID;
this.rounding = rounding;
this.zoneSize = zoneSize;
}
public Integer getSeqID() {
return seqID;
}
public Integer getCompoundMarkID() {
return compoundMarkID;
}
public String getRounding() {
return rounding;
}
public Integer getZoneSize() {
return zoneSize;
}
@Override
public String toString() {
return "Corner = {seqID=" + seqID + ", compoundMarkID=" + compoundMarkID + ", rounding="
+ rounding +", zoneSize=" + zoneSize + "}";
}
}
@@ -0,0 +1,86 @@
package seng302.model.mark;
import java.util.ArrayList;
import java.util.List;
import seng302.gameServer.messages.RoundingSide;
import seng302.model.GeoPoint;
/**
* An abstract class to represent general marks
* Created by Haoming Yin (hyi25) on 17/3/17.
*/
public class Mark extends GeoPoint {
@FunctionalInterface
public interface PositionListener {
void notifyPositionChange(Mark mark, double lat, double lon);
}
private int seqID;
private String name;
private int sourceID;
private List<PositionListener> positionListeners = new ArrayList<>();
private RoundingSide roundingSide;
public Mark(String name, int seqID, double lat, double lng, int sourceID) {
super(lat, lng);
this.name = name;
this.sourceID = sourceID;
this.seqID = seqID;
}
/**
* Prints out mark's info and its geo location, good for testing
* @return a string showing its details
*/
@Override
public String toString() {
return String.format("Mark%d: %s, source: %d, lat: %f, lng: %f", seqID, name, sourceID, getLat(), getLng());
}
public int getSeqID() {
return seqID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSourceID() {
return sourceID;
}
public RoundingSide getRoundingSide() {
return roundingSide;
}
public void setRoundingSide(RoundingSide roundingSide) {
this.roundingSide = roundingSide;
}
public void setSourceID(int sourceID) {
this.sourceID = sourceID;
}
public void updatePosition (double lat, double lon) {
this.setLat(lat);
this.setLng(lon);
for (PositionListener listener : positionListeners) {
listener.notifyPositionChange(this, lat, lon);
}
}
public void addPositionListener (PositionListener listener) {
positionListeners.add(listener);
}
public void removePositionListener (PositionListener listener) {
positionListeners.remove(listener);
}
}
@@ -0,0 +1,79 @@
package seng302.model.mark;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.RoundingSide;
import seng302.model.stream.xml.parser.RaceXMLData;
/**
* Class to hold the order of the marks in the race.
*/
public class MarkOrder {
private List<CompoundMark> raceMarkOrder;
private List<CompoundMark> orderedUniqueCompoundMarks;
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
private List<Mark> allMarks;
public MarkOrder(RaceXMLData raceXMLData){
raceMarkOrder = new ArrayList<>();
for (Corner corner : raceXMLData.getMarkSequence()){
CompoundMark compoundMark = raceXMLData.getCompoundMarks().get(corner.getCompoundMarkID());
compoundMark.setRoundingSide(
RoundingSide.getRoundingSide(corner.getRounding())
);
raceMarkOrder.add(compoundMark);
}
orderedUniqueCompoundMarks = new ArrayList<>(raceXMLData.getCompoundMarks().values());
}
/**
* @return An ordered list of marks in the race
* OR null if the mark order could not be loaded
*/
public List<CompoundMark> getMarkOrder() {
if (raceMarkOrder == null){
logger.warn("Race order accessed but not instantiated");
return null;
}
return Collections.unmodifiableList(raceMarkOrder);
}
public List<CompoundMark> getOrderedUniqueCompoundMarks() {
return orderedUniqueCompoundMarks;
}
/**
* @param seqID The seqID of the current mark the boat is heading to
* @return A Boolean indicating if this coming mark is the last one (finish line)
*/
public Boolean isLastMark(Integer seqID) {
return seqID == raceMarkOrder.size() - 1;
}
/**
* @param currentSeqID The seqID of the current mark the boat is heading to
* @return The mark last passed
* @throws IndexOutOfBoundsException if there is no next mark. Check seqID != 0 first
*/
public CompoundMark getPreviousMark(Integer currentSeqID) throws IndexOutOfBoundsException {
return raceMarkOrder.get(currentSeqID - 1);
}
public CompoundMark getCurrentMark(Integer currentSeqID) {
return raceMarkOrder.get(currentSeqID);
}
/**
* @param currentSeqID The seqID of the current mark the boat is heading to
* @return The mark following the mark that the boat is heading to
* @throws IndexOutOfBoundsException if there is no next mark. Check using {@link
* #isLastMark(Integer)}
*/
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException {
return raceMarkOrder.get(currentSeqID + 1);
}
}
@@ -0,0 +1,78 @@
package seng302.model.stream.packets;
public enum PacketType {
HEARTBEAT,
RACE_STATUS,
DISPLAY_TEXT_MESSAGE,
RACE_XML,
REGATTA_XML,
BOAT_XML,
RACE_START_STATUS,
YACHT_EVENT_CODE,
YACHT_ACTION_CODE,
CHATTER_TEXT,
BOAT_LOCATION,
MARK_ROUNDING,
COURSE_WIND,
AVG_WIND,
BOAT_ACTION,
OTHER,
RACE_REGISTRATION_REQUEST,
RACE_REGISTRATION_RESPONSE,
RACE_CUSTOMIZATION_REQUEST,
RACE_CUSTOMIZATION_RESPONSE,
SERVER_REGISTRATION, ROOM_CODE_REQUEST, LOBBY_REQUEST;
public static PacketType assignPacketType(int packetType, byte[] payload){
switch(packetType){
case 1:
return HEARTBEAT;
case 12:
return RACE_STATUS;
case 20:
return DISPLAY_TEXT_MESSAGE;
case 26:
switch (payload[9]) { //The type of XML message
case 5:
return REGATTA_XML;
case 6:
return RACE_XML;
case 7:
return BOAT_XML;
}
case 27:
return RACE_START_STATUS;
case 29:
return YACHT_EVENT_CODE;
case 31:
return YACHT_ACTION_CODE;
case 36:
return CHATTER_TEXT;
case 37:
return BOAT_LOCATION;
case 38:
return MARK_ROUNDING;
case 44:
return COURSE_WIND;
case 47:
return AVG_WIND;
case 100:
return BOAT_ACTION;
case 101:
return RACE_REGISTRATION_REQUEST;
case 102:
return RACE_REGISTRATION_RESPONSE;
case 103:
return RACE_CUSTOMIZATION_REQUEST;
case 104:
return RACE_CUSTOMIZATION_RESPONSE;
case 201:
return SERVER_REGISTRATION;
case 202:
return ROOM_CODE_REQUEST;
default:
}
return OTHER;
}
}
@@ -1,4 +1,4 @@
package seng302.models.stream.packets;
package seng302.model.stream.packets;
/**
* Created by kre39 on 23/04/17.
@@ -13,7 +13,7 @@ public class StreamPacket {
private byte[] payload;
public StreamPacket(int type, long messageLength, long timeStamp, byte[] payload) {
this.type = PacketType.assignPacketType(type);
this.type = PacketType.assignPacketType(type, payload);
this.messageLength = messageLength;
this.timeStamp = timeStamp;
this.payload = payload;
@@ -0,0 +1,36 @@
package seng302.model.stream.parser;
/**
* Simple data wrapper for mark rounding data packet.
*/
public class MarkRoundingData {
private int boatId;
private int markId;
private int roundingSide;
private long timeStamp;
public MarkRoundingData(int boatId, int markId, int roundingSide, long timeStamp) {
this.boatId = boatId;
this.markId = markId;
this.roundingSide = roundingSide;
this.timeStamp = timeStamp;
}
public int getBoatId() {
return boatId;
}
public int getMarkId() {
return markId;
}
public int getRoundingSide() {
return roundingSide;
}
public long getTimeStamp() {
return timeStamp;
}
}
@@ -0,0 +1,50 @@
package seng302.model.stream.parser;
public class PositionUpdateData {
public enum DeviceType {
YACHT_TYPE,
MARK_TYPE
}
private int deviceId;
private DeviceType type;
private double lat;
private double lon;
private double heading;
private double groundSpeed;
public PositionUpdateData(int deviceId, DeviceType type, double lat, double lon,
double heading, double groundSpeed) {
this.deviceId = deviceId;
this.type = type;
this.lat = lat;
this.lon = lon;
this.heading = heading;
this.groundSpeed = groundSpeed;
}
public int getDeviceId() {
return deviceId;
}
public DeviceType getType() {
return type;
}
public double getLat() {
return lat;
}
public double getLon() {
return lon;
}
public double getHeading() {
return heading;
}
public double getGroundSpeed() {
return groundSpeed;
}
}
@@ -0,0 +1,35 @@
package seng302.model.stream.parser;
/**
* Class for storing data parsed from race start status packet
*/
public class RaceStartData {
private long raceId;
private long raceStartTime;
private int notificationType;
private long timeStamp;
public RaceStartData (long raceId, long raceStartTime, int notificationType, long timeStamp) {
this.raceId = raceId;
this.raceStartTime = raceStartTime;
this.notificationType = notificationType;
this.timeStamp = timeStamp;
}
public long getRaceId() {
return raceId;
}
public long getRaceStartTime() {
return raceStartTime;
}
public int getNotificationType() {
return notificationType;
}
public long getTimeStamp() {
return timeStamp;
}
}

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