Work on dedicated server. This svn revision is totally broken, it is part of a complete redesign of the server.

There is a lobby thread for the server, and each game has its own game processing thread and a sender thread. Connections can be accepted from different sources, i.e. TCP/SCTP over IPv4, IPv6, all those work well in parallel.
This commit is contained in:
lotodore
2007-08-15 13:28:28 +00:00
parent ab0dd1d065
commit 59b7438376
12 changed files with 1561 additions and 797 deletions
+176 -58
View File
@@ -1,4 +1,6 @@
Changelog: Changelog:
08-14-2007: Supporting multiple games per server.
Player id is now 32 bit to avoid collisions.
08-02-2007: Added new requests for game start and kick player. 08-02-2007: Added new requests for game start and kick player.
Type ids changed. Type ids changed.
07-24-2007: Join Game ACK / Player Joined do not specify player number. 07-24-2007: Join Game ACK / Player Joined do not specify player number.
@@ -21,7 +23,7 @@ PokerTH general message format:
Minimum length is 8. Maximum length is 256. Minimum length is 8. Maximum length is 256.
Client Request: Join Game Client Request: Init
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -37,9 +39,9 @@ Client Request: Join Game
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Additional values for major version = 2: Additional values for major version = 2:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Password Length | Name Length | | Password Length | Player Name Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|| Reserved | | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | |
\ Password (UTF-8) / \ Password (UTF-8) /
@@ -47,24 +49,143 @@ Additional values for major version = 2:
/ | padding | / | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| \ | \
\ Name (UTF-8) / \ Player Name (UTF-8) /
| +-------------------------------+ | +-------------------------------+
/ | padding | / | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
[Future versions will include an id of the game, to support
multiple games per server.]
Server Reply: Join Game ACK Server Reply: Init ACK
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 2 | Message Length = 28 | | Message Type = 2 | Message Length = 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Your Session ID | | Your Session ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Your Player ID | Your Player Flags | | Your Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Player ID:
Unique Player ID
Session ID:
Unique Session ID which is not known by other players
Server Notification: Game List New
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 3 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game Mode | Game Name Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| \
\ Game Name (UTF-8) /
| +-------------------------------+
/ | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Game List notifications will be automatically sent if the player
is in the lobby. If a game is joined/started, no more messages
will be sent. As soon as the player leaves a game without
disconnecting, Game List notifications will be sent again.
Game Mode:
1: Game Created
2: Game Started
3: Game Closed (only for Game List Update)
Server Notification: Game List Update
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 4 | Message Length = 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game Mode | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Client Request: Create Game
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 5 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Password Length | Game Name Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Max Number of Players | Small Blind |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Hands before raise | Proposed GUI Speed |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player Action Timeout | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Start Money |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
\ Password (UTF-8) /
| +-------------------------------+
/ | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| \
\ Game Name (UTF-8) /
| +-------------------------------+
/ | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Proposed GUI Speed:
1-11
Player Action Timeout:
# seconds
Player Flags:
0x01 set: Player is human
0x02 set: Player is admin for this game
Server Reply: Create Game Ack
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 6 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(also implies that the client successfully joined the game)
Client Request: Join Game
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 7 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Password Length | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
\ Password (UTF-8) /
| +-------------------------------+
/ | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Server Reply: Join Game Ack
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 8 | Message Length = 20 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Max Number of Players | Small Blind | | Max Number of Players | Small Blind |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -75,30 +196,19 @@ Server Reply: Join Game ACK
| Start Money | | Start Money |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Player ID:
Unique Player ID
Proposed GUI Speed:
1-11
Player Action Timeout:
# seconds
Player Flags:
0x01 set: Player is human
0x02 set: Player is admin for this game
Server Notification: Player Joined Server Notification: Player Joined
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 3 | Message Length | | Message Type = 9 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID | Player Flags | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Name Length | Reserved | | Player Flags | Player Name Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| \ | \
\ Name (UTF-8) / \ Player Name (UTF-8) /
| +-------------------------------+ | +-------------------------------+
/ | padding | / | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -109,9 +219,9 @@ Server Notification: Player Left
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 4 | Message Length = 8 | | Message Type = 10 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID | Reserved | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -120,9 +230,9 @@ Client Request: Kick Player
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 5 | Message Length = 8 | | Message Type = 11 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID | Reserved | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -131,7 +241,7 @@ Client Request: Start Event
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 6 | Message Length = 4 | | Message Type = 12 | Message Length = 4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -140,18 +250,20 @@ Server Notification: Game Start
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 7 | Message Length | | Message Type = 13 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Start Dealer Player Id | Number of Players | | Start Dealer Player Id |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID Slot #1 | Player ID Slot #2 | | Number of Players | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID Slot #1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID Slot #2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| \ | \
\ Additional Player Slots / \ Additional Player Slots /
/ | / |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID Slot #n | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The player slots are the positions of the players on the table. Each slot The player slots are the positions of the players on the table. Each slot
contains the ID for the corresponding player. The slots are ordered. contains the ID for the corresponding player. The slots are ordered.
@@ -169,7 +281,7 @@ Server Notification: Hand Start
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 8 | Message Length = 8 | | Message Type = 14 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Your 1st Card | Your 2nd Card | | Your 1st Card | Your 2nd Card |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -183,9 +295,11 @@ Server Request/Notification: Player's Turn
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 9 | Message Length = 8 | | Message Type = 15 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game State | Player ID | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game State | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Game State: Game State:
@@ -200,7 +314,7 @@ Client Reply/Request: Player's Action
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 10 | Message Length = 12 | | Message Type = 16 | Message Length = 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game State | Player Action | | Game State | Player Action |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -225,11 +339,11 @@ Server Notification: Player's Action Done
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 11 | Message Length = 20 | | Message Type = 17 | Message Length = 20 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game State | Player Id | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player Action | Reserved | | Game State | Player Action |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Total Player Bet | | Total Player Bet |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -246,7 +360,7 @@ Server Reply: Player's Action Rejected
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 12 | Message Length = 16 | | Message Type = 18 | Message Length = 16 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Game State | Player Action | | Game State | Player Action |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -274,7 +388,7 @@ Server Notification: Deal Flop Cards
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 13 | Message Length = 12 | | Message Type = 19 | Message Length = 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Flop 1st Card | Flop 2nd Card | | Flop 1st Card | Flop 2nd Card |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -287,7 +401,7 @@ Server Notification: Deal Turn Card
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 14 | Message Length = 8 | | Message Type = 20 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Turn Card | Reserved | | Turn Card | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -298,7 +412,7 @@ Server Notification: Deal River Card
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 15 | Message Length = 8 | | Message Type = 21 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| River Card | Reserved | | River Card | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -309,7 +423,7 @@ Server Notification: All In Show Cards
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 16 | Message Length | | Message Type = 22 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number Of PlayerCards Records | Reserved | | Number Of PlayerCards Records | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -320,9 +434,9 @@ Server Notification: All In Show Cards
PlayerCards Record PlayerCards Record
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player Id | 1st Card | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 2nd Card | Reserved | | 1st Card | 2nd Card |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -331,7 +445,7 @@ Server Notification: End Of Hand Show Cards
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 17 | Message Length | | Message Type = 23 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Number Of PlayerResult Records | Reserved | |Number Of PlayerResult Records | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -342,13 +456,15 @@ Server Notification: End Of Hand Show Cards
PlayerResult Record PlayerResult Record
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player Id | 1st Card | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 2nd Card | Best Hand Position 1 | | 1st Card | 2nd Card |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Best Hand Position 2 | Best Hand Position 3 | | Best Hand Position 1 | Best Hand Position 2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Best Hand Position 4 | Best Hand Position 5 | | Best Hand Position 3 | Best Hand Position 4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Best Hand Position 5 | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Value Of Cards | | Value Of Cards |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -363,9 +479,9 @@ Server Notification: End Of Hand Hide Cards
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 18 | Message Length = 16 | | Message Type = 24 | Message Length = 16 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player Id | Reserved | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Money Won | | Money Won |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -378,9 +494,9 @@ Server Notification: End Of Game
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 19 | Message Length = 8 | | Message Type = 25 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Winner Player Id | Reserved | | Winner Player Id |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -407,7 +523,9 @@ Server Notification: Chat Text
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 513 | Message Length | | Message Type = 513 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Text Length | Player Id | | Player ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Text Length | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| \ | \
\ Text (UTF-8) / \ Text (UTF-8) /
+7 -1
View File
@@ -21,8 +21,14 @@
#ifndef _GAMEDATA_H_ #ifndef _GAMEDATA_H_
#define _GAMEDATA_H_ #define _GAMEDATA_H_
// For the sake of simplicity, this is a struct. enum GameMode
{
GAME_MODE_CREATED = 1,
GAME_MODE_STARTED,
GAME_MODE_CLOSED
};
// For the sake of simplicity, this is a struct.
struct GameData struct GameData
{ {
GameData() : maxNumberOfPlayers(0), startMoney(0), smallBlind(0), GameData() : maxNumberOfPlayers(0), startMoney(0), smallBlind(0),
+10 -13
View File
@@ -344,12 +344,12 @@ ClientStateStartSession::Process(ClientThread &client)
{ {
ClientContext &context = client.GetContext(); ClientContext &context = client.GetContext();
NetPacketJoinGame::Data initData; NetPacketInit::Data initData;
initData.password = context.GetPassword(); initData.password = context.GetPassword();
initData.playerName = context.GetPlayerName(); initData.playerName = context.GetPlayerName();
boost::shared_ptr<NetPacket> packet(new NetPacketJoinGame); boost::shared_ptr<NetPacket> packet(new NetPacketInit);
((NetPacketJoinGame *)packet.get())->SetData(initData); ((NetPacketInit *)packet.get())->SetData(initData);
client.GetSender().Send(context.GetSocket(), packet); client.GetSender().Send(context.GetSocket(), packet);
@@ -435,19 +435,16 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr<
int retVal = MSG_SOCK_INTERNAL_PENDING; int retVal = MSG_SOCK_INTERNAL_PENDING;
ClientContext &context = client.GetContext(); ClientContext &context = client.GetContext();
if (packet->ToNetPacketJoinGameAck()) if (packet->ToNetPacketInitAck())
{ {
// Everything is fine - we joined the game. // Everything is fine - we are in the lobby.
// Initialize game configuration. NetPacketInitAck::Data initAckData;
NetPacketJoinGameAck::Data joinGameAckData; packet->ToNetPacketInitAck()->GetData(initAckData);
packet->ToNetPacketJoinGameAck()->GetData(joinGameAckData); client.SetGuiPlayerId(initAckData.yourPlayerUniqueId);
client.SetGameData(joinGameAckData.gameData);
client.SetGuiPlayerId(joinGameAckData.yourPlayerUniqueId);
// TODO: Type Human is fixed here. // Player number is 0 on init. Will be set when the game starts.
// Player number is 0 on join. Will be set when the game starts.
boost::shared_ptr<PlayerData> playerData( boost::shared_ptr<PlayerData> playerData(
new PlayerData(joinGameAckData.yourPlayerUniqueId, 0, joinGameAckData.ptype, joinGameAckData.prights)); new PlayerData(initAckData.yourPlayerUniqueId, 0, PLAYER_TYPE_HUMAN, PLAYER_RIGHTS_NORMAL));
playerData->SetName(context.GetPlayerName()); playerData->SetName(context.GetPlayerName());
client.AddPlayerData(playerData); client.AddPlayerData(playerData);
File diff suppressed because it is too large Load Diff
+169 -494
View File
@@ -19,18 +19,18 @@
#include <net/serverrecvthread.h> #include <net/serverrecvthread.h>
#include <net/serverexception.h> #include <net/serverexception.h>
#include <net/serverrecvstate.h>
#include <net/senderthread.h> #include <net/senderthread.h>
#include <net/sendercallback.h> #include <net/sendercallback.h>
#include <net/receiverhelper.h> #include <net/receiverhelper.h>
#include <net/socket_msg.h> #include <net/socket_msg.h>
#include <game.h> #include <core/rand.h>
#include <tools.h>
#include <localenginefactory.h>
#include <boost/lambda/lambda.hpp> #include <boost/lambda/lambda.hpp>
#define SERVER_CLOSE_SESSION_DELAY_SEC 10 #define SERVER_CLOSE_SESSION_DELAY_SEC 10
#define SERVER_MAX_NUM_SESSIONS 64 // Maximum number of idle users in lobby.
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
using namespace std; using namespace std;
@@ -38,60 +38,56 @@ using namespace std;
class ServerSenderCallback : public SenderCallback class ServerSenderCallback : public SenderCallback
{ {
public: public:
ServerSenderCallback(ServerRecvThread &server) : m_server(server) {} ServerSenderCallback(ServerLobbyThread &server) : m_server(server) {}
virtual ~ServerSenderCallback() {} virtual ~ServerSenderCallback() {}
virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID) virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID)
{ {
// We just ignore send errors for now, on server side. // We just ignore send errors for now, on server side.
// A send error should trigger a read error or a read // A serious send error should trigger a read error or a read
// returning 0 afterwards, and we will handle this error. // returning 0 afterwards, and we will handle this error.
} }
private: private:
ServerRecvThread &m_server; ServerLobbyThread &m_server;
}; };
ServerRecvThread::ServerRecvThread(GuiInterface &gui, ConfigFile *playerConfig) ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig)
: m_curGameId(1), m_gui(gui), m_playerConfig(playerConfig) : m_gui(gui), m_playerConfig(playerConfig)
{ {
m_senderCallback.reset(new ServerSenderCallback(*this)); m_senderCallback.reset(new ServerSenderCallback(*this));
m_sender.reset(new SenderThread(GetSenderCallback())); m_sender.reset(new SenderThread(GetSenderCallback()));
m_receiver.reset(new ReceiverHelper); m_receiver.reset(new ReceiverHelper);
} }
ServerRecvThread::~ServerRecvThread() ServerLobbyThread::~ServerLobbyThread()
{ {
CleanupConnectQueue(); CleanupConnectQueue();
CleanupSessionMap();
} }
void void
ServerRecvThread::Init(const string &pwd, const GameData &gameData) ServerLobbyThread::Init(const string &pwd)
{ {
m_password = pwd; m_password = pwd;
m_gameData = gameData;
} }
void void
ServerRecvThread::AddConnection(boost::shared_ptr<ConnectData> data) ServerLobbyThread::AddConnection(boost::shared_ptr<ConnectData> data)
{ {
boost::mutex::scoped_lock lock(m_connectQueueMutex); boost::mutex::scoped_lock lock(m_connectQueueMutex);
m_connectQueue.push_back(data); m_connectQueue.push_back(data);
} }
void u_int32_t
ServerRecvThread::AddNotification(unsigned message, const string &param) ServerLobbyThread::GetNextUniquePlayerId()
{ {
boost::mutex::scoped_lock lock(m_notificationQueueMutex); return m_curUniquePlayerId++;
m_notificationQueue.push_back(Notification(message, param));
} }
void void
ServerRecvThread::Main() ServerLobbyThread::Main()
{ {
SetState(SERVER_INITIAL_STATE::Instance());
GetSender().Run(); GetSender().Run();
try try
@@ -110,12 +106,10 @@ ServerRecvThread::Main()
} }
} }
if (tmpData.get()) if (tmpData.get())
GetState().HandleNewConnection(*this, tmpData); HandleNewConnection(tmpData);
} }
// Process current state. // Process loop.
GetState().Process(*this); ProcessLoop();
// Process thread-safe notifications.
NotificationLoop();
// Close sessions. // Close sessions.
CloseSessionLoop(); CloseSessionLoop();
} }
@@ -127,28 +121,131 @@ ServerRecvThread::Main()
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
CleanupConnectQueue(); CleanupConnectQueue();
CleanupSessionMap(); m_sessionManager.Clear();
} }
void void
ServerRecvThread::NotificationLoop() ServerLobbyThread::ProcessLoop()
{ {
boost::mutex::scoped_lock lock(m_notificationQueueMutex); // Wait for data.
// Process all notifications. SessionWrapper session = m_sessionManager.Select(RECV_TIMEOUT_MSEC);
while (!m_notificationQueue.empty())
{
Notification notification = m_notificationQueue.front();
m_notificationQueue.pop_front();
// switch(notification.message) if (session.sessionData.get())
// { {
// break; boost::shared_ptr<NetPacket> packet;
// } try
{
// Receive the next packet.
packet = GetReceiver().Recv(session.sessionData->GetSocket());
} catch (const NetException &)
{
// On error: Close this session.
CloseSessionDelayed(session);
return;
}
if (packet.get())
{
if (packet->ToNetPacketInit())
{
// Session should be in initial state.
if (session.sessionData->GetState() != SessionData::Init)
SessionError(session, ERR_SOCK_INVALID_STATE);
else
HandleNetPacketInit(session, *packet->ToNetPacketInit());
}
// Session should be established.
else if (session.sessionData->GetState() != SessionData::Established)
SessionError(session, ERR_SOCK_INVALID_STATE);
else
{
if (packet->ToNetPacketCreateGame())
HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame());
else if (packet->ToNetPacketJoinGame())
HandleNetPacketJoinGame(session, *packet->ToNetPacketJoinGame());
}
}
} }
} }
void void
ServerRecvThread::CloseSessionLoop() ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket)
{
NetPacketInit::Data initData;
tmpPacket.GetData(initData);
// Check the protocol version.
if (initData.versionMajor != NET_VERSION_MAJOR)
{
SessionError(session, ERR_NET_VERSION_NOT_SUPPORTED);
return;
}
// Check the server password.
if (!CheckPassword(initData.password))
{
SessionError(session, ERR_NET_INVALID_PASSWORD);
return;
}
// Check whether the player name is correct.
// Partly, this is also done in netpacket.
// However, some disallowed names are checked only here.
if (initData.playerName.empty() || initData.playerName.size() > MAX_NAME_SIZE
|| initData.playerName.substr(0, sizeof(SERVER_COMPUTER_PLAYER_NAME) - 1) == SERVER_COMPUTER_PLAYER_NAME)
{
SessionError(session, ERR_NET_INVALID_PLAYER_NAME);
return;
}
// Check whether this player is already connected.
if (IsPlayerConnected(initData.playerName))
{
SessionError(session, ERR_NET_PLAYER_NAME_IN_USE);
return;
}
// Create player data object.
boost::shared_ptr<PlayerData> tmpPlayerData(
new PlayerData(GetNextUniquePlayerId(), 0, PLAYER_TYPE_HUMAN, PLAYER_RIGHTS_NORMAL));
tmpPlayerData->SetName(initData.playerName);
tmpPlayerData->SetNetSessionData(session.sessionData);
// Send ACK to client.
boost::shared_ptr<NetPacket> initAck(new NetPacketInitAck);
NetPacketInitAck::Data initAckData;
initAckData.sessionId = session.sessionData->GetId(); // TODO: currently unused.
initAckData.playerId = tmpPlayerData->GetUniqueId();
static_cast<NetPacketInitAck *>(initAck.get())->SetData(initAckData);
GetSender().Send(session.sessionData->GetSocket(), initAck);
// Send the game list to the client.
/*GameThreadList::iterator game_i = m_gameList.begin();
GameThreadList::iterator game_end = m_gameList.end();
while (game_i != game_end)
{
GetSender().Send(session.sessionData->GetSocket(), CreateNetPacketGameListUpdate(*(*game_i)));
++game_i;
}*/
// Set player data for session.
m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData);
// Session is now established.
session.sessionData->SetState(SessionData::Established);
}
void
ServerLobbyThread::HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket)
{
}
void
ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket)
{
}
void
ServerLobbyThread::CloseSessionLoop()
{ {
CloseSessionList::iterator i = m_closeSessionList.begin(); CloseSessionList::iterator i = m_closeSessionList.begin();
CloseSessionList::iterator end = m_closeSessionList.end(); CloseSessionList::iterator end = m_closeSessionList.end();
@@ -162,69 +259,32 @@ ServerRecvThread::CloseSessionLoop()
} }
} }
SOCKET void
ServerRecvThread::Select() ServerLobbyThread::HandleNewConnection(boost::shared_ptr<ConnectData> connData)
{ {
SOCKET retSock = INVALID_SOCKET; if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS)
SOCKET maxSock = INVALID_SOCKET;
fd_set rdset;
FD_ZERO(&rdset);
{ {
boost::mutex::scoped_lock lock(m_sessionMapMutex); // Create a random session id.
SocketSessionMap::iterator i = m_sessionMap.begin(); // This id can be used to reconnect to the server if the connection was lost.
SocketSessionMap::iterator end = m_sessionMap.end(); unsigned sessionId;
RandomBytes((unsigned char *)&sessionId, sizeof(sessionId)); // TODO: check for collisions.
while (i != end) // Create a new session.
{ boost::shared_ptr<SessionData> sessionData(new SessionData(connData->ReleaseSocket(), sessionId));
SOCKET tmpSock = i->first; m_sessionManager.AddSession(sessionData);
FD_SET(tmpSock, &rdset);
if (tmpSock > maxSock || maxSock == INVALID_SOCKET)
maxSock = tmpSock;
++i;
}
}
if (maxSock == INVALID_SOCKET)
{
Msleep(RECV_TIMEOUT_MSEC); // just sleep if there is no session
} }
else else
{ {
// wait for data // Server is full.
struct timeval timeout; // Create a generic session with Id 0.
timeout.tv_sec = 0; boost::shared_ptr<SessionData> sessionData(new SessionData(connData->ReleaseSocket(), 0));
timeout.tv_usec = RECV_TIMEOUT_MSEC * 1000; // Gracefully close this session.
int selectResult = select(maxSock + 1, &rdset, NULL, NULL, &timeout); SessionError(SessionWrapper(sessionData, boost::shared_ptr<PlayerData>()), ERR_NET_SERVER_FULL);
if (!IS_VALID_SELECT(selectResult))
{
throw ServerException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO());
}
if (selectResult > 0) // one (or more) of the sockets is readable
{
// Check which socket is readable, return the first.
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::iterator i = m_sessionMap.begin();
SocketSessionMap::iterator end = m_sessionMap.end();
while (i != end)
{
SOCKET tmpSock = i->first;
if (FD_ISSET(tmpSock, &rdset))
{
retSock = tmpSock;
break;
}
++i;
}
}
} }
return retSock;
} }
void void
ServerRecvThread::CleanupConnectQueue() ServerLobbyThread::CleanupConnectQueue()
{ {
boost::mutex::scoped_lock lock(m_connectQueueMutex); boost::mutex::scoped_lock lock(m_connectQueueMutex);
@@ -233,155 +293,7 @@ ServerRecvThread::CleanupConnectQueue()
} }
void void
ServerRecvThread::CleanupSessionMap() ServerLobbyThread::SessionError(SessionWrapper session, int errorCode)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
// Sockets will be closed automatically.
m_sessionMap.clear();
}
void
ServerRecvThread::InternalStartGame()
{
// Kick all players which are not fully connected.
RemoveNotEstablishedSessions();
// Set order of players.
AssignPlayerNumbers();
// Initialize the game.
GuiInterface &gui = GetGui();
PlayerDataList playerData = GetPlayerDataList();
// Create EngineFactory
boost::shared_ptr<EngineFactory> factory(new LocalEngineFactory(m_playerConfig)); // LocalEngine erstellen
// Set start data.
StartData startData;
startData.numberOfPlayers = playerData.size();
int tmpDealerPos = 0;
Tools::getRandNumber(0, startData.numberOfPlayers-1, 1, &tmpDealerPos, 0);
// The Player Id is not continuous. Therefore, the start dealer position
// needs to be converted to a player Id, and cannot be directly generated
// as player Id.
PlayerDataList::const_iterator player_i = playerData.begin();
PlayerDataList::const_iterator player_end = playerData.end();
bool randDealerFound = false;
while (player_i != player_end)
{
if ((*player_i)->GetNumber() == tmpDealerPos)
{
// Get ID of the dealer.
startData.startDealerPlayerId = static_cast<unsigned>((*player_i)->GetUniqueId());
randDealerFound = true;
break;
}
++player_i;
}
assert(randDealerFound); // TODO: Throw exception.
SetStartData(startData);
m_game.reset(new Game(&gui, factory, playerData, GetGameData(), GetStartData(), m_curGameId++));
}
void
ServerRecvThread::InternalKickPlayer(unsigned uniqueId)
{
SessionWrapper tmpSession = GetSessionByUniquePlayerId(uniqueId);
SessionError(tmpSession, ERR_NET_PLAYER_KICKED);
}
SessionWrapper
ServerRecvThread::GetSession(SOCKET sock) const
{
SessionWrapper tmpSession;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::const_iterator pos = m_sessionMap.find(sock);
if (pos != m_sessionMap.end())
{
tmpSession = pos->second;
}
return tmpSession;
}
SessionWrapper
ServerRecvThread::GetSessionByPlayerName(const string playerName) const
{
SessionWrapper tmpSession;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::const_iterator session_i = m_sessionMap.begin();
SocketSessionMap::const_iterator session_end = m_sessionMap.end();
while (session_i != session_end)
{
// Check all players which are fully connected.
if (session_i->second.sessionData->GetState() == SessionData::Established)
{
boost::shared_ptr<PlayerData> tmpPlayer(session_i->second.playerData);
assert(tmpPlayer.get());
if (tmpPlayer->GetName() == playerName)
{
tmpSession = session_i->second;
break;
}
}
++session_i;
}
return tmpSession;
}
SessionWrapper
ServerRecvThread::GetSessionByUniquePlayerId(unsigned uniqueId) const
{
SessionWrapper tmpSession;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::const_iterator session_i = m_sessionMap.begin();
SocketSessionMap::const_iterator session_end = m_sessionMap.end();
while (session_i != session_end)
{
// Check all players which are fully connected.
if (session_i->second.sessionData->GetState() == SessionData::Established)
{
boost::shared_ptr<PlayerData> tmpPlayer(session_i->second.playerData);
assert(tmpPlayer.get());
if (tmpPlayer->GetUniqueId() == uniqueId)
{
tmpSession = session_i->second;
break;
}
}
++session_i;
}
return tmpSession;
}
void
ServerRecvThread::AddSession(boost::shared_ptr<SessionData> sessionData)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::iterator pos = m_sessionMap.lower_bound(sessionData->GetSocket());
// If pos points to a pair whose key is equivalent to the socket, this handle
// already exists within the list.
if (pos != m_sessionMap.end() && sessionData->GetSocket() == pos->first)
{
throw ServerException(ERR_SOCK_CONN_EXISTS, 0);
}
m_sessionMap.insert(pos, SocketSessionMap::value_type(sessionData->GetSocket(), SessionWrapper(sessionData, boost::shared_ptr<PlayerData>())));
}
void
ServerRecvThread::SessionError(SessionWrapper session, int errorCode)
{ {
if (session.sessionData.get()) if (session.sessionData.get())
{ {
@@ -391,22 +303,9 @@ ServerRecvThread::SessionError(SessionWrapper session, int errorCode)
} }
void void
ServerRecvThread::RejectNewConnection(boost::shared_ptr<ConnectData> connData) ServerLobbyThread::CloseSessionDelayed(SessionWrapper session)
{ {
// Create a generic session with Id 0. m_sessionManager.RemoveSession(session.sessionData->GetSocket());
boost::shared_ptr<SessionData> sessionData(new SessionData(connData->ReleaseSocket(), 0));
// Gracefully close this session.
SessionError(SessionWrapper(sessionData, boost::shared_ptr<PlayerData>()), ERR_NET_GAME_ALREADY_RUNNING);
}
void
ServerRecvThread::CloseSessionDelayed(SessionWrapper session)
{
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
m_sessionMap.erase(session.sessionData->GetSocket());
}
boost::shared_ptr<PlayerData> tmpPlayerData = session.playerData; boost::shared_ptr<PlayerData> tmpPlayerData = session.playerData;
if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty()) if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty())
@@ -416,7 +315,7 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session)
NetPacketPlayerLeft::Data thisPlayerLeftData; NetPacketPlayerLeft::Data thisPlayerLeftData;
thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId(); thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId();
static_cast<NetPacketPlayerLeft *>(thisPlayerLeft.get())->SetData(thisPlayerLeftData); static_cast<NetPacketPlayerLeft *>(thisPlayerLeft.get())->SetData(thisPlayerLeftData);
SendToAllPlayers(thisPlayerLeft); m_sessionManager.SendToAllSessions(GetSender(), thisPlayerLeft);
GetCallback().SignalNetServerPlayerLeft(tmpPlayerData->GetName()); GetCallback().SignalNetServerPlayerLeft(tmpPlayerData->GetName());
} }
@@ -428,166 +327,7 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session)
} }
void void
ServerRecvThread::RemoveNotEstablishedSessions() ServerLobbyThread::SendError(SOCKET s, int errorCode)
{
SessionList removeList;
SocketSessionMap::iterator session_i = m_sessionMap.begin();
SocketSessionMap::iterator session_end = m_sessionMap.end();
while (session_i != session_end)
{
// Remove all players which are not fully connected.
assert(session_i->second.sessionData.get());
if (session_i->second.sessionData->GetState() != SessionData::Established)
{
// Do not mess with the map within this loop.
// Just store what needs to be removed.
removeList.push_back(session_i->second);
}
++session_i;
}
SessionList::iterator remove_i = removeList.begin();
SessionList::iterator remove_end = removeList.end();
while (remove_i != remove_end)
{
// Inform the players that we are starting without them.
// Gracefully remove them from the server.
SessionError(*remove_i, ERR_NET_GAME_ALREADY_RUNNING);
++remove_i;
}
}
void
ServerRecvThread::RemoveDisconnectedPlayers()
{
// This should only be called between hands.
if (m_game.get())
{
for (int i = 0; i < m_game->getStartQuantityPlayers(); i++)
{
boost::shared_ptr<PlayerInterface> tmpPlayer = m_game->getPlayerArray()[i];
if (!IsPlayerConnected(tmpPlayer->getMyUniqueID()) && tmpPlayer->getMyType() == PLAYER_TYPE_HUMAN)
{
tmpPlayer->setMyCash(0);
tmpPlayer->setMyActiveStatus(false);
tmpPlayer->setNetSessionData(boost::shared_ptr<SessionData>());
}
}
}
}
void
ServerRecvThread::AddComputerPlayer(boost::shared_ptr<PlayerData> player)
{
m_computerPlayers.push_back(player);
}
void
ServerRecvThread::ResetComputerPlayerList()
{
m_computerPlayers.clear();
}
size_t
ServerRecvThread::GetCurNumberOfPlayers() const
{
PlayerDataList playerList = GetPlayerDataList();
return playerList.size();
}
bool
ServerRecvThread::IsPlayerConnected(const string &playerName) const
{
bool retVal = false;
SessionWrapper tmpSession = GetSessionByPlayerName(playerName);
if (tmpSession.sessionData.get() && tmpSession.playerData.get())
retVal = true;
return retVal;
}
bool
ServerRecvThread::IsPlayerConnected(unsigned uniquePlayerId) const
{
bool retVal = false;
SessionWrapper tmpSession = GetSessionByUniquePlayerId(uniquePlayerId);
if (tmpSession.sessionData.get() && tmpSession.playerData.get())
retVal = true;
return retVal;
}
void
ServerRecvThread::SetSessionPlayerData(boost::shared_ptr<SessionData> sessionData, boost::shared_ptr<PlayerData> playerData)
{
assert(playerData.get());
assert(!playerData->GetName().empty());
assert(sessionData.get());
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::iterator pos = m_sessionMap.find(sessionData->GetSocket());
if (pos != m_sessionMap.end())
{
pos->second.playerData = playerData;
// Signal joining player to GUI.
GetCallback().SignalNetServerPlayerJoined(playerData->GetName());
}
}
PlayerDataList
ServerRecvThread::GetPlayerDataList() const
{
PlayerDataList playerList;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::const_iterator session_i = m_sessionMap.begin();
SocketSessionMap::const_iterator session_end = m_sessionMap.end();
while (session_i != session_end)
{
// Get all players which are fully connected.
if (session_i->second.sessionData->GetState() == SessionData::Established)
{
boost::shared_ptr<PlayerData> tmpPlayer(session_i->second.playerData);
assert(tmpPlayer.get());
assert(!tmpPlayer->GetName().empty());
playerList.push_back(tmpPlayer);
}
++session_i;
}
if (!m_computerPlayers.empty())
playerList.insert(playerList.end(), m_computerPlayers.begin(), m_computerPlayers.end());
return playerList;
}
void
ServerRecvThread::AssignPlayerNumbers()
{
int playerNumber = 0;
PlayerDataList playerList = GetPlayerDataList();
PlayerDataList::iterator player_i = playerList.begin();
PlayerDataList::iterator player_end = playerList.end();
while (player_i != player_end)
{
(*player_i)->SetNumber(playerNumber);
++playerNumber;
++player_i;
}
}
void
ServerRecvThread::SendError(SOCKET s, int errorCode)
{ {
boost::shared_ptr<NetPacket> packet(new NetPacketError); boost::shared_ptr<NetPacket> packet(new NetPacketError);
NetPacketError::Data errorData; NetPacketError::Data errorData;
@@ -596,119 +336,54 @@ ServerRecvThread::SendError(SOCKET s, int errorCode)
GetSender().Send(s, packet); GetSender().Send(s, packet);
} }
void bool
ServerRecvThread::SendToAllPlayers(boost::shared_ptr<NetPacket> packet) ServerLobbyThread::IsPlayerConnected(const string &playerName) const
{ {
// This function needs to be thread safe. bool retVal = false;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::iterator i = m_sessionMap.begin(); SessionWrapper tmpSession = m_sessionManager.GetSessionByPlayerName(playerName);
SocketSessionMap::iterator end = m_sessionMap.end();
while (i != end) if (tmpSession.sessionData.get() && tmpSession.playerData.get())
{ retVal = true;
assert(i->second.sessionData.get());
// Send each fully connected client a copy of the packet. return retVal;
if (i->second.sessionData->GetState() == SessionData::Established)
GetSender().Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone()));
++i;
}
}
void
ServerRecvThread::SendToAllButOnePlayers(boost::shared_ptr<NetPacket> packet, SOCKET except)
{
// This function needs to be thread safe.
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::iterator i = m_sessionMap.begin();
SocketSessionMap::iterator end = m_sessionMap.end();
while (i != end)
{
// Send each fully connected client but one a copy of the packet.
if (i->second.sessionData->GetState() == SessionData::Established)
if (i->first != except)
GetSender().Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone()));
++i;
}
} }
ServerCallback & ServerCallback &
ServerRecvThread::GetCallback() ServerLobbyThread::GetCallback()
{ {
return m_gui; return m_gui;
} }
ServerRecvState &
ServerRecvThread::GetState()
{
assert(m_curState);
return *m_curState;
}
void
ServerRecvThread::SetState(ServerRecvState &newState)
{
newState.Init();
m_curState = &newState;
}
SenderThread & SenderThread &
ServerRecvThread::GetSender() ServerLobbyThread::GetSender()
{ {
assert(m_sender.get()); assert(m_sender.get());
return *m_sender; return *m_sender;
} }
ReceiverHelper & ReceiverHelper &
ServerRecvThread::GetReceiver() ServerLobbyThread::GetReceiver()
{ {
assert(m_receiver.get()); assert(m_receiver.get());
return *m_receiver; return *m_receiver;
} }
Game &
ServerRecvThread::GetGame()
{
assert(m_game.get());
return *m_game;
}
const GameData &
ServerRecvThread::GetGameData() const
{
return m_gameData;
}
const StartData &
ServerRecvThread::GetStartData() const
{
return m_startData;
}
void
ServerRecvThread::SetStartData(const StartData &startData)
{
m_startData = startData;
}
bool bool
ServerRecvThread::CheckPassword(const string &password) const ServerLobbyThread::CheckPassword(const string &password) const
{ {
return (password == m_password); return (password == m_password);
} }
ServerSenderCallback & ServerSenderCallback &
ServerRecvThread::GetSenderCallback() ServerLobbyThread::GetSenderCallback()
{ {
assert(m_senderCallback.get()); assert(m_senderCallback.get());
return *m_senderCallback; return *m_senderCallback;
} }
GuiInterface & GuiInterface &
ServerRecvThread::GetGui() ServerLobbyThread::GetGui()
{ {
return m_gui; return m_gui;
} }
+237
View File
@@ -0,0 +1,237 @@
/***************************************************************************
* Copyright (C) 2007 by Lothar May *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <net/sessionmanager.h>
#include <net/senderthread.h>
#include <net/serverexception.h>
#include <net/socket_msg.h>
using namespace std;
SessionManager::SessionManager()
{
}
SessionManager::~SessionManager()
{
Clear();
}
void
SessionManager::AddSession(boost::shared_ptr<SessionData> sessionData)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::iterator pos = m_sessionMap.lower_bound(sessionData->GetSocket());
// If pos points to a pair whose key is equivalent to the socket, this handle
// already exists within the list.
if (pos != m_sessionMap.end() && sessionData->GetSocket() == pos->first)
{
throw ServerException(ERR_SOCK_CONN_EXISTS, 0);
}
m_sessionMap.insert(pos, SessionMap::value_type(sessionData->GetSocket(), SessionWrapper(sessionData, boost::shared_ptr<PlayerData>())));
}
void
SessionManager::SetSessionPlayerData(SOCKET session, boost::shared_ptr<PlayerData> playerData)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::iterator pos = m_sessionMap.find(session);
if (pos != m_sessionMap.end())
pos->second.playerData = playerData;
}
void
SessionManager::RemoveSession(SOCKET session)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
m_sessionMap.erase(session);
}
SessionWrapper
SessionManager::Select(unsigned timeoutMsec)
{
SessionWrapper retSession;
SOCKET maxSock = INVALID_SOCKET;
fd_set rdset;
FD_ZERO(&rdset);
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::iterator i = m_sessionMap.begin();
SessionMap::iterator end = m_sessionMap.end();
while (i != end)
{
SOCKET tmpSock = i->first;
FD_SET(tmpSock, &rdset);
if (tmpSock > maxSock || maxSock == INVALID_SOCKET)
maxSock = tmpSock;
++i;
}
}
if (maxSock == INVALID_SOCKET)
{
Thread::Msleep(timeoutMsec); // just sleep if there is no session
}
else
{
// wait for data
struct timeval timeout;
timeout.tv_sec = timeoutMsec / 1000;
timeout.tv_usec = (timeoutMsec % 1000) * 1000;
int selectResult = select(maxSock + 1, &rdset, NULL, NULL, &timeout);
if (!IS_VALID_SELECT(selectResult))
{
throw ServerException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO());
}
if (selectResult > 0) // one (or more) of the sockets is readable
{
// Check which socket is readable, return the first.
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::iterator i = m_sessionMap.begin();
SessionMap::iterator end = m_sessionMap.end();
while (i != end)
{
if (FD_ISSET(i->first, &rdset))
{
retSession = i->second;
break;
}
++i;
}
}
}
return retSession;
}
SessionWrapper
SessionManager::GetSessionByPlayerName(const string playerName) const
{
SessionWrapper tmpSession;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::const_iterator session_i = m_sessionMap.begin();
SessionMap::const_iterator session_end = m_sessionMap.end();
while (session_i != session_end)
{
// Check all players which are fully connected.
if (session_i->second.sessionData->GetState() == SessionData::Established)
{
boost::shared_ptr<PlayerData> tmpPlayer(session_i->second.playerData);
assert(tmpPlayer.get());
if (tmpPlayer->GetName() == playerName)
{
tmpSession = session_i->second;
break;
}
}
++session_i;
}
return tmpSession;
}
SessionWrapper
SessionManager::GetSessionByUniquePlayerId(unsigned uniqueId) const
{
SessionWrapper tmpSession;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::const_iterator session_i = m_sessionMap.begin();
SessionMap::const_iterator session_end = m_sessionMap.end();
while (session_i != session_end)
{
// Check all players which are fully connected.
if (session_i->second.sessionData->GetState() == SessionData::Established)
{
boost::shared_ptr<PlayerData> tmpPlayer(session_i->second.playerData);
assert(tmpPlayer.get());
if (tmpPlayer->GetUniqueId() == uniqueId)
{
tmpSession = session_i->second;
break;
}
}
++session_i;
}
return tmpSession;
}
void
SessionManager::Clear()
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
// Sockets will be closed automatically.
m_sessionMap.clear();
}
unsigned
SessionManager::GetRawSessionCount()
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
return m_sessionMap.size();
}
void
SessionManager::SendToAllSessions(SenderThread &sender, boost::shared_ptr<NetPacket> packet)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::iterator i = m_sessionMap.begin();
SessionMap::iterator end = m_sessionMap.end();
while (i != end)
{
assert(i->second.sessionData.get());
// Send each fully connected client a copy of the packet.
if (i->second.sessionData->GetState() == SessionData::Established)
sender.Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone()));
++i;
}
}
void
SessionManager::SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr<NetPacket> packet, SOCKET except)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::iterator i = m_sessionMap.begin();
SessionMap::iterator end = m_sessionMap.end();
while (i != end)
{
// Send each fully connected client but one a copy of the packet.
if (i->second.sessionData->GetState() == SessionData::Established)
if (i->first != except)
sender.Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone()));
++i;
}
}
+169 -16
View File
@@ -40,6 +40,12 @@
struct NetPacketHeader; struct NetPacketHeader;
class NetPacketInit;
class NetPacketInitAck;
class NetPacketGameListNew;
class NetPacketGameListUpdate;
class NetPacketCreateGame;
class NetPacketCreateGameAck;
class NetPacketJoinGame; class NetPacketJoinGame;
class NetPacketJoinGameAck; class NetPacketJoinGameAck;
class NetPacketPlayerJoined; class NetPacketPlayerJoined;
@@ -80,6 +86,12 @@ public:
u_int16_t GetType() const; u_int16_t GetType() const;
u_int16_t GetLen() const; u_int16_t GetLen() const;
virtual const NetPacketInit *ToNetPacketInit() const;
virtual const NetPacketInitAck *ToNetPacketInitAck() const;
virtual const NetPacketGameListNew *ToNetPacketGameListNew() const;
virtual const NetPacketGameListUpdate *ToNetPacketGameListUpdate() const;
virtual const NetPacketCreateGame *ToNetPacketCreateGame() const;
virtual const NetPacketCreateGameAck *ToNetPacketCreateGameAck() const;
virtual const NetPacketJoinGame *ToNetPacketJoinGame() const; virtual const NetPacketJoinGame *ToNetPacketJoinGame() const;
virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const; virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const;
virtual const NetPacketPlayerJoined *ToNetPacketPlayerJoined() const; virtual const NetPacketPlayerJoined *ToNetPacketPlayerJoined() const;
@@ -117,7 +129,7 @@ private:
const u_int16_t m_maxSize; const u_int16_t m_maxSize;
}; };
class NetPacketJoinGame : public NetPacket class NetPacketInit : public NetPacket
{ {
public: public:
struct Data struct Data
@@ -128,6 +140,151 @@ public:
std::string password; std::string password;
}; };
NetPacketInit();
virtual ~NetPacketInit();
virtual boost::shared_ptr<NetPacket> Clone() const;
void SetData(const Data &inData);
void GetData(Data &outData) const;
virtual const NetPacketInit *ToNetPacketInit() const;
protected:
virtual void InternalCheck(const NetPacketHeader* data) const;
};
class NetPacketInitAck : public NetPacket
{
public:
struct Data
{
u_int32_t sessionId;
u_int32_t playerId;
};
NetPacketInitAck();
virtual ~NetPacketInitAck();
virtual boost::shared_ptr<NetPacket> Clone() const;
void SetData(const Data &inData);
void GetData(Data &outData) const;
virtual const NetPacketInitAck *ToNetPacketInitAck() const;
protected:
virtual void InternalCheck(const NetPacketHeader* data) const;
};
class NetPacketGameListNew : public NetPacket
{
public:
struct Data
{
u_int32_t gameId;
GameMode gameMode;
std::string gameName;
};
NetPacketGameListNew();
virtual ~NetPacketGameListNew();
virtual boost::shared_ptr<NetPacket> Clone() const;
void SetData(const Data &inData);
void GetData(Data &outData) const;
virtual const NetPacketGameListNew *ToNetPacketGameListNew() const;
protected:
virtual void InternalCheck(const NetPacketHeader* data) const;
};
class NetPacketGameListUpdate : public NetPacket
{
public:
struct Data
{
u_int32_t gameId;
GameMode gameMode;
};
NetPacketGameListUpdate();
virtual ~NetPacketGameListUpdate();
virtual boost::shared_ptr<NetPacket> Clone() const;
void SetData(const Data &inData);
void GetData(Data &outData) const;
virtual const NetPacketGameListUpdate *ToNetPacketGameListUpdate() const;
protected:
virtual void InternalCheck(const NetPacketHeader* data) const;
};
class NetPacketCreateGame : public NetPacket
{
public:
struct Data
{
std::string gameName;
std::string password;
GameData gameData;
};
NetPacketCreateGame();
virtual ~NetPacketCreateGame();
virtual boost::shared_ptr<NetPacket> Clone() const;
void SetData(const Data &inData);
void GetData(Data &outData) const;
virtual const NetPacketCreateGame *ToNetPacketCreateGame() const;
protected:
virtual void InternalCheck(const NetPacketHeader* data) const;
};
class NetPacketCreateGameAck : public NetPacket
{
public:
struct Data
{
u_int32_t gameId;
};
NetPacketCreateGameAck();
virtual ~NetPacketCreateGameAck();
virtual boost::shared_ptr<NetPacket> Clone() const;
void SetData(const Data &inData);
void GetData(Data &outData) const;
virtual const NetPacketCreateGameAck *ToNetPacketCreateGameAck() const;
protected:
virtual void InternalCheck(const NetPacketHeader* data) const;
};
class NetPacketJoinGame : public NetPacket
{
public:
struct Data
{
u_int32_t gameId;
std::string password;
};
NetPacketJoinGame(); NetPacketJoinGame();
virtual ~NetPacketJoinGame(); virtual ~NetPacketJoinGame();
@@ -148,10 +305,6 @@ class NetPacketJoinGameAck : public NetPacket
public: public:
struct Data struct Data
{ {
u_int32_t sessionId;
u_int16_t yourPlayerUniqueId;
PlayerType ptype;
PlayerRights prights;
GameData gameData; GameData gameData;
}; };
@@ -175,7 +328,7 @@ class NetPacketPlayerJoined : public NetPacket
public: public:
struct Data struct Data
{ {
u_int16_t playerId; u_int32_t playerId;
PlayerType ptype; PlayerType ptype;
PlayerRights prights; PlayerRights prights;
std::string playerName; std::string playerName;
@@ -201,7 +354,7 @@ class NetPacketPlayerLeft : public NetPacket
public: public:
struct Data struct Data
{ {
u_int16_t playerId; u_int32_t playerId;
}; };
NetPacketPlayerLeft(); NetPacketPlayerLeft();
@@ -224,7 +377,7 @@ class NetPacketKickPlayer : public NetPacket
public: public:
struct Data struct Data
{ {
u_int16_t playerId; u_int32_t playerId;
}; };
NetPacketKickPlayer(); NetPacketKickPlayer();
@@ -264,7 +417,7 @@ public:
struct PlayerSlot struct PlayerSlot
{ {
unsigned playerId; u_int32_t playerId;
}; };
typedef std::list<PlayerSlot> PlayerSlotList; typedef std::list<PlayerSlot> PlayerSlotList;
@@ -319,7 +472,7 @@ public:
struct Data struct Data
{ {
GameState gameState; GameState gameState;
u_int16_t playerId; u_int32_t playerId;
}; };
NetPacketPlayersTurn(); NetPacketPlayersTurn();
@@ -368,7 +521,7 @@ public:
struct Data struct Data
{ {
GameState gameState; GameState gameState;
u_int16_t playerId; u_int32_t playerId;
PlayerAction playerAction; PlayerAction playerAction;
u_int32_t totalPlayerBet; u_int32_t totalPlayerBet;
u_int32_t playerMoney; u_int32_t playerMoney;
@@ -490,7 +643,7 @@ class NetPacketAllInShowCards : public NetPacket
public: public:
struct PlayerCards struct PlayerCards
{ {
u_int16_t playerId; u_int32_t playerId;
u_int16_t cards[2]; u_int16_t cards[2];
}; };
@@ -521,7 +674,7 @@ class NetPacketEndOfHandShowCards : public NetPacket
public: public:
struct PlayerResult struct PlayerResult
{ {
u_int16_t playerId; u_int32_t playerId;
u_int16_t cards[2]; u_int16_t cards[2];
u_int16_t bestHandPos[5]; u_int16_t bestHandPos[5];
u_int32_t valueOfCards; u_int32_t valueOfCards;
@@ -556,7 +709,7 @@ class NetPacketEndOfHandHideCards : public NetPacket
public: public:
struct Data struct Data
{ {
u_int16_t playerId; u_int32_t playerId;
u_int32_t moneyWon; u_int32_t moneyWon;
u_int32_t playerMoney; u_int32_t playerMoney;
}; };
@@ -581,7 +734,7 @@ class NetPacketEndOfGame : public NetPacket
public: public:
struct Data struct Data
{ {
u_int16_t winnerPlayerId; u_int32_t winnerPlayerId;
}; };
NetPacketEndOfGame(); NetPacketEndOfGame();
@@ -627,7 +780,7 @@ class NetPacketChatText : public NetPacket
public: public:
struct Data struct Data
{ {
u_int16_t playerId; u_int32_t playerId;
std::string text; std::string text;
}; };
+1 -1
View File
@@ -124,7 +124,7 @@ protected:
private: private:
u_int16_t m_curUniquePlayerId; u_int32_t m_curUniquePlayerId;
static boost::thread_specific_ptr<ServerRecvStateInit> Ptr; static boost::thread_specific_ptr<ServerRecvStateInit> Ptr;
}; };
+17 -92
View File
@@ -21,119 +21,70 @@
#ifndef _SERVERRECVTHREAD_H_ #ifndef _SERVERRECVTHREAD_H_
#define _SERVERRECVTHREAD_H_ #define _SERVERRECVTHREAD_H_
#include <core/thread.h>
#include <net/connectdata.h> #include <net/connectdata.h>
#include <net/sessiondata.h> #include <net/sessionmanager.h>
#include <net/netpacket.h>
#include <gui/guiinterface.h> #include <gui/guiinterface.h>
#include <gamedata.h> #include <gamedata.h>
#include <deque> #include <deque>
#include <map>
#include <list> #include <list>
#include <string>
#include <boost/shared_ptr.hpp>
#include <core/boost/timer.hpp> #include <core/boost/timer.hpp>
#define RECEIVER_THREAD_TERMINATE_TIMEOUT 200 #define RECEIVER_THREAD_TERMINATE_TIMEOUT 200
class ServerRecvState;
class SenderThread; class SenderThread;
class ReceiverHelper; class ReceiverHelper;
class ServerSenderCallback; class ServerSenderCallback;
class NetPacket;
class ConfigFile; class ConfigFile;
struct GameData; struct GameData;
class Game; class Game;
struct SessionWrapper class ServerLobbyThread : public Thread
{
SessionWrapper() {}
SessionWrapper(boost::shared_ptr<SessionData> s, boost::shared_ptr<PlayerData> p)
: sessionData(s), playerData(p) {}
boost::shared_ptr<SessionData> sessionData;
boost::shared_ptr<PlayerData> playerData;
};
class ServerRecvThread : public Thread
{ {
public: public:
ServerRecvThread(GuiInterface &gui, ConfigFile *playerConfig); ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig);
virtual ~ServerRecvThread(); virtual ~ServerLobbyThread();
void Init(const std::string &pwd, const GameData &gameData); void Init(const std::string &pwd);
void AddConnection(boost::shared_ptr<ConnectData> data); void AddConnection(boost::shared_ptr<ConnectData> data);
void AddNotification(unsigned message, const std::string &param);
u_int32_t GetNextUniquePlayerId();
ServerCallback &GetCallback(); ServerCallback &GetCallback();
void SendError(SOCKET s, int errorCode);
void SendToAllPlayers(boost::shared_ptr<NetPacket> packet);
void SendToAllButOnePlayers(boost::shared_ptr<NetPacket> packet, SOCKET except);
Game &GetGame();
protected: protected:
struct Notification
{
Notification(unsigned m, std::string p)
: message(m), param(p) {}
unsigned message;
std::string param;
};
typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue; typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue;
typedef std::map<SOCKET, SessionWrapper> SocketSessionMap;
typedef std::list<SessionWrapper> SessionList; typedef std::list<SessionWrapper> SessionList;
typedef std::deque<Notification> NotificationQueue;
typedef std::list<std::pair<boost::microsec_timer, boost::shared_ptr<SessionData> > > CloseSessionList; typedef std::list<std::pair<boost::microsec_timer, boost::shared_ptr<SessionData> > > CloseSessionList;
// Main function of the thread. // Main function of the thread.
virtual void Main(); virtual void Main();
void NotificationLoop(); void ProcessLoop();
void HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket);
void HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket);
void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket);
void CloseSessionLoop(); void CloseSessionLoop();
void HandleNewConnection(boost::shared_ptr<ConnectData> connData);
SOCKET Select(); SOCKET Select();
void CleanupConnectQueue(); void CleanupConnectQueue();
void CleanupSessionMap(); void CleanupSessionMap();
void InternalStartGame();
void InternalKickPlayer(unsigned uniqueId);
SessionWrapper GetSession(SOCKET sock) const;
SessionWrapper GetSessionByPlayerName(const std::string playerName) const;
SessionWrapper GetSessionByUniquePlayerId(unsigned uniqueId) const;
void AddSession(boost::shared_ptr<SessionData> sessionData); // new Sessions have no player data
void SessionError(SessionWrapper session, int errorCode); void SessionError(SessionWrapper session, int errorCode);
void RejectNewConnection(boost::shared_ptr<ConnectData> connData);
void CloseSessionDelayed(SessionWrapper session); void CloseSessionDelayed(SessionWrapper session);
void RemoveNotEstablishedSessions(); void SendError(SOCKET s, int errorCode);
void RemoveDisconnectedPlayers();
void AddComputerPlayer(boost::shared_ptr<PlayerData> player);
void ResetComputerPlayerList();
size_t GetCurNumberOfPlayers() const;
bool IsPlayerConnected(const std::string &playerName) const; bool IsPlayerConnected(const std::string &playerName) const;
bool IsPlayerConnected(unsigned uniquePlayerId) const;
void SetSessionPlayerData(boost::shared_ptr<SessionData> sessionData, boost::shared_ptr<PlayerData> playerData);
PlayerDataList GetPlayerDataList() const;
void AssignPlayerNumbers();
ServerRecvState &GetState();
void SetState(ServerRecvState &newState);
SenderThread &GetSender(); SenderThread &GetSender();
ReceiverHelper &GetReceiver(); ReceiverHelper &GetReceiver();
const GameData &GetGameData() const;
const StartData &GetStartData() const;
void SetStartData(const StartData &startData);
bool CheckPassword(const std::string &password) const; bool CheckPassword(const std::string &password) const;
ServerSenderCallback &GetSenderCallback(); ServerSenderCallback &GetSenderCallback();
@@ -143,45 +94,19 @@ private:
ConnectQueue m_connectQueue; ConnectQueue m_connectQueue;
mutable boost::mutex m_connectQueueMutex; mutable boost::mutex m_connectQueueMutex;
ServerRecvState *m_curState;
NotificationQueue m_notificationQueue; SessionManager m_sessionManager;
mutable boost::mutex m_notificationQueueMutex;
SocketSessionMap m_sessionMap;
mutable boost::mutex m_sessionMapMutex;
PlayerDataList m_computerPlayers;
CloseSessionList m_closeSessionList; CloseSessionList m_closeSessionList;
std::auto_ptr<ReceiverHelper> m_receiver; std::auto_ptr<ReceiverHelper> m_receiver;
std::auto_ptr<SenderThread> m_sender; std::auto_ptr<SenderThread> m_sender;
std::auto_ptr<Game> m_game;
GameData m_gameData;
StartData m_startData;
unsigned m_curGameId;
std::auto_ptr<ServerSenderCallback> m_senderCallback; std::auto_ptr<ServerSenderCallback> m_senderCallback;
std::string m_password;
GuiInterface &m_gui; GuiInterface &m_gui;
std::string m_password;
ConfigFile *m_playerConfig; ConfigFile *m_playerConfig;
u_int32_t m_curUniquePlayerId;
friend class ServerRecvStateInit;
friend class AbstractServerRecvStateReceiving;
friend class AbstractServerRecvStateRunning;
friend class ServerRecvStateStartGame;
friend class ServerRecvStateStartHand;
friend class ServerRecvStateStartRound;
friend class ServerRecvStateWaitPlayerAction;
friend class ServerRecvStateComputerAction;
friend class ServerRecvStateShowCardsDelay;
friend class ServerRecvStateDealCardsDelay;
friend class ServerRecvStateNextHandDelay;
friend class ServerRecvStateNextGameDelay;
}; };
#endif #endif
-1
View File
@@ -21,7 +21,6 @@
#ifndef _SESSIONDATA_H_ #ifndef _SESSIONDATA_H_
#define _SESSIONDATA_H_ #define _SESSIONDATA_H_
#include <playerdata.h>
#include <net/socket_helper.h> #include <net/socket_helper.h>
#include <string> #include <string>
+73
View File
@@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (C) 2007 by Lothar May *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/* Thread safe server session manager. */
#ifndef _SESSIONMANAGER_H_
#define _SESSIONMANAGER_H_
#include <net/sessiondata.h>
#include <playerdata.h>
#include <core/thread.h>
#include <map>
#include <string>
class SenderThread;
class NetPacket;
struct SessionWrapper
{
SessionWrapper() {}
SessionWrapper(boost::shared_ptr<SessionData> s, boost::shared_ptr<PlayerData> p)
: sessionData(s), playerData(p) {}
boost::shared_ptr<SessionData> sessionData;
boost::shared_ptr<PlayerData> playerData;
};
class SessionManager
{
public:
SessionManager();
virtual ~SessionManager();
void AddSession(boost::shared_ptr<SessionData> sessionData); // new Sessions have no player data
void SetSessionPlayerData(SOCKET session, boost::shared_ptr<PlayerData> playerData);
void RemoveSession(SOCKET session);
SessionWrapper Select(unsigned timeoutMsec);
SessionWrapper GetSessionByPlayerName(const std::string playerName) const;
SessionWrapper GetSessionByUniquePlayerId(unsigned uniqueId) const;
void Clear();
unsigned GetRawSessionCount();
void SendToAllSessions(SenderThread &sender, boost::shared_ptr<NetPacket> packet);
void SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr<NetPacket> packet, SOCKET except);
protected:
typedef std::map<SOCKET, SessionWrapper> SessionMap;
private:
SessionMap m_sessionMap;
mutable boost::mutex m_sessionMapMutex;
};
#endif
+7 -6
View File
@@ -51,12 +51,13 @@
#define ERR_NET_INVALID_PLAYER_NAME 107 #define ERR_NET_INVALID_PLAYER_NAME 107
#define ERR_NET_INVALID_PLAYER_CARDS 108 #define ERR_NET_INVALID_PLAYER_CARDS 108
#define ERR_NET_INVALID_PLAYER_RESULTS 109 #define ERR_NET_INVALID_PLAYER_RESULTS 109
#define ERR_NET_INVALID_CHAT_TEXT 110 #define ERR_NET_INVALID_GAME_NAME 110
#define ERR_NET_UNKNOWN_PLAYER_ID 111 #define ERR_NET_INVALID_CHAT_TEXT 111
#define ERR_NET_INVALID_ROUND 112 #define ERR_NET_UNKNOWN_PLAYER_ID 112
#define ERR_NET_PLAYER_KICKED 113 #define ERR_NET_INVALID_ROUND 113
#define ERR_NET_INVALID_PLAYER_COUNT 114 #define ERR_NET_PLAYER_KICKED 114
#define ERR_NET_PLAYER_NOT_IN_GAME 115 #define ERR_NET_INVALID_PLAYER_COUNT 115
#define ERR_NET_PLAYER_NOT_IN_GAME 116
// This is an internal message which is not reported. // This is an internal message which is not reported.
#define MSG_SOCK_INTERNAL_PENDING 0 #define MSG_SOCK_INTERNAL_PENDING 0