gamnit: move up UDP discovery logic from Tinks! to the lib
[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
72 clients.add client
73 end
74
75 if dedicated and clients.is_empty then
76 # No clients, sleep for a while
77 nanosleep(0, 10000000)
78 return turn
79 end
80
81 # Update clients
82 broadcast turn
83
84 # Get orders from players
85 var clients_to_remove = new Array[RemoteClient]
86 for client in clients do
87 if not client.socket.poll_in then continue
88
89 var orders = client.reader.deserialize
90 var errors = client.reader.errors
91 if errors.not_empty then
92 print_error "Comm Error: (Dropping client) {errors.join(", ")}"
93 clients_to_remove.add client
94 else if not orders isa Array[TOrder] then
95 if orders == null then
96 print_error "Comm Error: (Dropping client) Unexpected null"
97 else print_error "Comm Error: (Dropping client) Unexpected {orders.class_name}"
98 # TODO remove code duplication when we have ? or an equivalent
99
100 clients_to_remove.add client
101 else
102 client.player.orders.add_all orders
103 end
104 end
105
106 for client in clients_to_remove do clients.remove client
107
108 return turn
109 end
110 end