rubocop -a

This commit is contained in:
ChillerDragon 2022-11-05 17:19:05 +01:00
parent 0be954538c
commit ddef46991b
19 changed files with 192 additions and 229 deletions

View file

@ -9,27 +9,28 @@ client = TeeworldsClient.new(verbose: true)
# all keys are optional
# if not provided they will fall back to the default value
client.set_startinfo(
name: "ruby gamer",
clan: "",
country: -1,
body: "spiky",
marking: "duodonny",
decoration: "",
hands: "standard",
feet: "standard",
eyes: "standard",
custom_color_body: 0,
custom_color_marking: 0,
custom_color_decoration: 0,
custom_color_hands: 0,
custom_color_feet: 0,
custom_color_eyes: 0,
color_body: 0,
color_marking: 0,
color_decoration: 0,
color_hands: 0,
color_feet: 0,
color_eyes: 0)
name: 'ruby gamer',
clan: '',
country: -1,
body: 'spiky',
marking: 'duodonny',
decoration: '',
hands: 'standard',
feet: 'standard',
eyes: 'standard',
custom_color_body: 0,
custom_color_marking: 0,
custom_color_decoration: 0,
custom_color_hands: 0,
custom_color_feet: 0,
custom_color_eyes: 0,
color_body: 0,
color_marking: 0,
color_decoration: 0,
color_hands: 0,
color_feet: 0,
color_eyes: 0
)
# connect to localhost and block the current thread
client.connect('localhost', 8303, detach: false)

View file

@ -4,7 +4,7 @@ class Array
groups = []
group = []
self.each do |item|
each do |item|
group.push(item)
if group.size >= max_size
@ -16,4 +16,3 @@ class Array
groups
end
end

View file

@ -1,18 +1,17 @@
# turn byte array into hex string
def str_hex(data)
data.unpack("H*").first.scan(/../).join(' ').upcase
data.unpack1('H*').scan(/../).join(' ').upcase
end
# turn hex string to byte array
def str_bytes(str)
str.scan(/../).map{ |b| b.to_i(16) }
str.scan(/../).map { |b| b.to_i(16) }
end
def bytes_to_str(data)
data.unpack("H*").join('')
data.unpack('H*').join('')
end
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

View file

@ -27,4 +27,3 @@ class ChatMesage
"#{@author.name}: #{@message}"
end
end

View file

@ -4,6 +4,7 @@ require_relative 'bytes'
class NetChunk
attr_reader :next, :data, :msg, :sys, :flags
@@sent_vital_chunks = 0
def initialize(data)
@ -14,8 +15,8 @@ class NetChunk
chunk_end = CHUNK_HEADER_SIZE + @size
# puts "data[0]: " + str_hex(data[0])
@data = data[CHUNK_HEADER_SIZE...chunk_end]
@msg = @data[0].unpack("C*").first
@sys = @msg & 1 == 1 ? true : false
@msg = @data[0].unpack1('C*')
@sys = @msg & 1 == 1
@msg >>= 1
@next = data[chunk_end..] if data.size > chunk_end
end
@ -26,9 +27,9 @@ class NetChunk
def to_s
"NetChunk\n" +
" msg=#{msg} sys=#{sys}\n" +
" #{@flags}\n" +
" data: #{str_hex(data)}"
" msg=#{msg} sys=#{sys}\n" +
" #{@flags}\n" +
" data: #{str_hex(data)}"
end
##
@ -42,9 +43,7 @@ class NetChunk
# represented as an Array of 3 integers
def self.create_vital_header(flags, size, seq = nil)
@@sent_vital_chunks += 1
if seq.nil?
seq = @@sent_vital_chunks
end
seq = @@sent_vital_chunks if seq.nil?
flag_bits = '00'
flag_bits[0] = flags[:resend] ? '1' : '0'
@ -54,7 +53,6 @@ class NetChunk
# size_bits[0..5]
# size_bits[6..]
seq_bits = seq.to_s(2).rjust(10, '0')
# seq_bits[0..1]
# seq_bits[2..]
@ -68,7 +66,7 @@ class NetChunk
# q=sequence
#
# ffss ssss qqss ssss qqqq qqqq
header_bits =
header_bits =
flag_bits +
size_bits[0..5] +
seq_bits[0..1] +
@ -81,17 +79,17 @@ class NetChunk
def parse_header(data)
# flags
flags = data[0].unpack("B*").first
flags = data[0].unpack1('B*')
flags = flags[0..1]
@flags[:resend] = flags[0] == "1"
@flags[:vital] = flags[1] == "1"
@flags[:resend] = flags[0] == '1'
@flags[:vital] = flags[1] == '1'
# size
size = data[0..1].unpack("B*").first
size = data[0..1].unpack1('B*')
size_bytes = size.chars.groups_of(8)
# trim first 2 bits of both bytes
# 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)
# sequence number
@ -117,13 +115,12 @@ class BigChungusTheChunkGetter
while chunk.next
chunk = NetChunk.new(chunk.next)
chunks.push(chunk)
if chunks.size > MAX_NUM_CHUNKS
# inf loop guard case
puts "Warning: abort due to max num chunks bein reached"
break
end
next unless chunks.size > MAX_NUM_CHUNKS
# inf loop guard case
puts 'Warning: abort due to max num chunks bein reached'
break
end
chunks
end
end

