gamnit: add more options to `accept_clients` & `broadcast`
[nit.git] / contrib / tinks / src / server / server.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Server to host multiplayer games
16 module server
17
18 import gamnit::network
19
20 import game
21 import common
22
23 redef class RemoteClient
24 # `Player` associated to this client
25 var player = new Player
26 end
27
28 redef class Server
29
30 # The current game
31 var game = new TGame is lazy, writable
32
33 # Is this a dedicated server
34 var dedicated = false
35
36 # Create and run a new `Game`
37 fun run_dedicated
38 do
39 dedicated = true
40
41 # Setup game
42 print "Server: Setup game"
43 game
44
45 # Play
46 print "Server: Starting play"
47 loop do_turn
48 end
49
50 # Run the server logic over a single turn
51 fun do_turn: TTurn
52 do
53 var game = game
54
55 # Do game logic
56 var turn = game.do_turn
57
58 # Respond to discovery requests sent over UDP
59 answer_discovery_requests
60
61 # Setup clients
62 var new_clients = accept_clients
63 for client in new_clients do
64 # Register player and spawn first tank
65 game.players.add client.player
66 turn.spawn_tank client.player
67
68 client.writer.serialize game
69 client.writer.serialize client.player
70 client.socket.flush
71 end
72
73 if dedicated and clients.is_empty then
74 # No clients, sleep for a while
75 nanosleep(0, 10000000)
76 return turn
77 end
78
79 # Update clients
80 broadcast turn
81
82 # Get orders from players
83 var clients_to_remove = new Array[RemoteClient]
84 for client in clients do
85 if not client.socket.poll_in then continue
86
87 var orders = client.reader.deserialize
88 var errors = client.reader.errors
89 if errors.not_empty then
90 print_error "Comm Error: (Dropping client) {errors.join(", ")}"
91 clients_to_remove.add client
92 else if not orders isa Array[TOrder] then
93 if orders == null then
94 print_error "Comm Error: (Dropping client) Unexpected null"
95 else print_error "Comm Error: (Dropping client) Unexpected {orders.class_name}"
96 # TODO remove code duplication when we have ? or an equivalent
97
98 clients_to_remove.add client
99 else
100 client.player.orders.add_all orders
101 end
102 end
103
104 for client in clients_to_remove do clients.remove client
105
106 return turn
107 end
108 end