Unhardcode the last packet (startinfo)

Also support bigger integers than 63 :)
This commit is contained in:
ChillerDragon 2022-11-04 12:30:41 +01:00
parent 2c8e6aeb8f
commit 57a8f0bcc7
4 changed files with 82 additions and 57 deletions

View file

@ -4,7 +4,7 @@ require_relative 'bytes'
class NetChunk
attr_reader :next, :data, :msg, :sys, :flags
@@sent_vital_chunks = 1
@@sent_vital_chunks = 0
def initialize(data)
@next = nil

View file

@ -1,18 +1,7 @@
# randomize this
MY_TOKEN = [0x73, 0x34, 0xB4, 0xA0]
MSG_TOKEN = [0x04, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x05] + MY_TOKEN + Array.new(512, 0x00)
MSG_INFO = [0x40, 0x19, 0x01, 0x03, 0x30, 0x2E, 0x37, 0x20, 0x38, 0x30, 0x32, 0x66, # @...0.7 802f
0x31, 0x62, 0x65, 0x36, 0x30, 0x61, 0x30, 0x35, 0x36, 0x36, 0x35, 0x66, # 1be60a05665f
0x00, 0x00, 0x85, 0x1C]
MSG_STARTINFO = [0x41, 0x19, 0x03, 0x36, 0x6E, 0x61, 0x6D, 0x65 , 0x6C, 0x65, 0x73, 0x73, # A..6nameless
0x20, 0x6D, 0x65, 0x00, 0x00, 0x40, 0x67, 0x72 , 0x65, 0x65, 0x6E, 0x73, # me..@greens
0x77, 0x61, 0x72, 0x64, 0x00, 0x64, 0x75, 0x6F , 0x64, 0x6F, 0x6E, 0x6E, # ward.duodonn
0x79, 0x00, 0x00, 0x73, 0x74, 0x61, 0x6E, 0x64 , 0x61, 0x72, 0x64, 0x00, # y..standard
0x73, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64 , 0x00, 0x73, 0x74, 0x61, # standard.sta
0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x01, 0x01 , 0x00, 0x00, 0x00, 0x00, # ndard.......
0x80, 0xFC, 0xAF, 0x05, 0xEB, 0x83, 0xD0, 0x0A , 0x80, 0xFE, 0x07, 0x80, # ............
0xFE, 0x07, 0x80, 0xFE, 0x07, 0x80, 0xFE, 0x07]
GAME_VERSION = "0.7.5"
GAME_NETVERSION_HASH_FORCED = "802f1be60a05665f"
GAME_NETVERSION = "0.7 " + GAME_NETVERSION_HASH_FORCED
CLIENT_VERSION = 0x0705
NETMSG_NULL = 0
NETMSG_INFO = 1

View file

@ -1,62 +1,87 @@
require_relative 'array'
class Packer
# poor mans int packer
# homebrew not covering
# the full tw fancyness
#
# Format: ESDDDDDD EDDDDDDD EDD... Extended, Data, Sign
def self.pack_int(num)
if num > 63 || num < -63
# the first byte can fit 6 bits
# because the first two bits are extended and sign
# so if you have a number bigger than 63
# it needs two bytes
# which are also least significant byte first etc
# so we do not support that YET
#
# the first too big number 64 is represented as those bits
# 10000000 00000001
# ^^^ ^ ^ ^
# ||\ / \ /
# || \ / \ /
# || \ \/
# || \ /
# || \ /
# || \ /
# || \/
# || /\
# || / \
# || / \
# || 00000001 000000
# || |
# || v
# || 64
# ||
# |positive
# extended
raise "Numbers greater than 63 are not supported yet"
end
# the first byte can fit 6 bits
# because the first two bits are extended and sign
# so if you have a number bigger than 63
# it needs two bytes
# which are also least significant byte first etc
# so we do not support that YET
#
# the first too big number 64 is represented as those bits
# 10000000 00000001
# ^^^ ^ ^ ^
# ||\ / \ /
# || \ / \ /
# || \ \/
# || \ /
# || \ /
# || \ /
# || \/
# || /\
# || / \
# || / \
# || 00000001 000000
# || |
# || v
# || 64
# ||
# |positive
# extended
sign = '0'
if num.negative?
sign = '1'
num += 1
end
num = num.abs
if num > 63 || num < -63
return self.pack_big_int(sign, num)
end
ext = '0'
bits = ext + sign + num.to_s(2).rjust(6, '0')
[bits.to_i(2)]
end
def self.pack_big_int(sign, num)
num_bits = num.to_s(2)
first = '1' + sign + num_bits[-6..]
num_bits = num_bits[0..-7]
bytes = []
num_bits.chars.groups_of(7).each do |seven_bits|
# mark all as extended
bytes << '1' + seven_bits.join('').rjust(7, '0')
end
# least significant first
bytes = bytes.reverse
# mark last byte as unextended
bytes[-1][0] = '0'
([first] + bytes).map { |b| b.to_i(2) }
end
def self.pack_str(str)
str.chars.map(&:ord) + [0x00]
end
end
def todo_make_this_rspec_test
# single byte int
p Packer.pack_int(1) == [1]
p Packer.pack_int(3) == [3]
p Packer.pack_int(16) == [16]
p Packer.pack_int(63) == [63]
p Packer.pack_int(3) == [3]
# negative single byte
p Packer.pack_int(-1) == [64]
p Packer.pack_int(-2) == [65]
# todo
# p Packer.pack_int(64) == [64]
# multi byte int
p Packer.pack_int(64) == [128, 1]
p Packer.pack_int(99999999999999999) == [191, 131, 255, 147, 246, 194, 215, 232, 88]
# string
p Packer.pack_str("A") == [65, 0]
end

View file

@ -39,7 +39,9 @@ class TwClient
end
end
@ticks = 0
@client_token = MY_TOKEN.map { |b| b.to_s(16) }.join('')
# me trying to write cool code
@client_token = (1..4).to_a.map { |_| rand(0..255) }
@client_token = @client_token.map { |b| b.to_s(16) }.join('')
puts "client token #{@client_token}"
@netbase = NetBase.new
@netbase.client_token = @client_token
@ -99,7 +101,15 @@ class TwClient
end
def send_info()
send_msg(MSG_INFO)
data = []
data += Packer.pack_str(GAME_NETVERSION)
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
@netbase.send_packet(msg, 1)
end
def send_msg_startinfo()
@ -131,7 +141,7 @@ class TwClient
start_info.each do |key, value|
if value.class == String
data += value.chars.map(&:ord) + [0x00]
data += Packer.pack_str(value)
elsif value.class == Integer
data += Packer.pack_int(value)
else
@ -177,7 +187,8 @@ class TwClient
CHAT_ALL,
64 # should use TARGET_SERVER (-1) instead of hacking 64 in here
] +
str.chars.map(&:ord) + [0x00])
Packer.pack_str(str)
)
end
def send_input