From: Alexis Laferrière Date: Fri, 3 Jul 2015 21:14:36 +0000 (-0400) Subject: contrib/tinks: add the server X-Git-Tag: v0.7.8~106^2~2^2~8 X-Git-Url: http://nitlanguage.org contrib/tinks: add the server Signed-off-by: Alexis Laferrière --- diff --git a/contrib/tinks/src/common.nit b/contrib/tinks/src/common.nit new file mode 100644 index 0000000..8aae159 --- /dev/null +++ b/contrib/tinks/src/common.nit @@ -0,0 +1,29 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Services common to the client and server +module common + +import gamnit::network + +redef class Sys + # Name of this app + redef fun handshake_app_name do return "tinks" + + # Default listening port of the server + fun default_listening_port: Int do return 18721 + + # Port to which clients send discovery requests + fun discovery_port: Int do return 18722 +end diff --git a/contrib/tinks/src/server/dedicated.nit b/contrib/tinks/src/server/dedicated.nit new file mode 100644 index 0000000..db7bd9c --- /dev/null +++ b/contrib/tinks/src/server/dedicated.nit @@ -0,0 +1,24 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Dedicated server program +module dedicated + +import server + +var port = sys.default_listening_port +if args.length > 0 then port = args[0].to_i + +var server = new Server(port) +server.run_dedicated diff --git a/contrib/tinks/src/server/server.nit b/contrib/tinks/src/server/server.nit new file mode 100644 index 0000000..a74b727 --- /dev/null +++ b/contrib/tinks/src/server/server.nit @@ -0,0 +1,131 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Server to host multiplayer games +module server + +import gamnit::network + +import game +import common + +redef class RemoteClient + # `Player` associated to this client + var player = new Player +end + +redef class Server + # `UDPSocket` to which clients send discovery requests + var discovery_socket: UDPSocket do + var s = new UDPSocket + s.blocking = false + s.bind(null, discovery_port) + return s + end + + # The current game + var game = new TGame is lazy, writable + + # Is this a dedicated server + var dedicated = false + + # Create and run a new `Game` + fun run_dedicated + do + dedicated = true + + # Setup game + print "Server: Setup game" + game + + # Play + print "Server: Starting play" + loop do_turn + end + + # Run the server logic over a single turn + fun do_turn: TTurn + do + var game = game + + # Do game logic + var turn = game.do_turn + + # Respond to discovery requests + loop + var ptr = new Ref[nullable SocketAddress](null) + var read = discovery_socket.recv_from(1024, ptr) + + # No sender means there is no request (an error would also do it) + var sender = ptr.item + if sender == null then break + + var words = read.split(" ") + if words.length != 2 or words[0] != "Server?" or words[1] != handshake_app_name then + print "Server Warning: Rejected discovery request '{read}'" + continue + end + + discovery_socket.send_to(sender.address, sender.port, + "Server! {handshake_app_name} {self.port}") + end + + # Setup clients + var new_clients = accept_clients + for client in new_clients do + # Register player and spawn first tank + game.players.add client.player + turn.spawn_tank client.player + + client.writer.serialize game + client.writer.serialize client.player + client.socket.flush + + clients.add client + end + + if dedicated and clients.is_empty then + # No clients, sleep for a while + nanosleep(0, 10000000) + return turn + end + + # Update clients + broadcast turn + + # Get orders from players + var clients_to_remove = new Array[RemoteClient] + for client in clients do + var orders = client.reader.deserialize + var errors = client.reader.errors + if errors.not_empty then + print_error "Comm Error: (Dropping client) {errors.join(", ")}" + clients_to_remove.add client + else if not orders isa Array[TOrder] then + if orders == null then + print_error "Comm Error: (Dropping client) Unexpected null" + else print_error "Comm Error: (Dropping client) Unexpected {orders.class_name}" + # TODO remove code duplication when we have ? or an equivalent + + clients_to_remove.add client + else + client.player.orders.add_all orders + end + end + + for client in clients_to_remove do clients.remove client + + return turn + end +end