rubocop -a
This commit is contained in:
parent
0be954538c
commit
ddef46991b
|
@ -9,27 +9,28 @@ client = TeeworldsClient.new(verbose: true)
|
||||||
# all keys are optional
|
# all keys are optional
|
||||||
# if not provided they will fall back to the default value
|
# if not provided they will fall back to the default value
|
||||||
client.set_startinfo(
|
client.set_startinfo(
|
||||||
name: "ruby gamer",
|
name: 'ruby gamer',
|
||||||
clan: "",
|
clan: '',
|
||||||
country: -1,
|
country: -1,
|
||||||
body: "spiky",
|
body: 'spiky',
|
||||||
marking: "duodonny",
|
marking: 'duodonny',
|
||||||
decoration: "",
|
decoration: '',
|
||||||
hands: "standard",
|
hands: 'standard',
|
||||||
feet: "standard",
|
feet: 'standard',
|
||||||
eyes: "standard",
|
eyes: 'standard',
|
||||||
custom_color_body: 0,
|
custom_color_body: 0,
|
||||||
custom_color_marking: 0,
|
custom_color_marking: 0,
|
||||||
custom_color_decoration: 0,
|
custom_color_decoration: 0,
|
||||||
custom_color_hands: 0,
|
custom_color_hands: 0,
|
||||||
custom_color_feet: 0,
|
custom_color_feet: 0,
|
||||||
custom_color_eyes: 0,
|
custom_color_eyes: 0,
|
||||||
color_body: 0,
|
color_body: 0,
|
||||||
color_marking: 0,
|
color_marking: 0,
|
||||||
color_decoration: 0,
|
color_decoration: 0,
|
||||||
color_hands: 0,
|
color_hands: 0,
|
||||||
color_feet: 0,
|
color_feet: 0,
|
||||||
color_eyes: 0)
|
color_eyes: 0
|
||||||
|
)
|
||||||
|
|
||||||
# connect to localhost and block the current thread
|
# connect to localhost and block the current thread
|
||||||
client.connect('localhost', 8303, detach: false)
|
client.connect('localhost', 8303, detach: false)
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Array
|
||||||
|
|
||||||
groups = []
|
groups = []
|
||||||
group = []
|
group = []
|
||||||
self.each do |item|
|
each do |item|
|
||||||
group.push(item)
|
group.push(item)
|
||||||
|
|
||||||
if group.size >= max_size
|
if group.size >= max_size
|
||||||
|
@ -16,4 +16,3 @@ class Array
|
||||||
groups
|
groups
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
|
|
||||||
# turn byte array into hex string
|
# turn byte array into hex string
|
||||||
def str_hex(data)
|
def str_hex(data)
|
||||||
data.unpack("H*").first.scan(/../).join(' ').upcase
|
data.unpack1('H*').scan(/../).join(' ').upcase
|
||||||
end
|
end
|
||||||
|
|
||||||
# turn hex string to byte array
|
# turn hex string to byte array
|
||||||
def str_bytes(str)
|
def str_bytes(str)
|
||||||
str.scan(/../).map{ |b| b.to_i(16) }
|
str.scan(/../).map { |b| b.to_i(16) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def bytes_to_str(data)
|
def bytes_to_str(data)
|
||||||
data.unpack("H*").join('')
|
data.unpack('H*').join('')
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_byte(data, start = 0, num = 1)
|
def get_byte(data, start = 0, num = 1)
|
||||||
data[start...(start+num)].unpack("H*").join('').upcase
|
data[start...(start + num)].unpack('H*').join('').upcase
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,4 +27,3 @@ class ChatMesage
|
||||||
"#{@author.name}: #{@message}"
|
"#{@author.name}: #{@message}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
39
lib/chunk.rb
39
lib/chunk.rb
|
@ -4,6 +4,7 @@ require_relative 'bytes'
|
||||||
|
|
||||||
class NetChunk
|
class NetChunk
|
||||||
attr_reader :next, :data, :msg, :sys, :flags
|
attr_reader :next, :data, :msg, :sys, :flags
|
||||||
|
|
||||||
@@sent_vital_chunks = 0
|
@@sent_vital_chunks = 0
|
||||||
|
|
||||||
def initialize(data)
|
def initialize(data)
|
||||||
|
@ -14,8 +15,8 @@ class NetChunk
|
||||||
chunk_end = CHUNK_HEADER_SIZE + @size
|
chunk_end = CHUNK_HEADER_SIZE + @size
|
||||||
# puts "data[0]: " + str_hex(data[0])
|
# puts "data[0]: " + str_hex(data[0])
|
||||||
@data = data[CHUNK_HEADER_SIZE...chunk_end]
|
@data = data[CHUNK_HEADER_SIZE...chunk_end]
|
||||||
@msg = @data[0].unpack("C*").first
|
@msg = @data[0].unpack1('C*')
|
||||||
@sys = @msg & 1 == 1 ? true : false
|
@sys = @msg & 1 == 1
|
||||||
@msg >>= 1
|
@msg >>= 1
|
||||||
@next = data[chunk_end..] if data.size > chunk_end
|
@next = data[chunk_end..] if data.size > chunk_end
|
||||||
end
|
end
|
||||||
|
@ -26,9 +27,9 @@ class NetChunk
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
"NetChunk\n" +
|
"NetChunk\n" +
|
||||||
" msg=#{msg} sys=#{sys}\n" +
|
" msg=#{msg} sys=#{sys}\n" +
|
||||||
" #{@flags}\n" +
|
" #{@flags}\n" +
|
||||||
" data: #{str_hex(data)}"
|
" data: #{str_hex(data)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -42,9 +43,7 @@ class NetChunk
|
||||||
# represented as an Array of 3 integers
|
# represented as an Array of 3 integers
|
||||||
def self.create_vital_header(flags, size, seq = nil)
|
def self.create_vital_header(flags, size, seq = nil)
|
||||||
@@sent_vital_chunks += 1
|
@@sent_vital_chunks += 1
|
||||||
if seq.nil?
|
seq = @@sent_vital_chunks if seq.nil?
|
||||||
seq = @@sent_vital_chunks
|
|
||||||
end
|
|
||||||
|
|
||||||
flag_bits = '00'
|
flag_bits = '00'
|
||||||
flag_bits[0] = flags[:resend] ? '1' : '0'
|
flag_bits[0] = flags[:resend] ? '1' : '0'
|
||||||
|
@ -54,7 +53,6 @@ class NetChunk
|
||||||
# size_bits[0..5]
|
# size_bits[0..5]
|
||||||
# size_bits[6..]
|
# size_bits[6..]
|
||||||
|
|
||||||
|
|
||||||
seq_bits = seq.to_s(2).rjust(10, '0')
|
seq_bits = seq.to_s(2).rjust(10, '0')
|
||||||
# seq_bits[0..1]
|
# seq_bits[0..1]
|
||||||
# seq_bits[2..]
|
# seq_bits[2..]
|
||||||
|
@ -68,7 +66,7 @@ class NetChunk
|
||||||
# q=sequence
|
# q=sequence
|
||||||
#
|
#
|
||||||
# ffss ssss qqss ssss qqqq qqqq
|
# ffss ssss qqss ssss qqqq qqqq
|
||||||
header_bits =
|
header_bits =
|
||||||
flag_bits +
|
flag_bits +
|
||||||
size_bits[0..5] +
|
size_bits[0..5] +
|
||||||
seq_bits[0..1] +
|
seq_bits[0..1] +
|
||||||
|
@ -81,17 +79,17 @@ class NetChunk
|
||||||
|
|
||||||
def parse_header(data)
|
def parse_header(data)
|
||||||
# flags
|
# flags
|
||||||
flags = data[0].unpack("B*").first
|
flags = data[0].unpack1('B*')
|
||||||
flags = flags[0..1]
|
flags = flags[0..1]
|
||||||
@flags[:resend] = flags[0] == "1"
|
@flags[:resend] = flags[0] == '1'
|
||||||
@flags[:vital] = flags[1] == "1"
|
@flags[:vital] = flags[1] == '1'
|
||||||
|
|
||||||
# size
|
# size
|
||||||
size = data[0..1].unpack("B*").first
|
size = data[0..1].unpack1('B*')
|
||||||
size_bytes = size.chars.groups_of(8)
|
size_bytes = size.chars.groups_of(8)
|
||||||
# trim first 2 bits of both bytes
|
# trim first 2 bits of both bytes
|
||||||
# Size: 2 bytes (..00 0000 ..00 0010)
|
# Size: 2 bytes (..00 0000 ..00 0010)
|
||||||
size_bytes.map! {|b| b[2..].join('') }
|
size_bytes.map! { |b| b[2..].join('') }
|
||||||
@size = size_bytes.join('').to_i(2)
|
@size = size_bytes.join('').to_i(2)
|
||||||
|
|
||||||
# sequence number
|
# sequence number
|
||||||
|
@ -117,13 +115,12 @@ class BigChungusTheChunkGetter
|
||||||
while chunk.next
|
while chunk.next
|
||||||
chunk = NetChunk.new(chunk.next)
|
chunk = NetChunk.new(chunk.next)
|
||||||
chunks.push(chunk)
|
chunks.push(chunk)
|
||||||
if chunks.size > MAX_NUM_CHUNKS
|
next unless chunks.size > MAX_NUM_CHUNKS
|
||||||
# inf loop guard case
|
|
||||||
puts "Warning: abort due to max num chunks bein reached"
|
# inf loop guard case
|
||||||
break
|
puts 'Warning: abort due to max num chunks bein reached'
|
||||||
end
|
break
|
||||||
end
|
end
|
||||||
chunks
|
chunks
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class Context
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify
|
def verify
|
||||||
@data.each do |key, value|
|
@data.each do |key, _value|
|
||||||
next if @old_data.key? key
|
next if @old_data.key? key
|
||||||
|
|
||||||
raise "Error: invalid data key '#{key}'\n valid keys: #{@old_data.keys}"
|
raise "Error: invalid data key '#{key}'\n valid keys: #{@old_data.keys}"
|
||||||
|
@ -42,19 +42,20 @@ class GameClient
|
||||||
# puts "Got playerinfo flags: #{chunk.flags}"
|
# puts "Got playerinfo flags: #{chunk.flags}"
|
||||||
u = Unpacker.new(chunk.data[1..])
|
u = Unpacker.new(chunk.data[1..])
|
||||||
player = Player.new(
|
player = Player.new(
|
||||||
id: u.get_int(),
|
id: u.get_int,
|
||||||
local: u.get_int(),
|
local: u.get_int,
|
||||||
team: u.get_int(),
|
team: u.get_int,
|
||||||
name: u.get_string(),
|
name: u.get_string,
|
||||||
clan: u.get_string(),
|
clan: u.get_string,
|
||||||
country: u.get_int())
|
country: u.get_int
|
||||||
|
)
|
||||||
# skinparts and the silent flag
|
# skinparts and the silent flag
|
||||||
# are currently ignored
|
# are currently ignored
|
||||||
|
|
||||||
context = Context.new(
|
context = Context.new(
|
||||||
@client,
|
@client,
|
||||||
player: player,
|
player:,
|
||||||
chunk: chunk
|
chunk:
|
||||||
)
|
)
|
||||||
if @client.hooks[:client_info]
|
if @client.hooks[:client_info]
|
||||||
@client.hooks[:client_info].call(context)
|
@client.hooks[:client_info].call(context)
|
||||||
|
@ -68,17 +69,17 @@ class GameClient
|
||||||
|
|
||||||
def on_client_drop(chunk)
|
def on_client_drop(chunk)
|
||||||
u = Unpacker.new(chunk.data[1..])
|
u = Unpacker.new(chunk.data[1..])
|
||||||
client_id = u.get_int()
|
client_id = u.get_int
|
||||||
reason = u.get_string()
|
reason = u.get_string
|
||||||
silent = u.get_int()
|
silent = u.get_int
|
||||||
|
|
||||||
context = Context.new(
|
context = Context.new(
|
||||||
@cliemt,
|
@cliemt,
|
||||||
player: @players[client_id],
|
player: @players[client_id],
|
||||||
chunk: chunk,
|
chunk:,
|
||||||
client_id: client_id,
|
client_id:,
|
||||||
reason: reason == '' ? nil : reason,
|
reason: reason == '' ? nil : reason,
|
||||||
silent: silent
|
silent:
|
||||||
)
|
)
|
||||||
if @client.hooks[:client_drop]
|
if @client.hooks[:client_drop]
|
||||||
@client.hooks[:client_drop].call(context)
|
@client.hooks[:client_drop].call(context)
|
||||||
|
@ -89,7 +90,7 @@ class GameClient
|
||||||
@players.delete(context.data[:client_id])
|
@players.delete(context.data[:client_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_ready_to_enter(chunk)
|
def on_ready_to_enter(_chunk)
|
||||||
@client.send_enter_game
|
@client.send_enter_game
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -103,11 +104,10 @@ class GameClient
|
||||||
@client.send_msg_startinfo
|
@client.send_msg_startinfo
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_emoticon(chunk)
|
def on_emoticon(chunk); end
|
||||||
end
|
|
||||||
|
|
||||||
def on_map_change(chunk)
|
def on_map_change(chunk)
|
||||||
context = Context.new(@client, chunk: chunk)
|
context = Context.new(@client, chunk:)
|
||||||
if @client.hooks[:map_change]
|
if @client.hooks[:map_change]
|
||||||
@client.hooks[:map_change].call(context)
|
@client.hooks[:map_change].call(context)
|
||||||
context.verify
|
context.verify
|
||||||
|
@ -121,17 +121,14 @@ class GameClient
|
||||||
def on_chat(chunk)
|
def on_chat(chunk)
|
||||||
u = Unpacker.new(chunk.data[1..])
|
u = Unpacker.new(chunk.data[1..])
|
||||||
data = {
|
data = {
|
||||||
mode: u.get_int(),
|
mode: u.get_int,
|
||||||
client_id: u.get_int(),
|
client_id: u.get_int,
|
||||||
target_id: u.get_int(),
|
target_id: u.get_int,
|
||||||
message: u.get_string()
|
message: u.get_string
|
||||||
}
|
}
|
||||||
data[:author] = @players[data[:client_id]]
|
data[:author] = @players[data[:client_id]]
|
||||||
msg = ChatMesage.new(data)
|
msg = ChatMesage.new(data)
|
||||||
|
|
||||||
if @client.hooks[:chat]
|
@client.hooks[:chat].call(msg) if @client.hooks[:chat]
|
||||||
@client.hooks[:chat].call(msg)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ class NetBase
|
||||||
eight_bits.join('').to_i(2)
|
eight_bits.join('').to_i(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
header = header + str_bytes(@server_token)
|
header += str_bytes(@server_token)
|
||||||
data = (header + payload).pack('C*')
|
data = (header + payload).pack('C*')
|
||||||
@s.send(data, 0, @ip, @port)
|
@s.send(data, 0, @ip, @port)
|
||||||
|
|
||||||
|
@ -54,4 +54,3 @@ class NetBase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
GAME_VERSION = "0.7.5"
|
GAME_VERSION = '0.7.5'
|
||||||
GAME_NETVERSION_HASH_FORCED = "802f1be60a05665f"
|
GAME_NETVERSION_HASH_FORCED = '802f1be60a05665f'
|
||||||
GAME_NETVERSION = "0.7 " + GAME_NETVERSION_HASH_FORCED
|
GAME_NETVERSION = '0.7 ' + GAME_NETVERSION_HASH_FORCED
|
||||||
CLIENT_VERSION = 0x0705
|
CLIENT_VERSION = 0x0705
|
||||||
|
|
||||||
NETMSG_NULL = 0
|
NETMSG_NULL = 0
|
||||||
|
@ -76,7 +76,7 @@ NET_CTRLMSG_ACCEPT = 2
|
||||||
NET_CTRLMSG_CLOSE = 4
|
NET_CTRLMSG_CLOSE = 4
|
||||||
NET_CTRLMSG_TOKEN = 5
|
NET_CTRLMSG_TOKEN = 5
|
||||||
|
|
||||||
NET_MAX_SEQUENCE = 1<<10
|
NET_MAX_SEQUENCE = 1 << 10
|
||||||
|
|
||||||
NET_CONNSTATE_OFFLINE = 0
|
NET_CONNSTATE_OFFLINE = 0
|
||||||
NET_CONNSTATE_TOKEN = 1
|
NET_CONNSTATE_TOKEN = 1
|
||||||
|
@ -97,4 +97,3 @@ TARGET_SERVER = -1
|
||||||
|
|
||||||
PACKET_HEADER_SIZE = 7
|
PACKET_HEADER_SIZE = 7
|
||||||
CHUNK_HEADER_SIZE = 3
|
CHUNK_HEADER_SIZE = 3
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,8 @@ class Packer
|
||||||
num += 1
|
num += 1
|
||||||
end
|
end
|
||||||
num = num.abs
|
num = num.abs
|
||||||
if num > 63 || num < -63
|
return pack_big_int(sign, num) if num > 63 || num < -63
|
||||||
return self.pack_big_int(sign, num)
|
|
||||||
end
|
|
||||||
ext = '0'
|
ext = '0'
|
||||||
bits = ext + sign + num.to_s(2).rjust(6, '0')
|
bits = ext + sign + num.to_s(2).rjust(6, '0')
|
||||||
[bits.to_i(2)]
|
[bits.to_i(2)]
|
||||||
|
@ -69,26 +68,26 @@ end
|
||||||
class Unpacker
|
class Unpacker
|
||||||
def initialize(data)
|
def initialize(data)
|
||||||
@data = data
|
@data = data
|
||||||
if data.class == String
|
if data.instance_of?(String)
|
||||||
@data = data.unpack("C*")
|
@data = data.unpack('C*')
|
||||||
elsif data.class == Array
|
elsif data.instance_of?(Array)
|
||||||
@data = data
|
@data = data
|
||||||
else
|
else
|
||||||
raise "Error: Unpacker expects array of integers or byte string"
|
raise 'Error: Unpacker expects array of integers or byte string'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_string()
|
def get_string
|
||||||
return nil if @data.nil?
|
return nil if @data.nil?
|
||||||
|
|
||||||
str = ''
|
str = ''
|
||||||
@data.each_with_index do |byte, index|
|
@data.each_with_index do |byte, index|
|
||||||
if byte == 0x00
|
if byte == 0x00
|
||||||
if index == @data.length - 1
|
@data = if index == @data.length - 1
|
||||||
@data = nil
|
nil
|
||||||
else
|
else
|
||||||
@data = @data[(index + 1)..]
|
@data[(index + 1)..]
|
||||||
end
|
end
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
str += byte.chr
|
str += byte.chr
|
||||||
|
@ -98,10 +97,10 @@ class Unpacker
|
||||||
''
|
''
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_int()
|
def get_int
|
||||||
return nil if @data.nil?
|
return nil if @data.nil?
|
||||||
|
|
||||||
# todo: make this more performant
|
# TODO: make this more performant
|
||||||
# it should not read in ALL bytes
|
# it should not read in ALL bytes
|
||||||
# of the WHOLE packed data
|
# of the WHOLE packed data
|
||||||
# it should be max 4 bytes
|
# it should be max 4 bytes
|
||||||
|
@ -150,8 +149,8 @@ def todo_make_this_rspec_test
|
||||||
# p Packer.pack_int(-3).first.to_s(2) == '1000010'
|
# p Packer.pack_int(-3).first.to_s(2) == '1000010'
|
||||||
# p Packer.pack_int(-4).first.to_s(2) == '1000011'
|
# p Packer.pack_int(-4).first.to_s(2) == '1000011'
|
||||||
|
|
||||||
p Packer.pack_int(64).map { |e| e.to_s(2).rjust(8, '0') } == ["10000000", "00000001"]
|
p Packer.pack_int(64).map { |e| e.to_s(2).rjust(8, '0') } == %w[10000000 00000001]
|
||||||
p Packer.pack_int(-64).map { |e| e.to_s(2).rjust(8, '0') } == ["11000000", "00000000"]
|
p Packer.pack_int(-64).map { |e| e.to_s(2).rjust(8, '0') } == %w[11000000 00000000]
|
||||||
|
|
||||||
# # multi byte int
|
# # multi byte int
|
||||||
# p Packer.pack_int(64) == [128, 1]
|
# p Packer.pack_int(64) == [128, 1]
|
||||||
|
@ -184,8 +183,8 @@ def todo_also_rspec_unpacker
|
||||||
# p u.get_int() == 64
|
# p u.get_int() == 64
|
||||||
|
|
||||||
u = Unpacker.new([128, 1, 128, 1])
|
u = Unpacker.new([128, 1, 128, 1])
|
||||||
p u.get_int() == 64
|
p u.get_int == 64
|
||||||
p u.get_int() == 64
|
p u.get_int == 64
|
||||||
# p u.get_int() == nil
|
# p u.get_int() == nil
|
||||||
|
|
||||||
# (-128..128).each do |i|
|
# (-128..128).each do |i|
|
||||||
|
@ -194,15 +193,14 @@ def todo_also_rspec_unpacker
|
||||||
# end
|
# end
|
||||||
|
|
||||||
u = Unpacker.new(['00000001'.to_i(2)])
|
u = Unpacker.new(['00000001'.to_i(2)])
|
||||||
p u.get_int() == 1
|
p u.get_int == 1
|
||||||
|
|
||||||
u = Unpacker.new(['10000000'.to_i(2), '00000001'.to_i(2)])
|
u = Unpacker.new(['10000000'.to_i(2), '00000001'.to_i(2)])
|
||||||
p u.get_int() == 64
|
p u.get_int == 64
|
||||||
|
|
||||||
# todo should be -64
|
# TODO: should be -64
|
||||||
# u = Unpacker.new(['11000000'.to_i(2), '00000000'.to_i(2)])
|
# u = Unpacker.new(['11000000'.to_i(2), '00000000'.to_i(2)])
|
||||||
# p u.get_int()
|
# p u.get_int()
|
||||||
end
|
end
|
||||||
|
|
||||||
# todo_also_rspec_unpacker
|
# todo_also_rspec_unpacker
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,14 @@ class PacketFlags
|
||||||
def initialize(data)
|
def initialize(data)
|
||||||
@hash = {}
|
@hash = {}
|
||||||
@bits = ''
|
@bits = ''
|
||||||
if data.class == Hash
|
if data.instance_of?(Hash)
|
||||||
@bits = parse_hash(data)
|
@bits = parse_hash(data)
|
||||||
@hash = data
|
@hash = data
|
||||||
elsif data.class == String
|
elsif data.instance_of?(String)
|
||||||
@hash = parse_bits(data)
|
@hash = parse_bits(data)
|
||||||
@bits = data
|
@bits = data
|
||||||
else
|
else
|
||||||
raise "Flags have to be hash or string"
|
raise 'Flags have to be hash or string'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -56,12 +56,12 @@ class Packet
|
||||||
@prefix = prefix
|
@prefix = prefix
|
||||||
@huffman = Huffman.new
|
@huffman = Huffman.new
|
||||||
@data = data
|
@data = data
|
||||||
flags_byte = @data[0].unpack("B*")
|
flags_byte = @data[0].unpack('B*')
|
||||||
@flags = PacketFlags.new(flags_byte.first[2..5]).hash
|
@flags = PacketFlags.new(flags_byte.first[2..5]).hash
|
||||||
@payload = @data[PACKET_HEADER_SIZE..]
|
@payload = @data[PACKET_HEADER_SIZE..]
|
||||||
if flags_compressed
|
if flags_compressed
|
||||||
@payload = @huffman.decompress(@payload.unpack("C*"))
|
@payload = @huffman.decompress(@payload.unpack('C*'))
|
||||||
@payload = @payload.pack("C*")
|
@payload = @payload.pack('C*')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -70,37 +70,36 @@ class Packet
|
||||||
token = bytes[3..6].join(' ').green
|
token = bytes[3..6].join(' ').green
|
||||||
payload = bytes[7..].join(' ')
|
payload = bytes[7..].join(' ')
|
||||||
puts @prefix + " data: #{[header, token, payload].join(' ')}"
|
puts @prefix + " data: #{[header, token, payload].join(' ')}"
|
||||||
print @prefix + " "
|
print @prefix + ' '
|
||||||
print "header".ljust(3 * 3, ' ').yellow
|
print 'header'.ljust(3 * 3, ' ').yellow
|
||||||
print "token".ljust(4 * 3, ' ').green
|
print 'token'.ljust(4 * 3, ' ').green
|
||||||
puts "data"
|
puts 'data'
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s()
|
def to_s
|
||||||
puts @prefix + "Packet"
|
puts @prefix + 'Packet'
|
||||||
puts @prefix + " flags: #{@flags}"
|
puts @prefix + " flags: #{@flags}"
|
||||||
bytes = str_hex(@data).split(' ')
|
bytes = str_hex(@data).split(' ')
|
||||||
# todo: check terminal size?
|
# TODO: check terminal size?
|
||||||
max_width = 14
|
max_width = 14
|
||||||
rows = bytes.groups_of(max_width)
|
rows = bytes.groups_of(max_width)
|
||||||
annotate_first_row(rows.first)
|
annotate_first_row(rows.first)
|
||||||
rows[1..].each do |row|
|
rows[1..].each do |row|
|
||||||
print @prefix + " "
|
print @prefix + ' '
|
||||||
puts row.join(' ')
|
puts row.join(' ')
|
||||||
end
|
end
|
||||||
puts ""
|
puts ''
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags_compressed()
|
def flags_compressed
|
||||||
@flags[:compressed]
|
@flags[:compressed]
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags_connless()
|
def flags_connless
|
||||||
@flags[:connection] == false
|
@flags[:connection] == false
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags_control()
|
def flags_control
|
||||||
@flags[:control]
|
@flags[:control]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
class Player
|
class Player
|
||||||
attr_accessor :id, :local, :team, :name, :clan
|
attr_accessor :id, :local, :team, :name, :clan, :country, :skin_parts, :skin_custom_colors, :skin_colors
|
||||||
attr_accessor :country
|
|
||||||
attr_accessor :skin_parts, :skin_custom_colors, :skin_colors
|
|
||||||
|
|
||||||
def initialize(data = {})
|
def initialize(data = {})
|
||||||
@id = data[:id] || -1
|
@id = data[:id] || -1
|
||||||
|
@ -15,4 +13,3 @@ class Player
|
||||||
@skin_colors = data[:skin_colors] || Array.new(6, 0)
|
@skin_colors = data[:skin_colors] || Array.new(6, 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,4 +12,3 @@ class ServerInfo
|
||||||
"version=#{@version} gametype=#{gametype} map=#{map} name=#{name}"
|
"version=#{@version} gametype=#{gametype} map=#{map} name=#{name}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -22,4 +22,3 @@ class String
|
||||||
colorize(35)
|
colorize(35)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
140
lib/teeworlds-client.rb
Normal file → Executable file
140
lib/teeworlds-client.rb
Normal file → Executable file
|
@ -28,15 +28,15 @@ class TeeworldsClient
|
||||||
@signal_disconnect = false
|
@signal_disconnect = false
|
||||||
@game_client = GameClient.new(self)
|
@game_client = GameClient.new(self)
|
||||||
@start_info = {
|
@start_info = {
|
||||||
name: "ruby gamer",
|
name: 'ruby gamer',
|
||||||
clan: "",
|
clan: '',
|
||||||
country: -1,
|
country: -1,
|
||||||
body: "spiky",
|
body: 'spiky',
|
||||||
marking: "duodonny",
|
marking: 'duodonny',
|
||||||
decoration: "",
|
decoration: '',
|
||||||
hands: "standard",
|
hands: 'standard',
|
||||||
feet: "standard",
|
feet: 'standard',
|
||||||
eyes: "standard",
|
eyes: 'standard',
|
||||||
custom_color_body: 0,
|
custom_color_body: 0,
|
||||||
custom_color_marking: 0,
|
custom_color_marking: 0,
|
||||||
custom_color_decoration: 0,
|
custom_color_decoration: 0,
|
||||||
|
@ -74,7 +74,7 @@ class TeeworldsClient
|
||||||
|
|
||||||
def send_chat(str)
|
def send_chat(str)
|
||||||
@netbase.send_packet(
|
@netbase.send_packet(
|
||||||
NetChunk.create_vital_header({vital: true}, 4 + str.length) +
|
NetChunk.create_vital_header({ vital: true }, 4 + str.length) +
|
||||||
[
|
[
|
||||||
pack_msg_id(NETMSGTYPE_CL_SAY),
|
pack_msg_id(NETMSGTYPE_CL_SAY),
|
||||||
CHAT_ALL,
|
CHAT_ALL,
|
||||||
|
@ -86,11 +86,9 @@ class TeeworldsClient
|
||||||
|
|
||||||
def connect(ip, port, options = {})
|
def connect(ip, port, options = {})
|
||||||
options[:detach] = options[:detach] || false
|
options[:detach] = options[:detach] || false
|
||||||
if options[:detach]
|
if options[:detach] && @thread_running
|
||||||
if @thread_running
|
puts 'Error: connection thread already running call disconnect() first'
|
||||||
puts "Error: connection thread already running call disconnect() first"
|
return
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
disconnect
|
disconnect
|
||||||
@signal_disconnect = false
|
@signal_disconnect = false
|
||||||
|
@ -123,13 +121,9 @@ class TeeworldsClient
|
||||||
end
|
end
|
||||||
|
|
||||||
def disconnect
|
def disconnect
|
||||||
puts "disconnecting."
|
puts 'disconnecting.'
|
||||||
unless @netbase.nil?
|
@netbase.send_packet([NET_CTRLMSG_CLOSE], 0, control: true) unless @netbase.nil?
|
||||||
@netbase.send_packet([NET_CTRLMSG_CLOSE], 0, control: true)
|
@s.close unless @s.nil?
|
||||||
end
|
|
||||||
unless @s.nil?
|
|
||||||
@s.close
|
|
||||||
end
|
|
||||||
@signal_disconnect = true
|
@signal_disconnect = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -148,40 +142,40 @@ class TeeworldsClient
|
||||||
@netbase.send_packet(data)
|
@netbase.send_packet(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ctrl_keepalive()
|
def send_ctrl_keepalive
|
||||||
@netbase.send_packet([NET_CTRLMSG_KEEPALIVE], 0, control: true)
|
@netbase.send_packet([NET_CTRLMSG_KEEPALIVE], 0, control: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_msg_connect()
|
def send_msg_connect
|
||||||
msg = [NET_CTRLMSG_CONNECT] + str_bytes(@client_token) + Array.new(501, 0x00)
|
msg = [NET_CTRLMSG_CONNECT] + str_bytes(@client_token) + Array.new(501, 0x00)
|
||||||
@netbase.send_packet(msg, 0, control: true)
|
@netbase.send_packet(msg, 0, control: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ctrl_with_token()
|
def send_ctrl_with_token
|
||||||
@state = NET_CONNSTATE_TOKEN
|
@state = NET_CONNSTATE_TOKEN
|
||||||
msg = [NET_CTRLMSG_TOKEN] + str_bytes(@client_token) + Array.new(512, 0x00)
|
msg = [NET_CTRLMSG_TOKEN] + str_bytes(@client_token) + Array.new(512, 0x00)
|
||||||
@netbase.send_packet(msg, 0, control: true)
|
@netbase.send_packet(msg, 0, control: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_info()
|
def send_info
|
||||||
data = []
|
data = []
|
||||||
data += Packer.pack_str(GAME_NETVERSION)
|
data += Packer.pack_str(GAME_NETVERSION)
|
||||||
data += Packer.pack_str("password")
|
data += Packer.pack_str('password')
|
||||||
data += Packer.pack_int(CLIENT_VERSION)
|
data += Packer.pack_int(CLIENT_VERSION)
|
||||||
msg = NetChunk.create_vital_header({vital: true}, data.size + 1) +
|
msg = NetChunk.create_vital_header({ vital: true }, data.size + 1) +
|
||||||
[pack_msg_id(NETMSG_INFO, system: true)] +
|
[pack_msg_id(NETMSG_INFO, system: true)] +
|
||||||
data
|
data
|
||||||
|
|
||||||
@netbase.send_packet(msg, 1)
|
@netbase.send_packet(msg, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_msg_startinfo()
|
def send_msg_startinfo
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
@start_info.each do |key, value|
|
@start_info.each do |key, value|
|
||||||
if value.class == String
|
if value.instance_of?(String)
|
||||||
data += Packer.pack_str(value)
|
data += Packer.pack_str(value)
|
||||||
elsif value.class == Integer
|
elsif value.instance_of?(Integer)
|
||||||
data += Packer.pack_int(value)
|
data += Packer.pack_int(value)
|
||||||
else
|
else
|
||||||
puts "Error: invalid startinfo #{key}: #{value}"
|
puts "Error: invalid startinfo #{key}: #{value}"
|
||||||
|
@ -190,22 +184,24 @@ class TeeworldsClient
|
||||||
end
|
end
|
||||||
|
|
||||||
@netbase.send_packet(
|
@netbase.send_packet(
|
||||||
NetChunk.create_vital_header({vital: true}, data.size + 1) +
|
NetChunk.create_vital_header({ vital: true }, data.size + 1) +
|
||||||
[pack_msg_id(NETMSGTYPE_CL_STARTINFO, system: false)] +
|
[pack_msg_id(NETMSGTYPE_CL_STARTINFO, system: false)] +
|
||||||
data
|
data
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_msg_ready()
|
def send_msg_ready
|
||||||
@netbase.send_packet(
|
@netbase.send_packet(
|
||||||
NetChunk.create_vital_header({vital: true}, 1) +
|
NetChunk.create_vital_header({ vital: true }, 1) +
|
||||||
[pack_msg_id(NETMSG_READY, system: true)])
|
[pack_msg_id(NETMSG_READY, system: true)]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_enter_game()
|
def send_enter_game
|
||||||
@netbase.send_packet(
|
@netbase.send_packet(
|
||||||
NetChunk.create_vital_header({vital: true}, 1) +
|
NetChunk.create_vital_header({ vital: true }, 1) +
|
||||||
[pack_msg_id(NETMSG_ENTERGAME, system: true)])
|
[pack_msg_id(NETMSG_ENTERGAME, system: true)]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -214,12 +210,12 @@ class TeeworldsClient
|
||||||
# Takes a NETMSGTYPE_CL_* integer
|
# Takes a NETMSGTYPE_CL_* integer
|
||||||
# and returns a byte that can be send over
|
# and returns a byte that can be send over
|
||||||
# the network
|
# the network
|
||||||
def pack_msg_id(msg_id, options = {system: false})
|
def pack_msg_id(msg_id, options = { system: false })
|
||||||
(msg_id << 1) | (options[:system] ? 1 : 0)
|
(msg_id << 1) | (options[:system] ? 1 : 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_input
|
def send_input
|
||||||
header = [0x10, 0x0A, 01] + str_bytes(@token)
|
header = [0x10, 0x0A, 0o1] + str_bytes(@token)
|
||||||
random_compressed_input = [
|
random_compressed_input = [
|
||||||
0x4D, 0xE9, 0x48, 0x13, 0xD0, 0x0B, 0x6B, 0xFC, 0xB7, 0x2B, 0x6E, 0x00, 0xBA
|
0x4D, 0xE9, 0x48, 0x13, 0xD0, 0x0B, 0x6B, 0xFC, 0xB7, 0x2B, 0x6E, 0x00, 0xBA
|
||||||
]
|
]
|
||||||
|
@ -234,20 +230,20 @@ class TeeworldsClient
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_msg_token(data)
|
def on_msg_token(data)
|
||||||
@token = bytes_to_str(data)
|
@token = bytes_to_str(data)
|
||||||
@netbase.server_token = @token
|
@netbase.server_token = @token
|
||||||
puts "Got token #{@token}"
|
puts "Got token #{@token}"
|
||||||
send_msg_connect()
|
send_msg_connect
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_msg_accept
|
def on_msg_accept
|
||||||
puts "got accept. connection online"
|
puts 'got accept. connection online'
|
||||||
@state = NET_CONNSTATE_ONLINE
|
@state = NET_CONNSTATE_ONLINE
|
||||||
send_info
|
send_info
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_msg_close
|
def on_msg_close
|
||||||
puts "got NET_CTRLMSG_CLOSE"
|
puts 'got NET_CTRLMSG_CLOSE'
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -258,10 +254,10 @@ class TeeworldsClient
|
||||||
when NET_CTRLMSG_TOKEN then on_msg_token(data)
|
when NET_CTRLMSG_TOKEN then on_msg_token(data)
|
||||||
when NET_CTRLMSG_ACCEPT then on_msg_accept
|
when NET_CTRLMSG_ACCEPT then on_msg_accept
|
||||||
when NET_CTRLMSG_CLOSE then on_msg_close
|
when NET_CTRLMSG_CLOSE then on_msg_close
|
||||||
when NET_CTRLMSG_KEEPALIVE then # silently ignore keepalive
|
when NET_CTRLMSG_KEEPALIVE # silently ignore keepalive
|
||||||
else
|
else
|
||||||
puts "Uknown control message #{msg}"
|
puts "Uknown control message #{msg}"
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -273,14 +269,12 @@ class TeeworldsClient
|
||||||
when NETMSGTYPE_SV_EMOTICON then @game_client.on_emoticon(chunk)
|
when NETMSGTYPE_SV_EMOTICON then @game_client.on_emoticon(chunk)
|
||||||
when NETMSGTYPE_SV_CHAT then @game_client.on_chat(chunk)
|
when NETMSGTYPE_SV_CHAT then @game_client.on_chat(chunk)
|
||||||
else
|
else
|
||||||
if @verbose
|
puts "todo non sys chunks. skipped msg: #{chunk.msg}" if @verbose
|
||||||
puts "todo non sys chunks. skipped msg: #{chunk.msg}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_chunk(chunk)
|
def process_chunk(chunk)
|
||||||
if !chunk.sys
|
unless chunk.sys
|
||||||
on_message(chunk)
|
on_message(chunk)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -289,7 +283,7 @@ class TeeworldsClient
|
||||||
when NETMSG_MAP_CHANGE
|
when NETMSG_MAP_CHANGE
|
||||||
@game_client.on_map_change(chunk)
|
@game_client.on_map_change(chunk)
|
||||||
when NETMSG_SERVERINFO
|
when NETMSG_SERVERINFO
|
||||||
puts "ignore server info for now"
|
puts 'ignore server info for now'
|
||||||
when NETMSG_CON_READY
|
when NETMSG_CON_READY
|
||||||
@game_client.on_connected
|
@game_client.on_connected
|
||||||
when NETMSG_NULL
|
when NETMSG_NULL
|
||||||
|
@ -303,7 +297,7 @@ class TeeworldsClient
|
||||||
def process_server_packet(packet)
|
def process_server_packet(packet)
|
||||||
data = packet.payload
|
data = packet.payload
|
||||||
if data.size.zero?
|
if data.size.zero?
|
||||||
puts "Error: packet payload is empty"
|
puts 'Error: packet payload is empty'
|
||||||
puts packet.to_s
|
puts packet.to_s
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -311,9 +305,7 @@ class TeeworldsClient
|
||||||
chunks.each do |chunk|
|
chunks.each do |chunk|
|
||||||
if chunk.flags_vital && !chunk.flags_resend
|
if chunk.flags_vital && !chunk.flags_resend
|
||||||
@netbase.ack = (@netbase.ack + 1) % NET_MAX_SEQUENCE
|
@netbase.ack = (@netbase.ack + 1) % NET_MAX_SEQUENCE
|
||||||
if @verbose
|
puts "got ack: #{@netbase.ack}" if @verbose
|
||||||
puts "got ack: #{@netbase.ack}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
process_chunk(chunk)
|
process_chunk(chunk)
|
||||||
end
|
end
|
||||||
|
@ -327,12 +319,12 @@ class TeeworldsClient
|
||||||
pck = nil
|
pck = nil
|
||||||
end
|
end
|
||||||
if pck.nil? && @token.nil?
|
if pck.nil? && @token.nil?
|
||||||
@wait_for_token = @wait_for_token || 0
|
@wait_for_token ||= 0
|
||||||
@wait_for_token += 1
|
@wait_for_token += 1
|
||||||
if @wait_for_token > 6
|
if @wait_for_token > 6
|
||||||
@token = nil
|
@token = nil
|
||||||
send_ctrl_with_token
|
send_ctrl_with_token
|
||||||
puts "retrying connection ..."
|
puts 'retrying connection ...'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return unless pck
|
return unless pck
|
||||||
|
@ -340,36 +332,30 @@ class TeeworldsClient
|
||||||
data = pck.first
|
data = pck.first
|
||||||
|
|
||||||
packet = Packet.new(data, '<')
|
packet = Packet.new(data, '<')
|
||||||
if @verbose
|
puts packet.to_s if @verbose
|
||||||
puts packet.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
# process connless packets data
|
# process connless packets data
|
||||||
if packet.flags_control
|
if packet.flags_control
|
||||||
msg = data[PACKET_HEADER_SIZE].unpack("C*").first
|
msg = data[PACKET_HEADER_SIZE].unpack1('C*')
|
||||||
on_ctrl_message(msg, data[(PACKET_HEADER_SIZE + 1)..])
|
on_ctrl_message(msg, data[(PACKET_HEADER_SIZE + 1)..])
|
||||||
else # process non-connless packets
|
else # process non-connless packets
|
||||||
process_server_packet(packet)
|
process_server_packet(packet)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ticks += 1
|
@ticks += 1
|
||||||
if @ticks % 8 == 0
|
send_ctrl_keepalive if @ticks % 8 == 0
|
||||||
send_ctrl_keepalive
|
|
||||||
end
|
|
||||||
# if @ticks % 20 == 0
|
# if @ticks % 20 == 0
|
||||||
# send_chat("hello world")
|
# send_chat("hello world")
|
||||||
# end
|
# end
|
||||||
end
|
end
|
||||||
|
|
||||||
def connection_loop
|
def connection_loop
|
||||||
until @signal_disconnect
|
until @signal_disconnect
|
||||||
tick
|
tick
|
||||||
# todo: proper tick speed sleep
|
# TODO: proper tick speed sleep
|
||||||
sleep 0.001
|
sleep 0.001
|
||||||
end
|
end
|
||||||
@thread_running = false
|
@thread_running = false
|
||||||
@signal_disconnect = false
|
@signal_disconnect = false
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
18
sample.rb
18
sample.rb
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
require_relative 'lib/teeworlds-client'
|
require_relative 'lib/teeworlds-client'
|
||||||
|
|
||||||
args = {verbose: false, ip: nil, port: nil}
|
args = { verbose: false, ip: nil, port: nil }
|
||||||
|
|
||||||
ARGV.each do |arg|
|
ARGV.each do |arg|
|
||||||
if arg == '--help' || arg == '-h'
|
if ['--help', '-h'].include?(arg)
|
||||||
puts "usage: teeworlds.rb [OPTIONS..] [host] [port]"
|
puts 'usage: teeworlds.rb [OPTIONS..] [host] [port]'
|
||||||
echo "options:"
|
echo 'options:'
|
||||||
echo " --help|-h show this help"
|
echo ' --help|-h show this help'
|
||||||
echo " --verbose|-v verbose output"
|
echo ' --verbose|-v verbose output'
|
||||||
echo "example:"
|
echo 'example:'
|
||||||
echo " teeworlds.rb --verbose localhost 8303"
|
echo ' teeworlds.rb --verbose localhost 8303'
|
||||||
exit(0)
|
exit(0)
|
||||||
elsif arg == '--verbose' || arg == '-v'
|
elsif ['--verbose', '-v'].include?(arg)
|
||||||
args[:verbose] = true
|
args[:verbose] = true
|
||||||
elsif args[:ip].nil?
|
elsif args[:ip].nil?
|
||||||
args[:ip] = arg
|
args[:ip] = arg
|
||||||
|
|
|
@ -10,4 +10,3 @@ describe 'Array', :array do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
require_relative '../lib/packet'
|
require_relative '../lib/packet'
|
||||||
|
|
||||||
|
|
||||||
describe 'Packet', :packet do
|
describe 'Packet', :packet do
|
||||||
context 'Set flag bits' do
|
context 'Set flag bits' do
|
||||||
it 'Should set the control flag bit' do
|
it 'Should set the control flag bit' do
|
||||||
expect(PacketFlags.new(control: true).bits).to eq("0001")
|
expect(PacketFlags.new(control: true).bits).to eq('0001')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ require_relative '../lib/chunk'
|
||||||
describe 'NetChunk', :net_chunk do
|
describe 'NetChunk', :net_chunk do
|
||||||
context 'Create vital header' do
|
context 'Create vital header' do
|
||||||
it 'Should set the vital flag' do
|
it 'Should set the vital flag' do
|
||||||
expect(NetChunk.create_vital_header({vital: true}, 20, 5)).to eq([64, 20, 5])
|
expect(NetChunk.create_vital_header({ vital: true }, 20, 5)).to eq([64, 20, 5])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -15,7 +15,7 @@ describe 'BigChungusTheChunkGetter', :chunk_getter do
|
||||||
# one empty motd chunks
|
# one empty motd chunks
|
||||||
data = [
|
data = [
|
||||||
0x40, 0x02, 0x02, 0x02, 0x00
|
0x40, 0x02, 0x02, 0x02, 0x00
|
||||||
].pack("C*")
|
].pack('C*')
|
||||||
chunks = BigChungusTheChunkGetter.get_chunks(data)
|
chunks = BigChungusTheChunkGetter.get_chunks(data)
|
||||||
expect(chunks.size).to eq(1)
|
expect(chunks.size).to eq(1)
|
||||||
end
|
end
|
||||||
|
@ -28,7 +28,7 @@ describe 'BigChungusTheChunkGetter', :chunk_getter do
|
||||||
data = [
|
data = [
|
||||||
0x40, 0x02, 0x02, 0x02, 0x00,
|
0x40, 0x02, 0x02, 0x02, 0x00,
|
||||||
0x40, 0x02, 0x02, 0x02, 0x00
|
0x40, 0x02, 0x02, 0x02, 0x00
|
||||||
].pack("C*")
|
].pack('C*')
|
||||||
chunks = BigChungusTheChunkGetter.get_chunks(data)
|
chunks = BigChungusTheChunkGetter.get_chunks(data)
|
||||||
expect(chunks.size).to eq(2)
|
expect(chunks.size).to eq(2)
|
||||||
expect(chunks[0].msg).to eq(NETMSGTYPE_SV_MOTD)
|
expect(chunks[0].msg).to eq(NETMSGTYPE_SV_MOTD)
|
||||||
|
@ -42,7 +42,7 @@ describe 'BigChungusTheChunkGetter', :chunk_getter do
|
||||||
0x40, 0x02, 0x02, 0x02, 0x00, # motd
|
0x40, 0x02, 0x02, 0x02, 0x00, # motd
|
||||||
0x40, 0x07, 0x03, 0x22, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, # server settings
|
0x40, 0x07, 0x03, 0x22, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, # server settings
|
||||||
0x40, 0x01, 0x04, 0x0b # ready
|
0x40, 0x01, 0x04, 0x0b # ready
|
||||||
].pack("C*")
|
].pack('C*')
|
||||||
chunks = BigChungusTheChunkGetter.get_chunks(data)
|
chunks = BigChungusTheChunkGetter.get_chunks(data)
|
||||||
expect(chunks.size).to eq(3)
|
expect(chunks.size).to eq(3)
|
||||||
expect(chunks[0].msg).to eq(NETMSGTYPE_SV_MOTD)
|
expect(chunks[0].msg).to eq(NETMSGTYPE_SV_MOTD)
|
||||||
|
@ -56,11 +56,10 @@ describe 'BigChungusTheChunkGetter', :chunk_getter do
|
||||||
0xee, 0xcb, 0xd0, 0xd7, 0x02, 0x9c, 0x0e, 0x08, 0xa8, 0x15, 0x1a, 0xb3, 0xbb, 0xb1, 0xd4, 0x04,
|
0xee, 0xcb, 0xd0, 0xd7, 0x02, 0x9c, 0x0e, 0x08, 0xa8, 0x15, 0x1a, 0xb3, 0xbb, 0xb1, 0xd4, 0x04,
|
||||||
0x75, 0x68, 0xec, 0xe3, 0x41, 0x6e, 0x83, 0x20, 0xaf, 0x97, 0x0f, 0x49, 0xbe, 0x4f, 0x3c, 0x61,
|
0x75, 0x68, 0xec, 0xe3, 0x41, 0x6e, 0x83, 0x20, 0xaf, 0x97, 0x0f, 0x49, 0xbe, 0x4f, 0x3c, 0x61,
|
||||||
0x04, 0xf4, 0xbe, 0x60, 0xd2, 0x87, 0x39, 0x91, 0x59, 0xab
|
0x04, 0xf4, 0xbe, 0x60, 0xd2, 0x87, 0x39, 0x91, 0x59, 0xab
|
||||||
].pack("C*")
|
].pack('C*')
|
||||||
chunks = BigChungusTheChunkGetter.get_chunks(map_change)
|
chunks = BigChungusTheChunkGetter.get_chunks(map_change)
|
||||||
expect(chunks.size).to eq(1)
|
expect(chunks.size).to eq(1)
|
||||||
expect(chunks[0].sys).to eq(true)
|
expect(chunks[0].sys).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rake'
|
require 'rake'
|
||||||
|
|
Loading…
Reference in a new issue