From 3358cc6608ff21e127b64f8a654b5b09b33731ca Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 13 Nov 2022 10:37:46 +0100 Subject: [PATCH] Parse start info on server side --- docs/v0.0.1.md | 2 +- examples/04_player_infos.rb | 2 +- lib/game_client.rb | 2 +- lib/game_server.rb | 7 +- lib/models/client_info.rb | 141 ++++++++++++++++++++++++++++++++++++ lib/models/player.rb | 33 +++++++++ lib/models/start_info.rb | 129 +++++++++++++++++++++++++++++++++ lib/teeworlds_client.rb | 4 +- lib/teeworlds_server.rb | 2 +- 9 files changed, 315 insertions(+), 7 deletions(-) create mode 100644 lib/models/client_info.rb create mode 100644 lib/models/start_info.rb diff --git a/docs/v0.0.1.md b/docs/v0.0.1.md index 267bb57..74e494f 100644 --- a/docs/v0.0.1.md +++ b/docs/v0.0.1.md @@ -49,7 +49,7 @@ Reimplement your on on_connected logic and cancle the default one ```ruby client.on_connected do |ctx| - ctx.client.send_msg_startinfo + ctx.client.send_msg_start_info ctx.cancle end ``` diff --git a/examples/04_player_infos.rb b/examples/04_player_infos.rb index fefbf36..aad3c27 100755 --- a/examples/04_player_infos.rb +++ b/examples/04_player_infos.rb @@ -9,7 +9,7 @@ client = TeeworldsClient.new(verbose: true) # all keys are optional # if not provided they will fall back to the default value -client.set_startinfo( +client.set_start_info( name: 'ruby gamer', clan: '', country: -1, diff --git a/lib/game_client.rb b/lib/game_client.rb index 2ad63e6..57d1980 100644 --- a/lib/game_client.rb +++ b/lib/game_client.rb @@ -105,7 +105,7 @@ class GameClient context.verify return if context.cancled? end - @client.send_msg_startinfo + @client.send_msg_start_info end def on_disconnect diff --git a/lib/game_server.rb b/lib/game_server.rb index dc889ff..db6debb 100644 --- a/lib/game_server.rb +++ b/lib/game_server.rb @@ -4,6 +4,7 @@ require_relative 'models/map' require_relative 'models/server_info' require_relative 'models/server_settings' require_relative 'models/game_info' +require_relative 'models/start_info' class GameServer attr_accessor :pred_game_tick, :ack_game_tick, :map @@ -42,13 +43,17 @@ class GameServer @server.send_ready(packet.client) end - def on_startinfo(_chunk, packet) + def on_start_info(chunk, packet) # vanilla server sends 3 chunks here usually # - vote clear options # - tune params # - ready to enter # # We only send ready to enter for now + info = StartInfo.new(chunk.data[1..]) + packet.client.player.set_start_info(info) + info_str = info.to_s + puts "got start info: #{info_str}" if @verbose @server.send_ready_to_enter(packet.client) end diff --git a/lib/models/client_info.rb b/lib/models/client_info.rb new file mode 100644 index 0000000..34bf134 --- /dev/null +++ b/lib/models/client_info.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +require_relative '../packer' + +# TODO: use this on client side too + +## +# ClientInfo +# +# Server -> Client +class ClientInfo + def initialize(hash_or_raw) + if hash_or_raw.instance_of?(Hash) + init_hash(hash_or_raw) + else + init_raw(hash_or_raw) + end + end + + def init_raw(data) + u = Unpacker.new(data) + @client_id = u.get_int + @local = u.get_int + @team = u.get_int + @name = u.get_string + @clan = u.get_string + @country = u.get_int + @body = u.get_string + @marking = u.get_string + @decoration = u.get_string + @hands = u.get_string + @feet = u.get_string + @eyes = u.get_string + @custom_color_body = u.get_int + @custom_color_marking = u.get_int + @custom_color_decoration = u.get_int + @custom_color_hands = u.get_int + @custom_color_feet = u.get_int + @custom_color_eyes = u.get_int + @color_body = u.get_int + @color_marking = u.get_int + @color_decoration = u.get_int + @color_hands = u.get_int + @color_feet = u.get_int + @color_eyes = u.get_int + @silent = u.get_int + end + + def init_hash(attr) + @client_id = attr[:client_id] || -1 + @local = attr[:local] || 0 + @team = attr[:team] || 0 + @name = attr[:name] || 'ruby gamer' + @clan = attr[:clan] || '' + @country = attr[:country] || -1 + @body = attr[:body] || 'spiky' + @marking = attr[:marking] || 'duodonny' + @decoration = attr[:decoration] || '' + @hands = attr[:hands] || 'standard' + @feet = attr[:feet] || 'standard' + @eyes = attr[:eyes] || 'standard' + @custom_color_body = attr[:custom_color_body] || 0 + @custom_color_marking = attr[:custom_color_marking] || 0 + @custom_color_decoration = attr[:custom_color_decoration] || 0 + @custom_color_hands = attr[:custom_color_hands] || 0 + @custom_color_feet = attr[:custom_color_feet] || 0 + @custom_color_eyes = attr[:custom_color_eyes] || 0 + @color_body = attr[:color_body] || 0 + @color_marking = attr[:color_marking] || 0 + @color_decoration = attr[:color_decoration] || 0 + @color_hands = attr[:color_hands] || 0 + @color_feet = attr[:color_feet] || 0 + @color_eyes = attr[:color_eyes] || 0 + @silent = attr[:silent] || 0 + end + + # TODO: do we need this? + def to_h + { + client_id: @client_id, + local: @local, + team: @team, + name: @name, + clan: @clan, + country: @country, + body: @body, + marking: @marking, + decoration: @decoration, + hands: @hands, + feet: @feet, + eyes: @eyes, + custom_color_body: @custom_color_body, + custom_color_marking: @custom_color_marking, + custom_color_decoration: @custom_color_decoration, + custom_color_hands: @custom_color_hands, + custom_color_feet: @custom_color_feet, + custom_color_eyes: @custom_color_eyes, + color_body: @color_body, + color_marking: @color_marking, + color_decoration: @color_decoration, + color_hands: @color_hands, + color_feet: @color_feet, + color_eyes: @color_eyes, + silent: @silent + } + end + + # basically to_network + # int array the server sends to the client + def to_a + Packer.pack_int(@client_id) + + Packer.pack_int(@local) + + Packer.pack_int(@team) + + Packer.pack_str(@name) + + Packer.pack_str(@clan) + + Packer.pack_int(@country) + + Packer.pack_str(@body) + + Packer.pack_str(@marking) + + Packer.pack_str(@decoration) + + Packer.pack_str(@hands) + + Packer.pack_str(@feet) + + Packer.pack_str(@eyes) + + Packer.pack_int(@custom_color_body) + + Packer.pack_int(@custom_color_marking) + + Packer.pack_int(@custom_color_decoration) + + Packer.pack_int(@custom_color_hands) + + Packer.pack_int(@custom_color_feet) + + Packer.pack_int(@custom_color_eyes) + + Packer.pack_int(@color_body) + + Packer.pack_int(@color_marking) + + Packer.pack_int(@color_decoration) + + Packer.pack_int(@color_hands) + + Packer.pack_int(@color_feet) + + Packer.pack_int(@color_eyes) + + Packer.pack_int(@silent) + end + + def to_s + to_h + end +end diff --git a/lib/models/player.rb b/lib/models/player.rb index e8af37d..67bbcc2 100644 --- a/lib/models/player.rb +++ b/lib/models/player.rb @@ -16,4 +16,37 @@ class Player @score = data[:score] || 0 end + + def set_start_info(start_info) + raise "expected: StartInfo got: #{start_info.class}" unless start_info.instance_of?(StartInfo) + + start_info = start_info.to_h + @name = start_info[:name] + @clan = start_info[:clan] + @country = start_info[:country] + @skin_parts = [ + start_info[:body], + start_info[:marking], + start_info[:decoration], + start_info[:hands], + start_info[:feet], + start_info[:eyes] + ] + @skin_custom_colors = [ + start_info[:custom_color_body], + start_info[:custom_color_marking], + start_info[:custom_color_decoration], + start_info[:custom_color_hands], + start_info[:custom_color_feet], + start_info[:custom_color_eyes] + ] + @skin_colors = [ + start_info[:color_body], + start_info[:color_marking], + start_info[:color_decoration], + start_info[:color_hands], + start_info[:color_feet], + start_info[:color_eyes] + ] + end end diff --git a/lib/models/start_info.rb b/lib/models/start_info.rb new file mode 100644 index 0000000..e159d44 --- /dev/null +++ b/lib/models/start_info.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require_relative '../packer' + +# TODO: use this on the client side instead of the other hash + +## +# StartInfo +# +# Client -> Server +class StartInfo + attr_accessor :name, :clan, :country, :body, :marking, :decoration, :hands, :feet, :eyes, + :custom_color_body, :custom_color_marking, :custom_color_decoration, + :custom_color_hands, :custom_color_feet, :custom_color_eyes, + :color_body, :color_marking, :color_decoration, :color_hands, :color_feet, :color_eyes + + def initialize(hash_or_raw) + if hash_or_raw.instance_of?(Hash) + init_hash(hash_or_raw) + else + init_raw(hash_or_raw) + end + end + + def init_raw(data) + u = Unpacker.new(data) + @name = u.get_string + @clan = u.get_string + @country = u.get_int + @body = u.get_string + @marking = u.get_string + @decoration = u.get_string + @hands = u.get_string + @feet = u.get_string + @eyes = u.get_string + @custom_color_body = u.get_int + @custom_color_marking = u.get_int + @custom_color_decoration = u.get_int + @custom_color_hands = u.get_int + @custom_color_feet = u.get_int + @custom_color_eyes = u.get_int + @color_body = u.get_int + @color_marking = u.get_int + @color_decoration = u.get_int + @color_hands = u.get_int + @color_feet = u.get_int + @color_eyes = u.get_int + end + + def init_hash(attr) + @name = attr[:name] || 'ruby gamer' + @clan = attr[:clan] || '' + @country = attr[:country] || -1 + @body = attr[:body] || 'spiky' + @marking = attr[:marking] || 'duodonny' + @decoration = attr[:decoration] || '' + @hands = attr[:hands] || 'standard' + @feet = attr[:feet] || 'standard' + @eyes = attr[:eyes] || 'standard' + @custom_color_body = attr[:custom_color_body] || 0 + @custom_color_marking = attr[:custom_color_marking] || 0 + @custom_color_decoration = attr[:custom_color_decoration] || 0 + @custom_color_hands = attr[:custom_color_hands] || 0 + @custom_color_feet = attr[:custom_color_feet] || 0 + @custom_color_eyes = attr[:custom_color_eyes] || 0 + @color_body = attr[:color_body] || 0 + @color_marking = attr[:color_marking] || 0 + @color_decoration = attr[:color_decoration] || 0 + @color_hands = attr[:color_hands] || 0 + @color_feet = attr[:color_feet] || 0 + @color_eyes = attr[:color_eyes] || 0 + end + + def to_h + { + name: @name, + clan: @clan, + country: @country, + body: @body, + marking: @marking, + decoration: @decoration, + hands: @hands, + feet: @feet, + eyes: @eyes, + custom_color_body: @custom_color_body, + custom_color_marking: @custom_color_marking, + custom_color_decoration: @custom_color_decoration, + custom_color_hands: @custom_color_hands, + custom_color_feet: @custom_color_feet, + custom_color_eyes: @custom_color_eyes, + color_body: @color_body, + color_marking: @color_marking, + color_decoration: @color_decoration, + color_hands: @color_hands, + color_feet: @color_feet, + color_eyes: @color_eyes + } + end + + # basically to_network + # int array the client sends to the server + def to_a + Packer.pack_str(@name) + + Packer.pack_str(@clan) + + Packer.pack_int(@country) + + Packer.pack_str(@body) + + Packer.pack_str(@marking) + + Packer.pack_str(@decoration) + + Packer.pack_str(@hands) + + Packer.pack_str(@feet) + + Packer.pack_str(@eyes) + + Packer.pack_int(@custom_color_body) + + Packer.pack_int(@custom_color_marking) + + Packer.pack_int(@custom_color_decoration) + + Packer.pack_int(@custom_color_hands) + + Packer.pack_int(@custom_color_feet) + + Packer.pack_int(@custom_color_eyes) + + Packer.pack_int(@color_body) + + Packer.pack_int(@color_marking) + + Packer.pack_int(@color_decoration) + + Packer.pack_int(@color_hands) + + Packer.pack_int(@color_feet) + + Packer.pack_int(@color_eyes) + end + + def to_s + to_h + end +end diff --git a/lib/teeworlds_client.rb b/lib/teeworlds_client.rb index 9854916..03ecd43 100644 --- a/lib/teeworlds_client.rb +++ b/lib/teeworlds_client.rb @@ -222,7 +222,7 @@ class TeeworldsClient @netbase.send_packet(msg) end - def send_msg_startinfo + def send_msg_start_info data = [] @start_info.each do |key, value| @@ -231,7 +231,7 @@ class TeeworldsClient elsif value.instance_of?(Integer) data += Packer.pack_int(value) else - puts "Error: invalid startinfo #{key}: #{value}" + puts "Error: invalid start info #{key}: #{value}" exit 1 end end diff --git a/lib/teeworlds_server.rb b/lib/teeworlds_server.rb index 1f888e3..56f0dd3 100644 --- a/lib/teeworlds_server.rb +++ b/lib/teeworlds_server.rb @@ -103,7 +103,7 @@ class TeeworldsServer def on_message(chunk, packet) puts "got game chunk: #{chunk}" case chunk.msg - when NETMSGTYPE_CL_STARTINFO then @game_server.on_startinfo(chunk, packet) + when NETMSGTYPE_CL_STARTINFO then @game_server.on_start_info(chunk, packet) else puts "Unsupported game msg: #{chunk.msg}" exit(1)