Endgame WS messages & docs
This commit is contained in:
117
README.md
117
README.md
@ -234,8 +234,8 @@ loop #lightyellow Product select countdown timer (60s)
|
|||||||
Game ->o WS: Timer timeout
|
Game ->o WS: Timer timeout
|
||||||
activate Game
|
activate Game
|
||||||
activate WS #coral
|
activate WS #coral
|
||||||
WS o-> Client1: Cancel selection
|
WS o-> Client1: Selection timeout
|
||||||
WS o-> Client2: Cancel selection
|
WS o-> Client2: Selection timeout
|
||||||
deactivate WS
|
deactivate WS
|
||||||
Game -> Game: Unlock game
|
Game -> Game: Unlock game
|
||||||
deactivate Game
|
deactivate Game
|
||||||
@ -400,6 +400,8 @@ Response body:
|
|||||||
|
|
||||||
### Game state structure
|
### Game state structure
|
||||||
|
|
||||||
|
Direction: Game server -> Clients
|
||||||
|
|
||||||
Message: `game_dump`
|
Message: `game_dump`
|
||||||
|
|
||||||
Data:
|
Data:
|
||||||
@ -503,109 +505,42 @@ Data:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Product purchase start
|
### Player reached destination
|
||||||
|
|
||||||
Message: `product_purchase_start`
|
Direction: Game server -> Clients
|
||||||
|
|
||||||
|
Message: `player_reached_destination`
|
||||||
|
|
||||||
Data:
|
Data:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"player": {
|
"player": {
|
||||||
"id": "test-player-pero",
|
"id": "2e0f1a50-eaa6-4efd-b0c3-adbf7000eec2",
|
||||||
"name": "Pero",
|
"name": "Joso",
|
||||||
"active": true,
|
"active": true,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 10,
|
"x": 5,
|
||||||
"y": 10
|
"y": 5
|
||||||
},
|
},
|
||||||
"move_count": 1,
|
"move_count": 6,
|
||||||
"move_attempt_count": 1,
|
"move_attempt_count": 6,
|
||||||
"state": "ON_DESTINATION"
|
|
||||||
},
|
|
||||||
"products": [
|
|
||||||
{
|
|
||||||
"name": "CocaCola",
|
|
||||||
"id": "cocacola-id",
|
|
||||||
"description": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Pepsi",
|
|
||||||
"id": "pepsi-id",
|
|
||||||
"description": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Fanta",
|
|
||||||
"id": "fanta-id",
|
|
||||||
"description": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Snickers",
|
|
||||||
"id": "snickers-id",
|
|
||||||
"description": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mars",
|
|
||||||
"id": "mars-id",
|
|
||||||
"description": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Burek",
|
|
||||||
"id": "burek-id",
|
|
||||||
"description": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timeout": 5
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Product purchase timer tick
|
|
||||||
|
|
||||||
Message: `product_purchase_timer_tick`
|
|
||||||
|
|
||||||
Data:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"time_left": 4,
|
|
||||||
"player": {
|
|
||||||
"id": "test-player-pero",
|
|
||||||
"name": "Pero",
|
|
||||||
"active": true,
|
|
||||||
"position": {
|
|
||||||
"x": 10,
|
|
||||||
"y": 10
|
|
||||||
},
|
|
||||||
"move_count": 1,
|
|
||||||
"move_attempt_count": 1,
|
|
||||||
"state": "ON_DESTINATION"
|
"state": "ON_DESTINATION"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Product purchase timer done
|
### Product selection timeout
|
||||||
|
|
||||||
Message: `product_purchase_done`
|
Direction: Game server -> Clients
|
||||||
|
|
||||||
Data:
|
Message: `product_selection_timeout`
|
||||||
```json
|
|
||||||
{
|
|
||||||
"player": {
|
|
||||||
"id": "test-player-pero",
|
|
||||||
"name": "Pero",
|
|
||||||
"active": true,
|
|
||||||
"position": {
|
|
||||||
"x": 10,
|
|
||||||
"y": 10
|
|
||||||
},
|
|
||||||
"move_count": 1,
|
|
||||||
"move_attempt_count": 1,
|
|
||||||
"state": "ON_DESTINATION"
|
|
||||||
},
|
|
||||||
"product": {
|
|
||||||
"name": "CocaCola",
|
|
||||||
"id": "cocacola-id",
|
|
||||||
"description": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If product selection timeout occured, product will be null.
|
Data: `null`
|
||||||
|
|
||||||
|
### Product selection done
|
||||||
|
|
||||||
|
Message: `product_selection_done`
|
||||||
|
|
||||||
|
Direction: Client -> Game server, Game server -> Clients
|
||||||
|
|
||||||
|
Data: `null`
|
||||||
|
|||||||
@ -22,9 +22,6 @@
|
|||||||
<h1 class="mt-1 mb-2">
|
<h1 class="mt-1 mb-2">
|
||||||
FairHopper Visualisation Client
|
FairHopper Visualisation Client
|
||||||
</h1>
|
</h1>
|
||||||
<button type="button" class="btn btn-primary test-button">
|
|
||||||
Launch demo modal
|
|
||||||
</button>
|
|
||||||
<div id="purchase-container" class="purchase-container d-none">
|
<div id="purchase-container" class="purchase-container d-none">
|
||||||
<div class="d-flex header">
|
<div class="d-flex header">
|
||||||
<h3>
|
<h3>
|
||||||
@ -68,18 +65,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
document.querySelector(".test-button").onclick = () => {
|
|
||||||
playerReachedDestination({
|
|
||||||
player: {
|
|
||||||
name: "Pero Perić",
|
|
||||||
move_count: 123,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@ -104,6 +104,10 @@ function playerReachedDestination(data) {
|
|||||||
playerOnDestinationModal.show();
|
playerOnDestinationModal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function productSelectionTimeout() {
|
||||||
|
playerOnDestinationModal.hide();
|
||||||
|
}
|
||||||
|
|
||||||
function productSelectionDone() {
|
function productSelectionDone() {
|
||||||
playerOnDestinationModal.hide();
|
playerOnDestinationModal.hide();
|
||||||
}
|
}
|
||||||
@ -127,6 +131,9 @@ function wsConnect() {
|
|||||||
case "player_reached_destination":
|
case "player_reached_destination":
|
||||||
playerReachedDestination(wsMessage.data);
|
playerReachedDestination(wsMessage.data);
|
||||||
break;
|
break;
|
||||||
|
case "product_selection_timeout":
|
||||||
|
productSelectionTimeout();
|
||||||
|
break;
|
||||||
case "product_selection_done":
|
case "product_selection_done":
|
||||||
productSelectionDone();
|
productSelectionDone();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -185,7 +185,7 @@ class GameEngine:
|
|||||||
logging.info("Ding ding! Product selection countdown timer timeout")
|
logging.info("Ding ding! Product selection countdown timer timeout")
|
||||||
self._purchase_countdown_timer = None
|
self._purchase_countdown_timer = None
|
||||||
asyncio.run(
|
asyncio.run(
|
||||||
self.ws_server.send_product_selection_done_message()
|
self.ws_server.send_product_selection_timeout_message()
|
||||||
)
|
)
|
||||||
self.game_state = GameState.RUNNING
|
self.game_state = GameState.RUNNING
|
||||||
asyncio.run(self.send_game_dump())
|
asyncio.run(self.send_game_dump())
|
||||||
|
|||||||
@ -6,13 +6,7 @@ from typing import Optional, TypeVar
|
|||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from pydantic.generics import GenericModel
|
from pydantic.generics import GenericModel
|
||||||
|
|
||||||
from hopper.api.dto import (
|
from hopper.api.dto import BaseModel, BoardDto, DestinationDto, PlayerDto, PositionDto
|
||||||
BaseModel,
|
|
||||||
BoardDto,
|
|
||||||
DestinationDto,
|
|
||||||
PlayerDto,
|
|
||||||
PositionDto,
|
|
||||||
)
|
|
||||||
from hopper.enums import ObjectType
|
from hopper.enums import ObjectType
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +59,10 @@ class WSProductSelectionDoneMessage(WSMessage):
|
|||||||
message: str = "product_selection_done"
|
message: str = "product_selection_done"
|
||||||
|
|
||||||
|
|
||||||
|
class WSProductSelectionTimeoutMessage(WSMessage):
|
||||||
|
message: str = "product_selection_timeout"
|
||||||
|
|
||||||
|
|
||||||
class WSPlayerReachedDestinationMessage(WSMessage):
|
class WSPlayerReachedDestinationMessage(WSMessage):
|
||||||
message: str = "player_reached_destination"
|
message: str = "player_reached_destination"
|
||||||
data: PlayerReachedDestinationDto
|
data: PlayerReachedDestinationDto
|
||||||
|
|||||||
@ -15,6 +15,7 @@ from hopper.models.ws_dto import (
|
|||||||
WSMessage,
|
WSMessage,
|
||||||
WSPlayerReachedDestinationMessage,
|
WSPlayerReachedDestinationMessage,
|
||||||
WSProductSelectionDoneMessage,
|
WSProductSelectionDoneMessage,
|
||||||
|
WSProductSelectionTimeoutMessage,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -63,7 +64,9 @@ class WSServer(Thread):
|
|||||||
try:
|
try:
|
||||||
# we're expecting nothing from client, but read if client sends a message
|
# we're expecting nothing from client, but read if client sends a message
|
||||||
rcv_data = await websocket.recv()
|
rcv_data = await websocket.recv()
|
||||||
await self.handle_rcv_message(client=websocket, raw_message=rcv_data)
|
await self.handle_rcv_message(
|
||||||
|
client=websocket, raw_message=rcv_data
|
||||||
|
)
|
||||||
except ConnectionClosedOK:
|
except ConnectionClosedOK:
|
||||||
logging.info(f"Connection closed OK for client: {websocket.id}")
|
logging.info(f"Connection closed OK for client: {websocket.id}")
|
||||||
connected = False
|
connected = False
|
||||||
@ -126,6 +129,10 @@ class WSServer(Thread):
|
|||||||
message = WSProductSelectionDoneMessage()
|
message = WSProductSelectionDoneMessage()
|
||||||
await self.send_message_to_clients(message)
|
await self.send_message_to_clients(message)
|
||||||
|
|
||||||
|
async def send_product_selection_timeout_message(self) -> None:
|
||||||
|
message = WSProductSelectionTimeoutMessage()
|
||||||
|
await self.send_message_to_clients(message)
|
||||||
|
|
||||||
async def run_async(self) -> None:
|
async def run_async(self) -> None:
|
||||||
logging.info(
|
logging.info(
|
||||||
f"Starting FairHopper Websockets Server on {self.host}:{self.port}"
|
f"Starting FairHopper Websockets Server on {self.host}:{self.port}"
|
||||||
|
|||||||
Reference in New Issue
Block a user