Make client callbacks arrays
Allows to setup multiple on_* hook blocks as a lib user closed #10
This commit is contained in:
parent
2bec19ff21
commit
fe3e581f86
|
@ -15,7 +15,7 @@ require_relative 'lib/teeworlds_client'
|
||||||
|
|
||||||
client = TeeworldsClient.new(verbose: false)
|
client = TeeworldsClient.new(verbose: false)
|
||||||
|
|
||||||
client.on_chat do |msg|
|
client.on_chat do |_, msg|
|
||||||
# note use `next` instead of `return` in the block
|
# note use `next` instead of `return` in the block
|
||||||
next unless msg.message[0] == '!'
|
next unless msg.message[0] == '!'
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ args[:port] = args[:port] || 8303
|
||||||
|
|
||||||
client = TeeworldsClient.new(verbose: args[:verbose])
|
client = TeeworldsClient.new(verbose: args[:verbose])
|
||||||
|
|
||||||
client.on_chat do |msg|
|
client.on_chat do |_, msg|
|
||||||
puts "[chat] #{msg}"
|
puts "[chat] #{msg}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -87,17 +87,19 @@ client.connect('localhost', 8303, detach: true)
|
||||||
|
|
||||||
### <a name="on_chat"></a> #on_chat(&block)
|
### <a name="on_chat"></a> #on_chat(&block)
|
||||||
|
|
||||||
**Parameter: block [Block |[ChatMessage](../classes/ChatMessage.md)|]**
|
**Parameter: block [Block |[context](../classes/Context.md), [ChatMessage](../classes/ChatMessage.md)|]**
|
||||||
|
|
||||||
Takes a block that will be called when the client receives a chat message.
|
Takes a block that will be called when the client receives a chat message.
|
||||||
The block takes one parameter of type [ChatMessage](../classes/ChatMessage.md).
|
The block takes two parameters:
|
||||||
|
[context](../classes/Context.md) - pretty much useless as of right now
|
||||||
|
[ChatMessage](../classes/ChatMessage.md) - holds all the information of the chat message
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
client = TeeworldsClient.new
|
client = TeeworldsClient.new
|
||||||
|
|
||||||
client.on_chat do |msg|
|
client.on_chat do |context, msg|
|
||||||
puts "[chat] #{msg}"
|
puts "[chat] #{msg}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ client = TeeworldsClient.new(verbose: false)
|
||||||
# msg.author.team
|
# msg.author.team
|
||||||
# msg.author.name
|
# msg.author.name
|
||||||
# msg.author.clan
|
# msg.author.clan
|
||||||
client.on_chat do |msg|
|
client.on_chat do |_, msg|
|
||||||
puts "[chat] #{msg}"
|
puts "[chat] #{msg}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ require_relative '../lib/teeworlds_client'
|
||||||
|
|
||||||
client = TeeworldsClient.new(verbose: false)
|
client = TeeworldsClient.new(verbose: false)
|
||||||
|
|
||||||
client.on_chat do |msg|
|
client.on_chat do |_, msg|
|
||||||
next if msg.message[0] != '!'
|
next if msg.message[0] != '!'
|
||||||
|
|
||||||
case msg.message[1..]
|
case msg.message[1..]
|
||||||
|
|
24
integration_test/client/multiple_blocks.rb
Executable file
24
integration_test/client/multiple_blocks.rb
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../../lib/teeworlds_client'
|
||||||
|
|
||||||
|
client = TeeworldsClient.new
|
||||||
|
|
||||||
|
client.on_connected do |_|
|
||||||
|
puts 'block 1 rcon auth'
|
||||||
|
client.rcon_auth(password: 'rcon')
|
||||||
|
end
|
||||||
|
|
||||||
|
client.on_connected do |_|
|
||||||
|
puts 'block 2 rcon shutdown'
|
||||||
|
client.rcon('shutdown')
|
||||||
|
end
|
||||||
|
|
||||||
|
client.on_disconnect do
|
||||||
|
puts 'got disconnect'
|
||||||
|
exit 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# connect and block main thread
|
||||||
|
client.connect('localhost', 8377, detach: false)
|
|
@ -78,9 +78,9 @@ then
|
||||||
fi
|
fi
|
||||||
if [[ "$testname" =~ ^client/ ]]
|
if [[ "$testname" =~ ^client/ ]]
|
||||||
then
|
then
|
||||||
ruby_logfile="$logdir/ruby_client.tx"
|
ruby_logfile="$logdir/ruby_client.txt"
|
||||||
else
|
else
|
||||||
ruby_logfile="$logdir/ruby_server.tx"
|
ruby_logfile="$logdir/ruby_server.txt"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
|
@ -160,6 +160,36 @@ then
|
||||||
then
|
then
|
||||||
fail "Error: server still running rcon shutdown failed"
|
fail "Error: server still running rcon shutdown failed"
|
||||||
fi
|
fi
|
||||||
|
elif [ "$testname" == "client/multiple_blocks.rb" ]
|
||||||
|
then
|
||||||
|
sleep 1
|
||||||
|
if pgrep -f "$tw_srv_bin $srvcfg"
|
||||||
|
then
|
||||||
|
fail "Error: server still running rcon shutdown failed (2 blocks)"
|
||||||
|
fi
|
||||||
|
block1_ln="$(grep -n "block 1" "$ruby_logfile" | cut -d':' -f1)"
|
||||||
|
block2_ln="$(grep -n "block 2" "$ruby_logfile" | cut -d':' -f1)"
|
||||||
|
if [ "$block1_ln" == "" ]
|
||||||
|
then
|
||||||
|
fail "Error: 'block 1' not found in client log"
|
||||||
|
fi
|
||||||
|
if [ "$block2_ln" == "" ]
|
||||||
|
then
|
||||||
|
fail "Error: 'block 2' not found in client log"
|
||||||
|
fi
|
||||||
|
if [[ ! "$block1_ln" =~ ^[0-9]+$ ]]
|
||||||
|
then
|
||||||
|
fail "Error: failed to parse line number of 'block 1' got='$block1_ln'"
|
||||||
|
fi
|
||||||
|
if [[ ! "$block2_ln" =~ ^[0-9]+$ ]]
|
||||||
|
then
|
||||||
|
fail "Error: failed to parse line number of 'block 2' got='$block2_ln'"
|
||||||
|
fi
|
||||||
|
# ensure block call order matches definition order
|
||||||
|
if [ "$block1_ln" -gt "$block2_ln" ]
|
||||||
|
then
|
||||||
|
fail "Error: 'block 1' found after 'block 2' in client log"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "Error: unkown test '$testname'"
|
echo "Error: unkown test '$testname'"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
29
lib/context.rb
Normal file
29
lib/context.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Context
|
||||||
|
attr_reader :old_data, :client
|
||||||
|
attr_accessor :data
|
||||||
|
|
||||||
|
def initialize(client, keys = {})
|
||||||
|
@client = client
|
||||||
|
@cancle = false
|
||||||
|
@old_data = keys
|
||||||
|
@data = keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify
|
||||||
|
@data.each do |key, _value|
|
||||||
|
next if @old_data.key? key
|
||||||
|
|
||||||
|
raise "Error: invalid data key '#{key}'\n valid keys: #{@old_data.keys}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancled?
|
||||||
|
@cancle
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancle
|
||||||
|
@cancle = true
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,34 +3,7 @@
|
||||||
require_relative 'models/player'
|
require_relative 'models/player'
|
||||||
require_relative 'models/chat_message'
|
require_relative 'models/chat_message'
|
||||||
require_relative 'packer'
|
require_relative 'packer'
|
||||||
|
require_relative 'context'
|
||||||
class Context
|
|
||||||
attr_reader :old_data, :client
|
|
||||||
attr_accessor :data
|
|
||||||
|
|
||||||
def initialize(client, keys = {})
|
|
||||||
@client = client
|
|
||||||
@cancle = false
|
|
||||||
@old_data = keys
|
|
||||||
@data = keys
|
|
||||||
end
|
|
||||||
|
|
||||||
def verify
|
|
||||||
@data.each do |key, _value|
|
|
||||||
next if @old_data.key? key
|
|
||||||
|
|
||||||
raise "Error: invalid data key '#{key}'\n valid keys: #{@old_data.keys}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def cancled?
|
|
||||||
@cancle
|
|
||||||
end
|
|
||||||
|
|
||||||
def cancle
|
|
||||||
@cancle = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class GameClient
|
class GameClient
|
||||||
attr_accessor :players, :pred_game_tick, :ack_game_tick
|
attr_accessor :players, :pred_game_tick, :ack_game_tick
|
||||||
|
@ -42,6 +15,21 @@ class GameClient
|
||||||
@pred_game_tick = 0
|
@pred_game_tick = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# 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
|
||||||
|
return nil if context.cancled?
|
||||||
|
end
|
||||||
|
context
|
||||||
|
end
|
||||||
|
|
||||||
def on_client_info(chunk)
|
def on_client_info(chunk)
|
||||||
# puts "Got playerinfo flags: #{chunk.flags}"
|
# puts "Got playerinfo flags: #{chunk.flags}"
|
||||||
u = Unpacker.new(chunk.data[1..])
|
u = Unpacker.new(chunk.data[1..])
|
||||||
|
@ -61,11 +49,7 @@ class GameClient
|
||||||
player:,
|
player:,
|
||||||
chunk:
|
chunk:
|
||||||
)
|
)
|
||||||
if @client.hooks[:client_info]
|
return if call_hook(:client_info, context).nil?
|
||||||
@client.hooks[:client_info].call(context)
|
|
||||||
context.verify
|
|
||||||
return if context.cancled?
|
|
||||||
end
|
|
||||||
|
|
||||||
player = context.data[:player]
|
player = context.data[:player]
|
||||||
@players[player.id] = player
|
@players[player.id] = player
|
||||||
|
@ -78,18 +62,14 @@ class GameClient
|
||||||
silent = u.get_int
|
silent = u.get_int
|
||||||
|
|
||||||
context = Context.new(
|
context = Context.new(
|
||||||
@cliemt,
|
@client,
|
||||||
player: @players[client_id],
|
player: @players[client_id],
|
||||||
chunk:,
|
chunk:,
|
||||||
client_id:,
|
client_id:,
|
||||||
reason: reason == '' ? nil : reason,
|
reason: reason == '' ? nil : reason,
|
||||||
silent: silent != 0
|
silent: silent != 0
|
||||||
)
|
)
|
||||||
if @client.hooks[:client_drop]
|
return if call_hook(:client_drop, context).nil?
|
||||||
@client.hooks[:client_drop].call(context)
|
|
||||||
context.verify
|
|
||||||
return if context.cancled?
|
|
||||||
end
|
|
||||||
|
|
||||||
@players.delete(context.data[:client_id])
|
@players.delete(context.data[:client_id])
|
||||||
end
|
end
|
||||||
|
@ -100,16 +80,13 @@ class GameClient
|
||||||
|
|
||||||
def on_connected
|
def on_connected
|
||||||
context = Context.new(@client)
|
context = Context.new(@client)
|
||||||
if @client.hooks[:connected]
|
return if call_hook(:connected, context).nil?
|
||||||
@client.hooks[:connected].call(context)
|
|
||||||
context.verify
|
|
||||||
return if context.cancled?
|
|
||||||
end
|
|
||||||
@client.send_msg_start_info
|
@client.send_msg_start_info
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_disconnect
|
def on_disconnect
|
||||||
@client.hooks[:disconnect]&.call
|
call_hook(:disconnect, Context.new(@client))
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_rcon_line(chunk)
|
def on_rcon_line(chunk)
|
||||||
|
@ -118,7 +95,7 @@ class GameClient
|
||||||
@client,
|
@client,
|
||||||
line: u.get_string
|
line: u.get_string
|
||||||
)
|
)
|
||||||
@client.hooks[:rcon_line]&.call(context)
|
call_hook(:rcon_line, context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_snapshot(chunk)
|
def on_snapshot(chunk)
|
||||||
|
@ -162,11 +139,8 @@ class GameClient
|
||||||
|
|
||||||
def on_map_change(chunk)
|
def on_map_change(chunk)
|
||||||
context = Context.new(@client, chunk:)
|
context = Context.new(@client, chunk:)
|
||||||
if @client.hooks[:map_change]
|
return if call_hook(:map_change, context).nil?
|
||||||
@client.hooks[:map_change].call(context)
|
|
||||||
context.verify
|
|
||||||
return if context.cancled?
|
|
||||||
end
|
|
||||||
# ignore mapdownload at all times
|
# ignore mapdownload at all times
|
||||||
# and claim to have the map
|
# and claim to have the map
|
||||||
@client.send_msg_ready
|
@client.send_msg_ready
|
||||||
|
@ -183,6 +157,7 @@ class GameClient
|
||||||
data[:author] = @players[data[:client_id]]
|
data[:author] = @players[data[:client_id]]
|
||||||
msg = ChatMesage.new(data)
|
msg = ChatMesage.new(data)
|
||||||
|
|
||||||
@client.hooks[:chat]&.call(msg)
|
context = Context.new(@client, chunk:)
|
||||||
|
call_hook(:chat, context, msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,16 @@ class TeeworldsClient
|
||||||
@state = NET_CONNSTATE_OFFLINE
|
@state = NET_CONNSTATE_OFFLINE
|
||||||
@ip = 'localhost'
|
@ip = 'localhost'
|
||||||
@port = 8303
|
@port = 8303
|
||||||
@hooks = {}
|
@hooks = {
|
||||||
|
chat: [],
|
||||||
|
map_change: [],
|
||||||
|
client_info: [],
|
||||||
|
client_drop: [],
|
||||||
|
connected: [],
|
||||||
|
disconnect: [],
|
||||||
|
rcon_line: [],
|
||||||
|
snapshot: []
|
||||||
|
}
|
||||||
@thread_running = false
|
@thread_running = false
|
||||||
@signal_disconnect = false
|
@signal_disconnect = false
|
||||||
@game_client = GameClient.new(self)
|
@game_client = GameClient.new(self)
|
||||||
|
@ -53,35 +62,35 @@ class TeeworldsClient
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_chat(&block)
|
def on_chat(&block)
|
||||||
@hooks[:chat] = block
|
@hooks[:chat].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_map_change(&block)
|
def on_map_change(&block)
|
||||||
@hooks[:map_change] = block
|
@hooks[:map_change].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_client_info(&block)
|
def on_client_info(&block)
|
||||||
@hooks[:client_info] = block
|
@hooks[:client_info].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_client_drop(&block)
|
def on_client_drop(&block)
|
||||||
@hooks[:client_drop] = block
|
@hooks[:client_drop].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_connected(&block)
|
def on_connected(&block)
|
||||||
@hooks[:connected] = block
|
@hooks[:connected].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_disconnect(&block)
|
def on_disconnect(&block)
|
||||||
@hooks[:disconnect] = block
|
@hooks[:disconnect].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_rcon_line(&block)
|
def on_rcon_line(&block)
|
||||||
@hooks[:rcon_line] = block
|
@hooks[:rcon_line].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_snapshot(&block)
|
def on_snapshot(&block)
|
||||||
@hooks[:snapshot] = block
|
@hooks[:snapshot].push(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_chat(str)
|
def send_chat(str)
|
||||||
|
|
|
@ -144,9 +144,9 @@ function check_file() {
|
||||||
{
|
{
|
||||||
echo '# frozen_string_literal: true'
|
echo '# frozen_string_literal: true'
|
||||||
echo ''
|
echo ''
|
||||||
echo "require_relative '../../$ruby_file'"
|
echo "require_relative '../../${ruby_file::-3}'"
|
||||||
echo "obj = $ruby_class.new"
|
echo "obj = $ruby_class.new"
|
||||||
echo "obj.$hook { |_| _ }"
|
echo "obj.$hook(&:verify)"
|
||||||
} > "$tmpfile"
|
} > "$tmpfile"
|
||||||
if ! ruby "$tmpfile" &>/dev/null
|
if ! ruby "$tmpfile" &>/dev/null
|
||||||
then
|
then
|
||||||
|
|
Loading…
Reference in a new issue