diff --git a/docs/v0.0.1/classes/Context.md b/docs/v0.0.1/classes/Context.md
index a09b86f..5da680f 100644
--- a/docs/v0.0.1/classes/Context.md
+++ b/docs/v0.0.1/classes/Context.md
@@ -5,15 +5,15 @@ When you hook into methods using a ``on_*`` method you can access its context.
This gives you the ability to read and modify the data before the default behavior processes it.
Or skip the default behavior and implement your own logic.
-### #cancle
+### #cancel
-Call the ``cancle()`` on the context object to not run any default code for that event.
+Call the ``cancel()`` on the context object to not run any default code for that event.
```ruby
client.on_map_change do |context|
# do nothing when a map change packet comes in
# skips the send ready packet code
- context.cancle
+ context.cancel
end
```
@@ -23,12 +23,12 @@ Access the network client to send packets.
**Example:**
-Reimplement your on on_connected logic and cancle the default one
+Reimplement your on on_connected logic and cancel the default one
```ruby
client.on_connected do |ctx|
ctx.client.send_msg_start_info
- ctx.cancle
+ ctx.cancel
end
```
diff --git a/docs/v0.0.1/classes/TeeworldsClient.md b/docs/v0.0.1/classes/TeeworldsClient.md
index 3477550..d3c407f 100644
--- a/docs/v0.0.1/classes/TeeworldsClient.md
+++ b/docs/v0.0.1/classes/TeeworldsClient.md
@@ -1,5 +1,107 @@
# TeeworldsClient
+### #on_maplist_entry_rem(&block)
+
+**Parameter: block [Block |[context](../classes/Context.md)|]**
+
+TODO: generated documentation
+
+**Example:**
+```ruby
+client = TeeworldsClient.new
+
+client.on_maplist_entry_rem do |context|
+ # TODO: generated documentation
+end
+
+client.connect('localhost', 8303, detach: true)
+```
+
+### #on_maplist_entry_add(&block)
+
+**Parameter: block [Block |[context](../classes/Context.md)|]**
+
+TODO: generated documentation
+
+**Example:**
+```ruby
+client = TeeworldsClient.new
+
+client.on_maplist_entry_add do |context|
+ # TODO: generated documentation
+end
+
+client.connect('localhost', 8303, detach: true)
+```
+
+### #on_rcon_cmd_rem(&block)
+
+**Parameter: block [Block |[context](../classes/Context.md)|]**
+
+TODO: generated documentation
+
+**Example:**
+```ruby
+client = TeeworldsClient.new
+
+client.on_rcon_cmd_rem do |context|
+ # TODO: generated documentation
+end
+
+client.connect('localhost', 8303, detach: true)
+```
+
+### #on_rcon_cmd_add(&block)
+
+**Parameter: block [Block |[context](../classes/Context.md)|]**
+
+TODO: generated documentation
+
+**Example:**
+```ruby
+client = TeeworldsClient.new
+
+client.on_rcon_cmd_add do |context|
+ # TODO: generated documentation
+end
+
+client.connect('localhost', 8303, detach: true)
+```
+
+### #on_auth_off(&block)
+
+**Parameter: block [Block |[context](../classes/Context.md)|]**
+
+TODO: generated documentation
+
+**Example:**
+```ruby
+client = TeeworldsClient.new
+
+client.on_auth_off do |context|
+ # TODO: generated documentation
+end
+
+client.connect('localhost', 8303, detach: true)
+```
+
+### #on_auth_on(&block)
+
+**Parameter: block [Block |[context](../classes/Context.md)|]**
+
+TODO: generated documentation
+
+**Example:**
+```ruby
+client = TeeworldsClient.new
+
+client.on_auth_on do |context|
+ # TODO: generated documentation
+end
+
+client.connect('localhost', 8303, detach: true)
+```
+
### #on_input_timing(&block)
**Parameter: block [Block |[context](../classes/Context.md)|]**
@@ -138,7 +240,7 @@ client.on_map_change do |context|
# skip default behavior
# in this case do not send the ready packet
- context.cancle
+ context.cancel
end
client.connect('localhost', 8303, detach: true)
diff --git a/lib/chunk.rb b/lib/chunk.rb
index 49565c1..643c430 100644
--- a/lib/chunk.rb
+++ b/lib/chunk.rb
@@ -5,7 +5,7 @@ require_relative 'network'
require_relative 'bytes'
class NetChunk
- attr_reader :next, :data, :msg, :sys, :flags, :header_raw
+ attr_reader :next, :data, :msg, :sys, :flags, :header_raw, :full_raw
@@sent_vital_chunks = 0
@@ -27,6 +27,7 @@ class NetChunk
@sys = @msg & 1 == 1
@msg >>= 1
@next = data[chunk_end..] if data.size > chunk_end
+ @full_raw = data[..chunk_end]
end
def self.reset
diff --git a/lib/context.rb b/lib/context.rb
index 3289cf5..5640cbe 100644
--- a/lib/context.rb
+++ b/lib/context.rb
@@ -6,7 +6,7 @@ class Context
def initialize(todo_rename_this, keys = {})
@todo_rename_this = todo_rename_this # the obj holding the parsed chunk
- @cancle = false
+ @cancel = false
@old_data = keys
@data = keys
end
@@ -19,11 +19,11 @@ class Context
end
end
- def cancled?
- @cancle
+ def canceld?
+ @cancel
end
- def cancle
- @cancle = true
+ def cancel
+ @cancel = true
end
end
diff --git a/lib/game_client.rb b/lib/game_client.rb
index ba4b44f..12faa03 100644
--- a/lib/game_client.rb
+++ b/lib/game_client.rb
@@ -4,6 +4,10 @@ require_relative 'models/player'
require_relative 'models/chat_message'
require_relative 'messages/input_timing'
require_relative 'messages/sv_client_drop'
+require_relative 'messages/rcon_cmd_add'
+require_relative 'messages/rcon_cmd_rem'
+require_relative 'messages/maplist_entry_add'
+require_relative 'messages/maplist_entry_rem'
require_relative 'packer'
require_relative 'context'
@@ -27,11 +31,57 @@ class GameClient
@client.hooks[hook_sym].each do |hook|
hook.call(context, optional)
context.verify
- return nil if context.cancled?
+ return nil if context.canceld?
end
context
end
+ 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
+
def on_client_info(chunk)
# puts "Got playerinfo flags: #{chunk.flags}"
u = Unpacker.new(chunk.data[1..])
diff --git a/lib/messages/maplist_entry_add.rb b/lib/messages/maplist_entry_add.rb
new file mode 100644
index 0000000..83c207a
--- /dev/null
+++ b/lib/messages/maplist_entry_add.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require_relative '../packer'
+
+##
+# MaplistEntryAdd
+#
+# Server -> Client
+class MaplistEntryAdd
+ attr_accessor :name
+
+ 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(SANITIZE_CC)
+ end
+
+ def init_hash(attr)
+ @name = attr[:name] || 'TODO: fill default'
+ end
+
+ def to_h
+ {
+ name: @name
+ }
+ end
+
+ # basically to_network
+ # int array the Server sends to the Client
+ def to_a
+ Packer.pack_str(@name)
+ end
+
+ def to_s
+ to_h
+ end
+end
diff --git a/lib/messages/maplist_entry_rem.rb b/lib/messages/maplist_entry_rem.rb
new file mode 100644
index 0000000..bad9e3d
--- /dev/null
+++ b/lib/messages/maplist_entry_rem.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require_relative '../packer'
+
+##
+# MaplistEntryRem
+#
+# Server -> Client
+class MaplistEntryRem
+ attr_accessor :name
+
+ 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(SANITIZE_CC)
+ end
+
+ def init_hash(attr)
+ @name = attr[:name] || 'TODO: fill default'
+ end
+
+ def to_h
+ {
+ name: @name
+ }
+ end
+
+ # basically to_network
+ # int array the Server sends to the Client
+ def to_a
+ Packer.pack_str(@name)
+ end
+
+ def to_s
+ to_h
+ end
+end
diff --git a/lib/messages/rcon_cmd_add.rb b/lib/messages/rcon_cmd_add.rb
new file mode 100644
index 0000000..3605b20
--- /dev/null
+++ b/lib/messages/rcon_cmd_add.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require_relative '../packer'
+
+##
+# RconCmdAdd
+#
+# Server -> Client
+class RconCmdAdd
+ attr_accessor :name, :help, :params
+
+ 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(SANITIZE_CC)
+ @help = u.get_string(SANITIZE_CC)
+ @params = u.get_string(SANITIZE_CC)
+ end
+
+ def init_hash(attr)
+ @name = attr[:name] || ''
+ @help = attr[:help] || ''
+ @params = attr[:params] || ''
+ end
+
+ def to_h
+ {
+ name: @name,
+ help: @help,
+ params: @params
+ }
+ end
+
+ # basically to_network
+ # int array the Server sends to the Client
+ def to_a
+ Packer.pack_str(@name) +
+ Packer.pack_str(@help) +
+ Packer.pack_str(@params)
+ end
+
+ def to_s
+ to_h
+ end
+end
diff --git a/lib/messages/rcon_cmd_rem.rb b/lib/messages/rcon_cmd_rem.rb
new file mode 100644
index 0000000..212a10b
--- /dev/null
+++ b/lib/messages/rcon_cmd_rem.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require_relative '../packer'
+
+##
+# RconCmdRem
+#
+# Server -> Client
+class RconCmdRem
+ attr_accessor :name
+
+ 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(SANITIZE_CC)
+ end
+
+ def init_hash(attr)
+ @name = attr[:name] || ''
+ end
+
+ def to_h
+ {
+ name: @name
+ }
+ end
+
+ # basically to_network
+ # int array the Server sends to the Client
+ def to_a
+ Packer.pack_str(@name)
+ end
+
+ def to_s
+ to_h
+ end
+end
diff --git a/lib/network.rb b/lib/network.rb
index 273d34c..4563c58 100644
--- a/lib/network.rb
+++ b/lib/network.rb
@@ -22,6 +22,9 @@ NETMSG_RCON_LINE = 13 # line that should be printed to the remote console
NETMSG_RCON_CMD_ADD = 14
NETMSG_RCON_CMD_REM = 15
+NETMSG_MAPLIST_ENTRY_ADD = 29 # TODO: 0.8: move up
+NETMSG_MAPLIST_ENTRY_REM = 30
+
# sent by client
NETMSG_READY = 18
NETMSG_ENTERGAME = 19
diff --git a/lib/packer.rb b/lib/packer.rb
index fbe5149..62d48fd 100644
--- a/lib/packer.rb
+++ b/lib/packer.rb
@@ -103,7 +103,6 @@ class Unpacker
return nil if @data.nil?
str = ''
- p @data
@data.each_with_index do |byte, index|
if byte.zero?
@data = index == @data.length - 1 ? nil : @data[(index + 1)..]
diff --git a/lib/teeworlds_client.rb b/lib/teeworlds_client.rb
index aadeb6b..639e736 100644
--- a/lib/teeworlds_client.rb
+++ b/lib/teeworlds_client.rb
@@ -16,6 +16,7 @@ require_relative 'game_client'
class TeeworldsClient
attr_reader :state, :hooks, :game_client
+ attr_accessor :rcon_authed
def initialize(options = {})
@verbose = options[:verbose] || false
@@ -31,7 +32,13 @@ class TeeworldsClient
disconnect: [],
rcon_line: [],
snapshot: [],
- input_timing: []
+ input_timing: [],
+ auth_on: [],
+ auth_off: [],
+ rcon_cmd_add: [],
+ rcon_cmd_rem: [],
+ maplist_entry_add: [],
+ maplist_entry_rem: []
}
@thread_running = false
@signal_disconnect = false
@@ -59,6 +66,35 @@ class TeeworldsClient
color_feet: 0,
color_eyes: 0
}
+ @rcon_authed = false
+ end
+
+ def rcon_authed?
+ @rcon_authed
+ end
+
+ def on_auth_on(&block)
+ @hooks[:auth_on].push(block)
+ end
+
+ def on_auth_off(&block)
+ @hooks[:auth_off].push(block)
+ end
+
+ def on_rcon_cmd_add(&block)
+ @hooks[:rcon_cmd_add].push(block)
+ end
+
+ def on_rcon_cmd_rem(&block)
+ @hooks[:rcon_cmd_rem].push(block)
+ end
+
+ def on_maplist_entry_add(&block)
+ @hooks[:maplist_entry_add].push(block)
+ end
+
+ def on_maplist_entry_rem(&block)
+ @hooks[:maplist_entry_rem].push(block)
end
def on_chat(&block)
@@ -353,7 +389,7 @@ class TeeworldsClient
on_message(chunk)
return
end
- puts "proccess chunk with msg: #{chunk.msg}"
+ puts "proccess chunk with msg: #{chunk.msg}" if @verbose
case chunk.msg
when NETMSG_MAP_CHANGE
@game_client.on_map_change(chunk)
@@ -369,8 +405,21 @@ class TeeworldsClient
@game_client.on_snapshot(chunk)
when NETMSG_INPUTTIMING
@game_client.on_input_timing(chunk)
+ when NETMSG_RCON_AUTH_ON
+ @game_client.on_auth_on
+ when NETMSG_RCON_AUTH_OFF
+ @game_client.on_auth_off
+ when NETMSG_RCON_CMD_ADD
+ @game_client.on_rcon_cmd_add(chunk)
+ when NETMSG_RCON_CMD_REM
+ @game_client.on_rcon_cmd_rem(chunk)
+ when NETMSG_MAPLIST_ENTRY_ADD
+ @game_client.on_maplist_entry_add(chunk)
+ when NETMSG_MAPLIST_ENTRY_REM
+ @game_client.on_maplist_entry_rem(chunk)
else
puts "Unsupported system msg: #{chunk.msg}"
+ p str_hex(chunk.full_raw)
exit(1)
end
end