2022-11-05 16:48:47 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-11-13 07:54:46 +00:00
|
|
|
require_relative 'models/player'
|
|
|
|
require_relative 'models/chat_message'
|
2022-11-16 08:37:47 +00:00
|
|
|
require_relative 'messages/input_timing'
|
|
|
|
require_relative 'messages/sv_client_drop'
|
2022-11-16 09:50:54 +00:00
|
|
|
require_relative 'messages/rcon_cmd_add'
|
|
|
|
require_relative 'messages/rcon_cmd_rem'
|
|
|
|
require_relative 'messages/maplist_entry_add'
|
|
|
|
require_relative 'messages/maplist_entry_rem'
|
2022-11-04 15:26:24 +00:00
|
|
|
require_relative 'packer'
|
2022-11-14 09:25:28 +00:00
|
|
|
require_relative 'context'
|
2022-11-19 08:59:00 +00:00
|
|
|
require_relative 'snapshot/unpacker'
|
2022-11-05 09:35:40 +00:00
|
|
|
|
2022-11-04 15:26:24 +00:00
|
|
|
class GameClient
|
2022-11-06 19:08:32 +00:00
|
|
|
attr_accessor :players, :pred_game_tick, :ack_game_tick
|
2022-11-04 15:26:24 +00:00
|
|
|
|
|
|
|
def initialize(client)
|
|
|
|
@client = client
|
|
|
|
@players = {}
|
2022-11-06 19:08:32 +00:00
|
|
|
@ack_game_tick = -1
|
|
|
|
@pred_game_tick = 0
|
2022-11-04 15:26:24 +00:00
|
|
|
end
|
|
|
|
|
2022-11-14 09:25:28 +00:00
|
|
|
##
|
|
|
|
# call_hook
|
|
|
|
#
|
|
|
|
# @param: hook_sym [Symbol] name of the symbol to call
|
|
|
|
# @param: context [Context] context object to pass on data
|
|
|
|
# @param: optional [Any] optional 2nd parameter passed to the callback
|
|
|
|
def call_hook(hook_sym, context, optional = nil)
|
|
|
|
@client.hooks[hook_sym].each do |hook|
|
|
|
|
hook.call(context, optional)
|
|
|
|
context.verify
|
2022-11-16 09:50:54 +00:00
|
|
|
return nil if context.canceld?
|
2022-11-14 09:25:28 +00:00
|
|
|
end
|
|
|
|
context
|
|
|
|
end
|
|
|
|
|
2022-11-16 09:50:54 +00:00
|
|
|
def on_auth_on
|
|
|
|
return if call_hook(:auth_on, Context.new(nil)).nil?
|
|
|
|
|
|
|
|
@client.rcon_authed = true
|
|
|
|
puts 'rcon logged in'
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_auth_off
|
|
|
|
return if call_hook(:auth_off, Context.new(nil)).nil?
|
|
|
|
|
|
|
|
@client.rcon_authed = false
|
|
|
|
puts 'rcon logged out'
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_rcon_cmd_add(chunk)
|
|
|
|
todo_rename_this = RconCmdAdd.new(chunk.data[1..])
|
|
|
|
context = Context.new(todo_rename_this)
|
|
|
|
return if call_hook(:rcon_cmd_add, context).nil?
|
|
|
|
|
|
|
|
p context.todo_rename_this
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_rcon_cmd_rem(chunk)
|
|
|
|
todo_rename_this = RconCmdRem.new(chunk.data[1..])
|
|
|
|
context = Context.new(todo_rename_this)
|
|
|
|
return if call_hook(:rcon_cmd_rem, context).nil?
|
|
|
|
|
|
|
|
p context.todo_rename_this
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_maplist_entry_add(chunk)
|
|
|
|
todo_rename_this = MaplistEntryAdd.new(chunk.data[1..])
|
|
|
|
context = Context.new(todo_rename_this)
|
|
|
|
return if call_hook(:maplist_entry_add, context).nil?
|
|
|
|
|
|
|
|
p context.todo_rename_this
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_maplist_entry_rem(chunk)
|
|
|
|
todo_rename_this = MaplistEntryRem.new(chunk.data[1..])
|
|
|
|
context = Context.new(todo_rename_this)
|
|
|
|
return if call_hook(:maplist_entry_rem, context).nil?
|
|
|
|
|
|
|
|
p context.todo_rename_this
|
|
|
|
end
|
|
|
|
|
2022-11-05 09:35:40 +00:00
|
|
|
def on_client_info(chunk)
|
2022-11-04 15:26:24 +00:00
|
|
|
# puts "Got playerinfo flags: #{chunk.flags}"
|
|
|
|
u = Unpacker.new(chunk.data[1..])
|
|
|
|
player = Player.new(
|
2022-11-05 16:19:05 +00:00
|
|
|
id: u.get_int,
|
|
|
|
local: u.get_int,
|
|
|
|
team: u.get_int,
|
|
|
|
name: u.get_string,
|
|
|
|
clan: u.get_string,
|
|
|
|
country: u.get_int
|
|
|
|
)
|
2022-11-04 15:26:24 +00:00
|
|
|
# skinparts and the silent flag
|
|
|
|
# are currently ignored
|
|
|
|
|
2022-11-05 09:35:40 +00:00
|
|
|
context = Context.new(
|
2022-11-15 09:33:05 +00:00
|
|
|
nil,
|
2022-11-05 16:19:05 +00:00
|
|
|
player:,
|
|
|
|
chunk:
|
2022-11-05 09:35:40 +00:00
|
|
|
)
|
2022-11-14 09:25:28 +00:00
|
|
|
return if call_hook(:client_info, context).nil?
|
2022-11-05 09:35:40 +00:00
|
|
|
|
|
|
|
player = context.data[:player]
|
2022-11-04 15:26:24 +00:00
|
|
|
@players[player.id] = player
|
2022-11-05 10:59:36 +00:00
|
|
|
end
|
|
|
|
|
2022-11-15 09:33:05 +00:00
|
|
|
def on_input_timing(chunk)
|
|
|
|
todo_rename_this = InputTiming.new(chunk.data[1..])
|
2022-11-15 11:55:43 +00:00
|
|
|
context = Context.new(todo_rename_this, chunk:)
|
2022-11-15 09:33:05 +00:00
|
|
|
call_hook(:input_timing, context)
|
|
|
|
end
|
|
|
|
|
2022-11-05 10:59:36 +00:00
|
|
|
def on_client_drop(chunk)
|
2022-11-15 11:55:43 +00:00
|
|
|
todo_rename_this = SvClientDrop.new(chunk.data[1..])
|
2022-11-05 10:59:36 +00:00
|
|
|
context = Context.new(
|
2022-11-15 09:33:05 +00:00
|
|
|
nil,
|
2022-11-15 11:55:43 +00:00
|
|
|
player: @players[todo_rename_this.client_id],
|
2022-11-05 16:19:05 +00:00
|
|
|
chunk:,
|
2022-11-15 11:55:43 +00:00
|
|
|
client_id: todo_rename_this.client_id,
|
|
|
|
reason: todo_rename_this.reason,
|
|
|
|
silent: todo_rename_this.silent?
|
2022-11-05 10:59:36 +00:00
|
|
|
)
|
2022-11-14 09:25:28 +00:00
|
|
|
return if call_hook(:client_drop, context).nil?
|
2022-11-05 10:59:36 +00:00
|
|
|
|
|
|
|
@players.delete(context.data[:client_id])
|
2022-11-04 15:26:24 +00:00
|
|
|
end
|
|
|
|
|
2022-11-05 16:19:05 +00:00
|
|
|
def on_ready_to_enter(_chunk)
|
2022-11-05 09:35:40 +00:00
|
|
|
@client.send_enter_game
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_connected
|
2022-11-15 09:33:05 +00:00
|
|
|
context = Context.new(nil)
|
2022-11-14 09:25:28 +00:00
|
|
|
return if call_hook(:connected, context).nil?
|
|
|
|
|
2022-11-13 09:37:46 +00:00
|
|
|
@client.send_msg_start_info
|
2022-11-05 09:35:40 +00:00
|
|
|
end
|
|
|
|
|
2022-11-12 15:47:12 +00:00
|
|
|
def on_disconnect
|
2022-11-15 09:33:05 +00:00
|
|
|
call_hook(:disconnect, Context.new(nil))
|
2022-11-12 15:47:12 +00:00
|
|
|
end
|
|
|
|
|
2022-11-06 17:26:14 +00:00
|
|
|
def on_rcon_line(chunk)
|
|
|
|
u = Unpacker.new(chunk.data[1..])
|
|
|
|
context = Context.new(
|
2022-11-15 09:33:05 +00:00
|
|
|
nil,
|
2022-11-06 17:26:14 +00:00
|
|
|
line: u.get_string
|
|
|
|
)
|
2022-11-14 09:25:28 +00:00
|
|
|
call_hook(:rcon_line, context)
|
2022-11-06 17:26:14 +00:00
|
|
|
end
|
|
|
|
|
2022-11-06 19:08:32 +00:00
|
|
|
def on_snapshot(chunk)
|
2022-11-18 09:34:47 +00:00
|
|
|
u = SnapshotUnpacker.new
|
|
|
|
game_tick = u.snap_single(chunk)
|
|
|
|
return if game_tick.nil?
|
2022-11-06 19:08:32 +00:00
|
|
|
|
|
|
|
# ack every snapshot no matter how broken
|
|
|
|
@ack_game_tick = game_tick
|
|
|
|
return unless (@pred_game_tick - @ack_game_tick).abs > 10
|
|
|
|
|
|
|
|
@pred_game_tick = @ack_game_tick + 1
|
|
|
|
end
|
|
|
|
|
2022-11-05 16:19:05 +00:00
|
|
|
def on_emoticon(chunk); end
|
2022-11-05 10:34:34 +00:00
|
|
|
|
2022-11-05 09:35:40 +00:00
|
|
|
def on_map_change(chunk)
|
2022-11-15 09:33:05 +00:00
|
|
|
context = Context.new(nil, chunk:)
|
2022-11-14 09:25:28 +00:00
|
|
|
return if call_hook(:map_change, context).nil?
|
|
|
|
|
2022-11-05 09:35:40 +00:00
|
|
|
# ignore mapdownload at all times
|
|
|
|
# and claim to have the map
|
|
|
|
@client.send_msg_ready
|
|
|
|
end
|
|
|
|
|
2022-11-04 15:26:24 +00:00
|
|
|
def on_chat(chunk)
|
|
|
|
u = Unpacker.new(chunk.data[1..])
|
|
|
|
data = {
|
2022-11-05 16:19:05 +00:00
|
|
|
mode: u.get_int,
|
|
|
|
client_id: u.get_int,
|
|
|
|
target_id: u.get_int,
|
|
|
|
message: u.get_string
|
2022-11-04 15:26:24 +00:00
|
|
|
}
|
|
|
|
data[:author] = @players[data[:client_id]]
|
|
|
|
msg = ChatMesage.new(data)
|
|
|
|
|
2022-11-15 09:33:05 +00:00
|
|
|
context = Context.new(nil, chunk:)
|
2022-11-14 09:25:28 +00:00
|
|
|
call_hook(:chat, context, msg)
|
2022-11-04 15:26:24 +00:00
|
|
|
end
|
|
|
|
end
|