View file

@ -14,7 +14,7 @@ class Context
end
def verify
@data.each do |key, value|
@data.each do |key, _value|
next if @old_data.key? key
raise "Error: invalid data key '#{key}'\n valid keys: #{@old_data.keys}"
@ -42,19 +42,20 @@ class GameClient
# puts "Got playerinfo flags: #{chunk.flags}"
u = Unpacker.new(chunk.data[1..])
player = Player.new(
id: u.get_int(),
local: u.get_int(),
team: u.get_int(),
name: u.get_string(),
clan: u.get_string(),
country: u.get_int())
id: u.get_int,
local: u.get_int,
team: u.get_int,
name: u.get_string,
clan: u.get_string,
country: u.get_int
)
# skinparts and the silent flag
# are currently ignored
context = Context.new(
@client,
player: player,
chunk: chunk
player:,
chunk:
)
if @client.hooks[:client_info]
@client.hooks[:client_info].call(context)
@ -68,17 +69,17 @@ class GameClient
def on_client_drop(chunk)
u = Unpacker.new(chunk.data[1..])
client_id = u.get_int()
reason = u.get_string()
silent = u.get_int()
client_id = u.get_int
reason = u.get_string
silent = u.get_int
context = Context.new(
@cliemt,
player: @players[client_id],
chunk: chunk,
client_id: client_id,
chunk:,
client_id:,
reason: reason == '' ? nil : reason,
silent: silent
silent:
)
if @client.hooks[:client_drop]
@client.hooks[:client_drop].call(context)
@ -89,7 +90,7 @@ class GameClient
@players.delete(context.data[:client_id])
end
def on_ready_to_enter(chunk)
def on_ready_to_enter(_chunk)
@client.send_enter_game
end
@ -103,11 +104,10 @@ class GameClient
@client.send_msg_startinfo
end
def on_emoticon(chunk)
end
def on_emoticon(chunk); end
def on_map_change(chunk)
context = Context.new(@client, chunk: chunk)
context = Context.new(@client, chunk:)
if @client.hooks[:map_change]
@client.hooks[:map_change].call(context)
context.verify
@ -121,17 +121,14 @@ class GameClient
def on_chat(chunk)
u = Unpacker.new(chunk.data[1..])
data = {
mode: u.get_int(),
client_id: u.get_int(),
target_id: u.get_int(),
message: u.get_string()
mode: u.get_int,
client_id: u.get_int,
target_id: u.get_int,
message: u.get_string
}
data[:author] = @players[data[:client_id]]
msg = ChatMesage.new(data)
if @client.hooks[:chat]
@client.hooks[:chat].call(msg)
end
@client.hooks[:chat].call(msg) if @client.hooks[:chat]
end
end

View file

@ -44,7 +44,7 @@ class NetBase
eight_bits.join('').to_i(2)
end
header = header + str_bytes(@server_token)
header += str_bytes(@server_token)
data = (header + payload).pack('C*')
@s.send(data, 0, @ip, @port)
@ -54,4 +54,3 @@ class NetBase
end
end
end

View file

