Class: NetChunk

Inherits:
Object
  • Object
show all
Defined in:
lib/chunk.rb

Overview

The NetChunk class represents one individual chunk of a teeworlds packet.

A teeworlds packet holds multiple game and system messages as its payload, those are called chunks or messages.

chillerdragon.github.io/teeworlds-protocol/07/packet_layout.html

Constant Summary collapse

@@sent_vital_chunks =
0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ NetChunk

Returns a new instance of NetChunk.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/chunk.rb', line 20

def initialize(data)
  @next = nil
  @flags = {}
  @size = 0
  parse_header(data[0..2])
  header_size = if flags_vital
                  VITAL_CHUNK_HEADER_SIZE
                else
                  NON_VITAL_CHUNK_HEADER_SIZE
                end
  @header_raw = data[...header_size]
  chunk_end = header_size + @size
  # puts "data[0]: " + str_hex(data[0])
  @data = data[header_size...chunk_end]
  @msg = @data[0].unpack1('C*')
  @sys = @msg & 1 == 1
  @msg >>= 1
  @next = data[chunk_end..] if data.size > chunk_end
  @full_raw = data[..chunk_end]
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



16
17
18
# File 'lib/chunk.rb', line 16

def data
  @data
end

#flagsObject (readonly)

Returns the value of attribute flags.



16
17
18
# File 'lib/chunk.rb', line 16

def flags
  @flags
end

#full_rawObject (readonly)

Returns the value of attribute full_raw.



16
17
18
# File 'lib/chunk.rb', line 16

def full_raw
  @full_raw
end

#header_rawObject (readonly)

Returns the value of attribute header_raw.



16
17
18
# File 'lib/chunk.rb', line 16

def header_raw
  @header_raw
end

#msgObject (readonly)

Returns the value of attribute msg.



16
17
18
# File 'lib/chunk.rb', line 16

def msg
  @msg
end

#nextObject (readonly)

Returns the value of attribute next.



16
17
18
# File 'lib/chunk.rb', line 16

def next
  @next
end

#sysObject (readonly)

Returns the value of attribute sys.



16
17
18
# File 'lib/chunk.rb', line 16

def sys
  @sys
end

Class Method Details

._create_non_vital_header(data = { size: 0 }) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/chunk.rb', line 53

def self._create_non_vital_header(data = { size: 0 })
  flag_bits = '00'
  unused_bits = '00'

  size_bits = data[:size].to_s(2).rjust(12, '0')
  header_bits =
    flag_bits +
    size_bits[0..5] +
    unused_bits +
    size_bits[6..]
  header_bits.chars.groups_of(8).map do |eigth_bits|
    eigth_bits.join.to_i(2)
  end
end

.create_header(opts = { resend: false, vital: false, size: nil, seq: nil, client: nil }) ⇒ Object

Create int array ready to be send over the network

Given the flags hash (vital/resend) the size the sequence number

It will create a 3 byte chunk header represented as an Array of 3 integers



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/chunk.rb', line 77

def self.create_header(opts = { resend: false, vital: false, size: nil, seq: nil, client: nil })
  raise 'Chunk.create_header :size option can not be nil' if opts[:size].nil?
  return _create_non_vital_header(opts) unless opts[:vital]

  # client only counts this class var
  @@sent_vital_chunks += 1
  seq = opts[:seq].nil? ? @@sent_vital_chunks : opts[:seq]

  # server counts per client
  unless opts[:client].nil?
    opts[:client].vital_sent += 1
    seq = opts[:client].vital_sent
  end

  flag_bits = '00'.dup
  flag_bits[0] = opts[:resend] ? '1' : '0'
  flag_bits[1] = opts[:vital] ? '1' : '0'

  size_bits = opts[:size].to_s(2).rjust(12, '0')
  # size_bits[0..5]
  # size_bits[6..]

  seq_bits = seq.to_s(2).rjust(10, '0')
  # seq_bits[0..1]
  # seq_bits[2..]

  # The vital chunk header is 3 bytes
  # containing flags, size and sequence
  # in the following format
  #
  # f=flag
  # s=size
  # q=sequence
  #
  # ffss ssss qqss ssss qqqq qqqq
  header_bits =
    flag_bits +
    size_bits[0..5] +
    seq_bits[0..1] +
    size_bits[6..] +
    seq_bits[2..]
  header_bits.chars.groups_of(8).map do |eigth_bits|
    eigth_bits.join.to_i(2)
  end
end

.resetObject



41
42
43
# File 'lib/chunk.rb', line 41

def self.reset
  @@sent_vital_chunks = 0
end

Instance Method Details

#flags_resendBoolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/chunk.rb', line 148

def flags_resend
  @flags[:resend]
end

#flags_vitalBoolean

Returns:

  • (Boolean)


143
144
145
# File 'lib/chunk.rb', line 143

def flags_vital
  @flags[:vital]
end

#parse_header(data) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/chunk.rb', line 123

def parse_header(data)
  # flags
  flags = data[0].unpack1('B*')
  flags = flags[0..1]
  @flags[:resend] = flags[0] == '1'
  @flags[:vital] = flags[1] == '1'

  # size
  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 = size_bytes.join.to_i(2)

  # sequence number
  # in da third byte but who needs seq?!
end

#to_sObject



45
46
47
48
49
50
51
# File 'lib/chunk.rb', line 45

def to_s
  "NetChunk\n" \
    "  msg=#{msg} sys=#{sys}\n" \
    "  #{@flags}\n" \
    "  header: #{str_hex(header_raw)}\n" \
    "  data: #{str_hex(data)}"
end