Add more hooks to the server (#9)

This commit is contained in:
ChillerDragon 2024-02-21 11:39:57 +08:00
parent 6de22bae6d
commit a7895747b6
4 changed files with 211 additions and 11 deletions

View file

@ -9,6 +9,7 @@ require_relative 'messages/server_settings'
require_relative 'messages/start_info' require_relative 'messages/start_info'
require_relative 'messages/cl_say' require_relative 'messages/cl_say'
require_relative 'messages/cl_emoticon' require_relative 'messages/cl_emoticon'
require_relative 'messages/cl_info'
class GameServer class GameServer
attr_accessor :pred_game_tick, :ack_game_tick, :map attr_accessor :pred_game_tick, :ack_game_tick, :map
@ -41,19 +42,17 @@ class GameServer
end end
def on_emoticon(chunk, _packet) def on_emoticon(chunk, _packet)
message = ClEmoticon.new(chunk.data[1..]) msg = ClEmoticon.new(chunk.data[1..])
p message return if call_hook(:emote, Context.new(msg, chunk:, packet:)).nil?
end end
def on_info(chunk, packet) def on_info(chunk, packet)
u = Unpacker.new(chunk.data[1..]) msg = ClInfo.new(chunk.data[1..])
net_version = u.get_string
password = u.get_string return if call_hook(:info, Context.new(msg, chunk:, packet:)).nil?
client_version = u.get_int
puts "vers=#{net_version} vers=#{client_version} pass=#{password}"
# TODO: check version and password # TODO: check version and password
puts "vers=#{msg.net_version} vers=#{msg.client_version} pass=#{msg.password}"
@server.send_map(packet.client) @server.send_map(packet.client)
end end
@ -63,6 +62,8 @@ class GameServer
# - server settings # - server settings
# - ready # - ready
# #
return if call_hook(:ready, Context.new(nil, chunk: nil, packet:)).nil?
@server.send_server_settings(packet.client, ServerSettings.new.to_a) @server.send_server_settings(packet.client, ServerSettings.new.to_a)
@server.send_ready(packet.client) @server.send_ready(packet.client)
end end
@ -75,6 +76,8 @@ class GameServer
# #
# We only send ready to enter for now # We only send ready to enter for now
info = StartInfo.new(chunk.data[1..]) info = StartInfo.new(chunk.data[1..])
return if call_hook(:start_info, Context.new(info, chunk: nil, packet:)).nil?
packet.client.player.set_start_info(info) packet.client.player.set_start_info(info)
info_str = info.to_s info_str = info.to_s
puts "got start info: #{info_str}" if @verbose puts "got start info: #{info_str}" if @verbose
@ -99,6 +102,8 @@ class GameServer
# - game info # - game info
# - client info # - client info
# - snap single # - snap single
return if call_hook(:enter_game, Context.new(nil, chunk: nil, packet:)).nil?
packet.client.in_game = true packet.client.in_game = true
@server.send_server_info(packet.client, ServerInfo.new.to_a) @server.send_server_info(packet.client, ServerInfo.new.to_a)
@server.send_game_info(packet.client, GameInfo.new.to_a) @server.send_game_info(packet.client, GameInfo.new.to_a)
@ -136,12 +141,17 @@ class GameServer
# - input_timing # - input_timing
# - snap (empty) # - snap (empty)
# we do nothing for now msg = ClInput.new(chunk.data[1..])
# TODO: do something return if call_hook(:input, Context.new(msg, chunk:, packet:)).nil?
dir = msg.direction
puts "#{packet.client.player.id} tried to move #{dir}" unless dir.zero?
end end
def on_client_drop(client, reason = nil) def on_client_drop(client, reason = nil)
reason = reason.nil? ? '' : " (#{reason})" reason = reason.nil? ? '' : " (#{reason})"
return if call_hook(:client_drop, Context.new(nil, chunk:, packet:, reason:)).nil?
puts "'#{client.player.name}' left the game#{reason}" puts "'#{client.player.name}' left the game#{reason}"
end end
@ -156,6 +166,8 @@ class GameServer
end end
def on_tick def on_tick
return if call_hook(:tick, Context.new(nil, chunk:, packet:)).nil?
now = Time.now now = Time.now
timeout_ids = [] timeout_ids = []
@server.clients.each do |id, client| @server.clients.each do |id, client|

52
lib/messages/cl_info.rb Normal file
View file

@ -0,0 +1,52 @@
# frozen_string_literal: true
require_relative '../packer'
##
# ClInfo
#
# Client -> Server
class ClInfo
attr_accessor :net_version, :password, :client_version
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)
@net_version = u.get_string
@password = u.get_string
@client_version = u.get_int
end
def init_hash(attr)
@net_version = attr[:net_version] || 'TODO: fill default'
@password = attr[:password] || 'TODO: fill default'
@client_version = attr[:client_version] || 0
end
def to_h
{
net_version: @net_version,
password: @password,
client_version: @client_version
}
end
# basically to_network
# int array the Client sends to the Server
def to_a
Packer.pack_str(@net_version) +
Packer.pack_str(@password) +
Packer.pack_int(@client_version)
end
def to_s
to_h
end
end