@ -1,6 +1,6 @@
GAME_VERSION = "0.7.5"
GAME_NETVERSION_HASH_FORCED = "802f1be60a05665f"
GAME_NETVERSION = "0.7 " + GAME_NETVERSION_HASH_FORCED
GAME_VERSION = '0.7.5'
GAME_NETVERSION_HASH_FORCED = '802f1be60a05665f'
GAME_NETVERSION = '0.7 ' + GAME_NETVERSION_HASH_FORCED
CLIENT_VERSION = 0x0705
NETMSG_NULL = 0
@ -76,7 +76,7 @@ NET_CTRLMSG_ACCEPT = 2
NET_CTRLMSG_CLOSE = 4
NET_CTRLMSG_TOKEN = 5
NET_MAX_SEQUENCE = 1<<10
NET_MAX_SEQUENCE = 1 << 10
NET_CONNSTATE_OFFLINE = 0
NET_CONNSTATE_TOKEN = 1
@ -97,4 +97,3 @@ TARGET_SERVER = -1
PACKET_HEADER_SIZE = 7
CHUNK_HEADER_SIZE = 3

View file

@ -36,9 +36,8 @@ class Packer
num += 1
end
num = num.abs
if num > 63 || num < -63
return self.pack_big_int(sign, num)
end
return pack_big_int(sign, num) if num > 63 || num < -63
ext = '0'
bits = ext + sign + num.to_s(2).rjust(6, '0')
[bits.to_i(2)]
@ -69,26 +68,26 @@ end
class Unpacker
def initialize(data)
@data = data
if data.class == String
@data = data.unpack("C*")
elsif data.class == Array
if data.instance_of?(String)
@data = data.unpack('C*')
elsif data.instance_of?(Array)
@data = data
else
raise "Error: Unpacker expects array of integers or byte string"
raise 'Error: Unpacker expects array of integers or byte string'
end
end
def get_string()
def get_string
return nil if @data.nil?
str = ''
@data.each_with_index do |byte, index|
if byte == 0x00
if index == @data.length - 1
@data = nil
else
@data = @data[(index + 1)..]
end
@data = if index == @data.length - 1
nil
else
@data[(index + 1)..]
end
return str
end
str += byte.chr
@ -98,10 +97,10 @@ class Unpacker
''
end
def get_int()
def get_int
return nil if @data.nil?
# todo: make this more performant
# TODO: make this more performant
# it should not read in ALL bytes
# of the WHOLE packed data
# 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(-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') } == ["11000000", "00000000"]
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') } == %w[11000000 00000000]
# # multi byte int
# p Packer.pack_int(64) == [128, 1]
@ -184,8 +183,8 @@ def todo_also_rspec_unpacker
# p u.get_int() == 64
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
# (-128..128).each do |i|
@ -194,15 +193,14 @@ def todo_also_rspec_unpacker
# end
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)])
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)])
# p u.get_int()
end
# todo_also_rspec_unpacker

View file

@ -6,14 +6,14 @@ class PacketFlags
def initialize(data)
@hash = {}
@bits = ''
if data.class == Hash
if data.instance_of?(Hash)
@bits = parse_hash(data)
@hash = data
elsif data.class == String
elsif data.instance_of?(String)
@hash = parse_bits(data)
@bits = data
else
raise "Flags have to be hash or string"
raise 'Flags have to be hash or string'
end
end
@ -56,12 +56,12 @@ class Packet
@prefix = prefix
@huffman = Huffman.new
@data = data
flags_byte = @data[0].unpack("B*")
flags_byte = @data[0].unpack('B*')
@flags = PacketFlags.new(flags_byte.first[2..5]).hash
@payload = @data[PACKET_HEADER_SIZE..]
if flags_compressed
@payload = @huffman.decompress(@payload.unpack("C*"))
@payload = @payload.pack("C*")
@payload = @huffman.decompress(@payload.unpack('C*'))
@payload = @payload.pack('C*')
end
end
@ -70,37 +70,36 @@ class Packet
token = bytes[3..6].join(' ').green
payload = bytes[7..].join(' ')
puts @prefix + " data: #{[header, token, payload].join(' ')}"
print @prefix + " "
print "header".ljust(3 * 3, ' ').yellow
print "token".ljust(4 * 3, ' ').green
puts "data"
print @prefix + ' '
print 'header'.ljust(3 * 3, ' ').yellow
print 'token'.ljust(4 * 3, ' ').green
puts 'data'
end
def to_s()
puts @prefix + "Packet"
def to_s
puts @prefix + 'Packet'
puts @prefix + " flags: #{@flags}"
bytes = str_hex(@data).split(' ')
# todo: check terminal size?
# TODO: check terminal size?
max_width = 14
rows = bytes.groups_of(max_width)
annotate_first_row(rows.first)
rows[1..].each do |row|
print @prefix + " "
print @prefix + ' '
puts row.join(' ')
end
puts ""
puts ''
end
def flags_compressed()
def flags_compressed
@flags[:compressed]
end
def flags_connless()
def flags_connless
@flags[:connection] == false
end
def flags_control()
def flags_control
@flags[:control]
end
end

