Drop known chunks. Fixes duplicated chat messages.

This commit is contained in:
ChillerDragon 2024-06-24 11:42:08 +08:00
parent deb679d1d0
commit af7367be0c
3 changed files with 42 additions and 6 deletions

View file

@ -13,13 +13,14 @@ require_relative 'bytes'
#
# https://chillerdragon.github.io/teeworlds-protocol/07/packet_layout.html
class NetChunk
attr_reader :next, :data, :msg, :sys, :flags, :header_raw, :full_raw
attr_reader :next, :data, :msg, :sys, :flags, :seq, :header_raw, :full_raw
@@sent_vital_chunks = 0
def initialize(data)
@next = nil
@flags = {}
@seq = 0
@size = 0
parse_header(data[0..2])
header_size = if flags_vital
@ -135,8 +136,12 @@ class NetChunk
size_bytes.map! { |b| b[2..].join }
@size = size_bytes.join.to_i(2)
# sequence number
# in da third byte but who needs seq?!
if @flags[:vital]
data = data[0..2].bytes
@seq = (data[1] & (0xC0 << 2)) | data[2]
else
@seq = 0
end
end
# @return [Boolean]

20
lib/connection.rb Normal file
View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
##
# Only used for chunks where the sequence number does not match the expected value
# to decide wether to drop known chunks silently or request resend if something got lost
#
# true - if the sequence number is already known and the chunk should be dropped
# false - if the sequence number is off and we need to request a resend of lost chunks
#
# @return [Boolean]
def seq_in_backroom?(seq, ack)
bottom = ack - (NET_MAX_SEQUENCE / 2)
if bottom.negative?
return true if seq <= ack
return true if seq >= (bottom + NET_MAX_SEQUENCE)
elsif seq <= ack && seq >= bottom
return true
end
false
end

View file

@ -14,6 +14,7 @@ require_relative 'packer'
require_relative 'models/player'
require_relative 'game_client'
require_relative 'config'
require_relative 'connection'
class TeeworldsClient
attr_reader :state, :hooks, :game_client, :verbose_snap
@ -445,9 +446,19 @@ class TeeworldsClient
end
chunks = BigChungusTheChunkGetter.get_chunks(data)
chunks.each do |chunk|
if chunk.flags_vital && !chunk.flags_resend && chunk.msg != NETMSG_NULL
@netbase.ack = (@netbase.ack + 1) % NET_MAX_SEQUENCE
puts "got ack: #{@netbase.ack}" if @verbose
if chunk.flags_vital
if chunk.seq == (@netbase.ack + 1) % NET_MAX_SEQUENCE
# in sequence
@netbase.ack = (@netbase.ack + 1) % NET_MAX_SEQUENCE
else
puts "warning: got chunk out of sequence! seq=#{chunk.seq} expected_seq=#{(@netbase.ack + 1) % NET_MAX_SEQUENCE}"
if seq_in_backroom?(chunk.seq, @netbase.ack)
puts ' dropping known chunk ...'
next
end
# TODO: request resend
puts ' REQUESTING RESEND NOT IMPLEMENTED'
end
end
process_chunk(chunk)
end