96
lib/messages/cl_input.rb Normal file
View file

@ -0,0 +1,96 @@
# frozen_string_literal: true
require_relative '../packer'
##
# ClInput
#
# Client -> Server
class ClInput
attr_accessor :ack_game_tick, :prediction_tick, :size, :direction, :target_x, :target_y, :jump, :fire, :hook, :player_flags, :wanted_weapon, :next_weapon, :prev_weapon, :ping
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)
@ack_game_tick = u.get_int
@prediction_tick = u.get_int
@size = u.get_int
@direction = u.get_int
@target_x = u.get_int
@target_y = u.get_int
@jump = u.get_int
@fire = u.get_int
@hook = u.get_int
@player_flags = u.get_int
@wanted_weapon = u.get_int
@next_weapon = u.get_int
@prev_weapon = u.get_int
@ping = u.get_int
end
def init_hash(attr)
@ack_game_tick = attr[:ack_game_tick] || 0
@prediction_tick = attr[:prediction_tick] || 0
@size = attr[:size] || 0
@direction = attr[:direction] || 0
@target_x = attr[:target_x] || 0
@target_y = attr[:target_y] || 0
@jump = attr[:jump] || 0
@fire = attr[:fire] || 0
@hook = attr[:hook] || 0
@player_flags = attr[:player_flags] || 0
@wanted_weapon = attr[:wanted_weapon] || 0
@next_weapon = attr[:next_weapon] || 0
@prev_weapon = attr[:prev_weapon] || 0
@ping = attr[:ping] || 0
end
def to_h
{
ack_game_tick: @ack_game_tick,
prediction_tick: @prediction_tick,
size: @size,
direction: @direction,
target_x: @target_x,
target_y: @target_y,
jump: @jump,
fire: @fire,
hook: @hook,
player_flags: @player_flags,
wanted_weapon: @wanted_weapon,
next_weapon: @next_weapon,
prev_weapon: @prev_weapon,
ping: @ping
}
end
# basically to_network
# int array the Client sends to the Server
def to_a
Packer.pack_int(@ack_game_tick) +
Packer.pack_int(@prediction_tick) +
Packer.pack_int(@size) +
Packer.pack_int(@direction) +
Packer.pack_int(@target_x) +
Packer.pack_int(@target_y) +
Packer.pack_int(@jump) +
Packer.pack_int(@fire) +
Packer.pack_int(@hook) +
Packer.pack_int(@player_flags) +
Packer.pack_int(@wanted_weapon) +
Packer.pack_int(@next_weapon) +
Packer.pack_int(@prev_weapon) +
Packer.pack_int(@ping)
end
def to_s
to_h
end
end

View file

@ -78,7 +78,15 @@ class TeeworldsServer
chat: [], chat: [],
rcon_auth: [], rcon_auth: [],
rcon_cmd: [], rcon_cmd: [],
shutdown: [] shutdown: [],
emote: [],
info: [],
ready: [],
start_info: [],
enter_game: [],
input: [],
client_drop: [],
tick: []
} }
@thread_running = false @thread_running = false
@is_shutting_down = false @is_shutting_down = false
@ -106,6 +114,38 @@ class TeeworldsServer
@hooks[:shutdown].push(block) @hooks[:shutdown].push(block)
end end
def on_emote(&block)
@hooks[:emote].push(block)
end
def on_info(&block)
@hooks[:info].push(block)
end
def on_ready(&block)
@hooks[:ready].push(block)
end
def on_start_info(&block)
@hooks[:start_info].push(block)
end
def on_enter_game(&block)
@hooks[:enter_game].push(block)
end
def on_input(&block)
@hooks[:input].push(block)
end
def on_client_drop(&block)
@hooks[:client_drop].push(block)
end
def on_tick(&block)
@hooks[:tick].push(block)
end
def main_loop def main_loop
loop do loop do
break if @is_shutting_down break if @is_shutting_down