View file

@ -1,7 +1,5 @@
class Player
attr_accessor :id, :local, :team, :name, :clan
attr_accessor :country
attr_accessor :skin_parts, :skin_custom_colors, :skin_colors
attr_accessor :id, :local, :team, :name, :clan, :country, :skin_parts, :skin_custom_colors, :skin_colors
def initialize(data = {})
@id = data[:id] || -1
@ -15,4 +13,3 @@ class Player
@skin_colors = data[:skin_colors] || Array.new(6, 0)
end
end

View file

@ -12,4 +12,3 @@ class ServerInfo
"version=#{@version} gametype=#{gametype} map=#{map} name=#{name}"
end
end

View file

@ -22,4 +22,3 @@ class String
colorize(35)
end
end

140
lib/teeworlds-client.rb Normal file → Executable file
View file

@ -28,15 +28,15 @@ class TeeworldsClient
@signal_disconnect = false
@game_client = GameClient.new(self)
@start_info = {
name: "ruby gamer",
clan: "",
name: 'ruby gamer',
clan: '',
country: -1,
body: "spiky",
marking: "duodonny",
decoration: "",
hands: "standard",
feet: "standard",
eyes: "standard",
body: 'spiky',
marking: 'duodonny',
decoration: '',
hands: 'standard',
feet: 'standard',
eyes: 'standard',
custom_color_body: 0,
custom_color_marking: 0,
custom_color_decoration: 0,
@ -74,7 +74,7 @@ class TeeworldsClient
def send_chat(str)
@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),
CHAT_ALL,
@ -86,11 +86,9 @@ class TeeworldsClient
def connect(ip, port, options = {})
options[:detach] = options[:detach] || false
if options[:detach]
if @thread_running
puts "Error: connection thread already running call disconnect() first"
return
end
if options[:detach] && @thread_running
puts 'Error: connection thread already running call disconnect() first'
return
end
disconnect
@signal_disconnect = false
@ -123,13 +121,9 @@ class TeeworldsClient
end
def disconnect
puts "disconnecting."
unless @netbase.nil?
@netbase.send_packet([NET_CTRLMSG_CLOSE], 0, control: true)
end
unless @s.nil?
@s.close
end
puts 'disconnecting.'
@netbase.send_packet([NET_CTRLMSG_CLOSE], 0, control: true) unless @netbase.nil?
@s.close unless @s.nil?
@signal_disconnect = true
end
@ -148,40 +142,40 @@ class TeeworldsClient
@netbase.send_packet(data)
end
def send_ctrl_keepalive()
def send_ctrl_keepalive
@netbase.send_packet([NET_CTRLMSG_KEEPALIVE], 0, control: true)
end
def send_msg_connect()
def send_msg_connect
msg = [NET_CTRLMSG_CONNECT] + str_bytes(@client_token) + Array.new(501, 0x00)
@netbase.send_packet(msg, 0, control: true)
end
def send_ctrl_with_token()
def send_ctrl_with_token
@state = NET_CONNSTATE_TOKEN
msg = [NET_CTRLMSG_TOKEN] + str_bytes(@client_token) + Array.new(512, 0x00)
@netbase.send_packet(msg, 0, control: true)
end
def send_info()
def send_info
data = []
data += Packer.pack_str(GAME_NETVERSION)
data += Packer.pack_str("password")
data += Packer.pack_str('password')
data += Packer.pack_int(CLIENT_VERSION)
msg = NetChunk.create_vital_header({vital: true}, data.size + 1) +
[pack_msg_id(NETMSG_INFO, system: true)] +
data
msg = NetChunk.create_vital_header({ vital: true }, data.size + 1) +
[pack_msg_id(NETMSG_INFO, system: true)] +
data
@netbase.send_packet(msg, 1)
end
def send_msg_startinfo()
def send_msg_startinfo
data = []
@start_info.each do |key, value|
if value.class == String
if value.instance_of?(String)
data += Packer.pack_str(value)
elsif value.class == Integer
elsif value.instance_of?(Integer)
data += Packer.pack_int(value)
else
puts "Error: invalid startinfo #{key}: #{value}"
@ -190,22 +184,24 @@ class TeeworldsClient
end
@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)] +
data
)
end
def send_msg_ready()
def send_msg_ready
@netbase.send_packet(
NetChunk.create_vital_header({vital: true}, 1) +
[pack_msg_id(NETMSG_READY, system: true)])
NetChunk.create_vital_header({ vital: true }, 1) +
[pack_msg_id(NETMSG_READY, system: true)]
)
end
def send_enter_game()
def send_enter_game
@netbase.send_packet(
NetChunk.create_vital_header({vital: true}, 1) +
[pack_msg_id(NETMSG_ENTERGAME, system: true)])
NetChunk.create_vital_header({ vital: true }, 1) +
[pack_msg_id(NETMSG_ENTERGAME, system: true)]
)
end
##
@ -214,12 +210,12 @@ class TeeworldsClient
# Takes a NETMSGTYPE_CL_* integer
# and returns a byte that can be send over
# 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)
end
def send_input
header = [0x10, 0x0A, 01] + str_bytes(@token)
header = [0x10, 0x0A, 0o1] + str_bytes(@token)
random_compressed_input = [
0x4D, 0xE9, 0x48, 0x13, 0xD0, 0x0B, 0x6B, 0xFC, 0xB7, 0x2B, 0x6E, 0x00, 0xBA
]
@ -234,20 +230,20 @@ class TeeworldsClient
end
def on_msg_token(data)
@token = bytes_to_str(data)
@netbase.server_token = @token
puts "Got token #{@token}"
send_msg_connect()
@token = bytes_to_str(data)
@netbase.server_token = @token
puts "Got token #{@token}"
send_msg_connect
end
def on_msg_accept
puts "got accept. connection online"
puts 'got accept. connection online'
@state = NET_CONNSTATE_ONLINE
send_info
end
def on_msg_close
puts "got NET_CTRLMSG_CLOSE"
puts 'got NET_CTRLMSG_CLOSE'
end
private
@ -258,10 +254,10 @@ class TeeworldsClient
when NET_CTRLMSG_TOKEN then on_msg_token(data)
when NET_CTRLMSG_ACCEPT then on_msg_accept
when NET_CTRLMSG_CLOSE then on_msg_close
when NET_CTRLMSG_KEEPALIVE then # silently ignore keepalive
when NET_CTRLMSG_KEEPALIVE # silently ignore keepalive
else
puts "Uknown control message #{msg}"
exit(1)
puts "Uknown control message #{msg}"
exit(1)
end
end
@ -273,14 +269,12 @@ class TeeworldsClient
when NETMSGTYPE_SV_EMOTICON then @game_client.on_emoticon(chunk)
when NETMSGTYPE_SV_CHAT then @game_client.on_chat(chunk)
else
if @verbose
puts "todo non sys chunks. skipped msg: #{chunk.msg}"
end
puts "todo non sys chunks. skipped msg: #{chunk.msg}" if @verbose
end
end
def process_chunk(chunk)
if !chunk.sys
unless chunk.sys
on_message(chunk)
return
end
@ -289,7 +283,7 @@ class TeeworldsClient
when NETMSG_MAP_CHANGE
@game_client.on_map_change(chunk)
when NETMSG_SERVERINFO
puts "ignore server info for now"
puts 'ignore server info for now'
when NETMSG_CON_READY
@game_client.on_connected
when NETMSG_NULL
@ -303,7 +297,7 @@ class TeeworldsClient
def process_server_packet(packet)
data = packet.payload
if data.size.zero?
puts "Error: packet payload is empty"
puts 'Error: packet payload is empty'
puts packet.to_s
return
end
@ -311,9 +305,7 @@ class TeeworldsClient
chunks.each do |chunk|
if chunk.flags_vital && !chunk.flags_resend
@netbase.ack = (@netbase.ack + 1) % NET_MAX_SEQUENCE
if @verbose
puts "got ack: #{@netbase.ack}"
end
puts "got ack: #{@netbase.ack}" if @verbose
end
process_chunk(chunk)
end
@ -327,12 +319,12 @@ class TeeworldsClient
pck = nil
end
if pck.nil? && @token.nil?
@wait_for_token = @wait_for_token || 0
@wait_for_token ||= 0
@wait_for_token += 1
if @wait_for_token > 6
@token = nil
send_ctrl_with_token
puts "retrying connection ..."
puts 'retrying connection ...'
end
end
return unless pck
@ -340,36 +332,30 @@ class TeeworldsClient
data = pck.first
packet = Packet.new(data, '<')
if @verbose
puts packet.to_s
end
puts packet.to_s if @verbose
# process connless packets data
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)..])
else # process non-connless packets
process_server_packet(packet)
end
@ticks += 1
if @ticks % 8 == 0
send_ctrl_keepalive
end
send_ctrl_keepalive if @ticks % 8 == 0
# if @ticks % 20 == 0
# send_chat("hello world")
# end
end
def connection_loop
until @signal_disconnect
tick
# todo: proper tick speed sleep
sleep 0.001
end
@thread_running = false
@signal_disconnect = false
until @signal_disconnect
tick
# TODO: proper tick speed sleep
sleep 0.001
end
@thread_running = false
@signal_disconnect = false
end
end

