58555aec0d118fb26c221714c0e5f8b1bae3d88a
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Server to host multiplayer games
18 import gamnit
::network
23 redef class RemoteClient
24 # `Player` associated to this client
25 var player
= new Player
29 # `UDPSocket` to which clients send discovery requests
30 var discovery_socket
: UDPSocket do
33 s
.bind
(null, discovery_port
)
38 var game
= new TGame is lazy
, writable
40 # Is this a dedicated server
43 # Create and run a new `Game`
49 print
"Server: Setup game"
53 print
"Server: Starting play"
57 # Run the server logic over a single turn
63 var turn
= game
.do_turn
65 # Respond to discovery requests
67 var ptr
= new Ref[nullable SocketAddress](null)
68 var read
= discovery_socket
.recv_from
(1024, ptr
)
70 # No sender means there is no request (an error would also do it)
72 if sender
== null then break
74 var words
= read
.split
(" ")
75 if words
.length
!= 2 or words
[0] != "Server?" or words
[1] != handshake_app_name
then
76 print
"Server Warning: Rejected discovery request '{read}'"
80 discovery_socket
.send_to
(sender
.address
, sender
.port
,
81 "Server! {handshake_app_name} {self.port}")
85 var new_clients
= accept_clients
86 for client
in new_clients
do
87 # Register player and spawn first tank
88 game
.players
.add client
.player
89 turn
.spawn_tank client
.player
91 client
.writer
.serialize game
92 client
.writer
.serialize client
.player
98 if dedicated
and clients
.is_empty
then
99 # No clients, sleep for a while
100 nanosleep
(0, 10000000)
107 # Get orders from players
108 var clients_to_remove
= new Array[RemoteClient]
109 for client
in clients
do
110 if not client
.socket
.poll_in
then continue
112 var orders
= client
.reader
.deserialize
113 var errors
= client
.reader
.errors
114 if errors
.not_empty
then
115 print_error
"Comm Error: (Dropping client) {errors.join(", ")}"
116 clients_to_remove
.add client
117 else if not orders
isa Array[TOrder] then
118 if orders
== null then
119 print_error
"Comm Error: (Dropping client) Unexpected null"
120 else print_error
"Comm Error: (Dropping client) Unexpected {orders.class_name}"
121 # TODO remove code duplication when we have ? or an equivalent
123 clients_to_remove
.add client
125 client
.player
.orders
.add_all orders
129 for client
in clients_to_remove
do clients
.remove client