From 05867afa62a2b229d693bf10ec32559d55784ef1 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Wed, 21 Feb 2024 13:07:10 +0800 Subject: [PATCH] Fix some server crashes and implement emoticons --- lib/game_server.rb | 11 +++++---- lib/messages/sv_emoticon.rb | 48 +++++++++++++++++++++++++++++++++++++ lib/teeworlds_server.rb | 35 +++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 lib/messages/sv_emoticon.rb diff --git a/lib/game_server.rb b/lib/game_server.rb index 7144733..0464c19 100644 --- a/lib/game_server.rb +++ b/lib/game_server.rb @@ -10,6 +10,7 @@ require_relative 'messages/start_info' require_relative 'messages/cl_say' require_relative 'messages/cl_emoticon' require_relative 'messages/cl_info' +require_relative 'messages/cl_input' class GameServer attr_accessor :pred_game_tick, :ack_game_tick, :map @@ -41,9 +42,11 @@ class GameServer context end - def on_emoticon(chunk, _packet) + def on_emoticon(chunk, packet) msg = ClEmoticon.new(chunk.data[1..]) - call_hook(:emote, Context.new(msg, chunk:, packet:)).nil? + return if call_hook(:emote, Context.new(msg, chunk:, packet:)).nil? + + @server.send_emoticon(packet.client.player.id, msg.emoticon) end def on_info(chunk, packet) @@ -150,7 +153,7 @@ class GameServer def on_client_drop(client, reason = nil) reason = reason.nil? ? '' : " (#{reason})" - return if call_hook(:client_drop, Context.new(nil, chunk:, packet:, reason:)).nil? + return if call_hook(:client_drop, Context.new(nil, client:, reason:)).nil? puts "'#{client.player.name}' left the game#{reason}" end @@ -166,7 +169,7 @@ class GameServer end def on_tick - return if call_hook(:tick, Context.new(nil, chunk:, packet:)).nil? + return if call_hook(:tick, Context.new(nil)).nil? now = Time.now timeout_ids = [] diff --git a/lib/messages/sv_emoticon.rb b/lib/messages/sv_emoticon.rb new file mode 100644 index 0000000..1ce45db --- /dev/null +++ b/lib/messages/sv_emoticon.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require_relative '../packer' + +## +# SvEmoticon +# +# Server -> Client +class SvEmoticon + attr_accessor :client_id, :emoticon + + 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 + @emoticon = u.get_int + end + + def init_hash(attr) + @client_id = attr[:client_id] || 0 + @emoticon = attr[:emoticon] || 0 + end + + def to_h + { + client_id: @client_id, + emoticon: @emoticon + } + end + + # basically to_network + # int array the Server sends to the Client + def to_a + Packer.pack_int(@client_id) + + Packer.pack_int(@emoticon) + end + + def to_s + to_h + end +end diff --git a/lib/teeworlds_server.rb b/lib/teeworlds_server.rb index e5da521..2b8d6ba 100644 --- a/lib/teeworlds_server.rb +++ b/lib/teeworlds_server.rb @@ -13,6 +13,7 @@ require_relative 'models/net_addr' require_relative 'packer' require_relative 'game_server' require_relative 'models/token' +require_relative 'messages/sv_emoticon' class Client attr_accessor :id, :addr, :vital_sent, :last_recv_time, :token, :player, :in_game, :authed @@ -309,6 +310,40 @@ class TeeworldsServer @netbase.send_packet(msg, chunks: 1, client:) end + ## + # sends emoticon to all connected clients + # + # emote ids: + # 0 - oop! + # 1 - alert + # 2 - heart + # 3 - tear + # 4 - ... + # 5 - music + # 6 - sorry + # 7 - ghost + # 8 - annoyed + # 9 - angry + # 10 - devil + # 11 - swearing + # 12 - zzZ + # 13 - WTF + # 14 - happy + # 15 - ?? + # + # @param client_id [Integer] id of the client who sent the emoticon + # @param emoticon [Integer] emoticon id see list above + def send_emoticon(client_id, emoticon) + emote = SvEmoticon.new(client_id:, emoticon:) + data = emote.to_a + @clients.each_value do |client| + msg = NetChunk.create_header(vital: true, size: 1, client:) + + [pack_msg_id(NETMSGTYPE_SV_EMOTICON, system: false)] + + data + @netbase.send_packet(msg, chunks: 1, client:) + end + end + def send_rcon_auth_on(client) msg = NetChunk.create_header(vital: true, size: 1, client:) + [pack_msg_id(NETMSG_RCON_AUTH_ON, system: true)]