View file

@ -2,18 +2,18 @@
require_relative 'lib/teeworlds-client'
args = {verbose: false, ip: nil, port: nil}
args = { verbose: false, ip: nil, port: nil }
ARGV.each do |arg|
if arg == '--help' || arg == '-h'
puts "usage: teeworlds.rb [OPTIONS..] [host] [port]"
echo "options:"
echo " --help|-h show this help"
echo " --verbose|-v verbose output"
echo "example:"
echo " teeworlds.rb --verbose localhost 8303"
if ['--help', '-h'].include?(arg)
puts 'usage: teeworlds.rb [OPTIONS..] [host] [port]'
echo 'options:'
echo ' --help|-h show this help'
echo ' --verbose|-v verbose output'
echo 'example:'
echo ' teeworlds.rb --verbose localhost 8303'
exit(0)
elsif arg == '--verbose' || arg == '-v'
elsif ['--verbose', '-v'].include?(arg)
args[:verbose] = true
elsif args[:ip].nil?
args[:ip] = arg

View file

@ -10,4 +10,3 @@ describe 'Array', :array do
end
end
end

View file

@ -1,11 +1,9 @@
require_relative '../lib/packet'
describe 'Packet', :packet do
context 'Set flag bits' 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

View file

@ -3,7 +3,7 @@ require_relative '../lib/chunk'
describe 'NetChunk', :net_chunk do
context 'Create vital header' 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
@ -15,7 +15,7 @@ describe 'BigChungusTheChunkGetter', :chunk_getter do
# one empty motd chunks
data = [
0x40, 0x02, 0x02, 0x02, 0x00
].pack("C*")
].pack('C*')
chunks = BigChungusTheChunkGetter.get_chunks(data)
expect(chunks.size).to eq(1)
end
@ -28,7 +28,7 @@ describe 'BigChungusTheChunkGetter', :chunk_getter do
data = [
0x40, 0x02, 0x02, 0x02, 0x00,
0x40, 0x02, 0x02, 0x02, 0x00
].pack("C*")
].pack('C*')
chunks = BigChungusTheChunkGetter.get_chunks(data)
expect(chunks.size).to eq(2)
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, 0x07, 0x03, 0x22, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, # server settings
0x40, 0x01, 0x04, 0x0b # ready
].pack("C*")
].pack('C*')
chunks = BigChungusTheChunkGetter.get_chunks(data)
expect(chunks.size).to eq(3)
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,
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
].pack("C*")
].pack('C*')
chunks = BigChungusTheChunkGetter.get_chunks(map_change)
expect(chunks.size).to eq(1)
expect(chunks[0].sys).to eq(true)
end
end
end

View file

@ -1,4 +1,3 @@
# frozen_string_literal: true
require 'rake'