157 lines
4.2 KiB
GDScript
157 lines
4.2 KiB
GDScript
extends Node2D
|
|
|
|
var server: TCPServer = null
|
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
func _ready():
|
|
server = TCPServer.new()
|
|
var status = server.listen(25565)
|
|
if status != OK:
|
|
print('статус не ок')
|
|
|
|
var segment_bits = 0x7F
|
|
var continue_bit = 0x80
|
|
|
|
func read_var_int(conn: StreamPeerTCP):
|
|
var value = 0
|
|
var position = 0
|
|
var byte
|
|
while true:
|
|
byte = conn.get_8()
|
|
value |= (byte & segment_bits) << position
|
|
if (byte & continue_bit) == 0: break
|
|
position += 7
|
|
|
|
if position >= 32:
|
|
assert(false, 'varint слишком большой')
|
|
|
|
return value
|
|
|
|
func shr(value: int, shift: int):
|
|
if value < 0:
|
|
return ((-value) >> shift) | (0x7000 >> shift)
|
|
return value >> shift
|
|
|
|
func write_var_int_test(value: int):
|
|
var result = 0
|
|
while true:
|
|
if (value & ~segment_bits) == 0:
|
|
result = (result << 8) | value
|
|
return result
|
|
result = (result << 8) | ((value & segment_bits) | continue_bit)
|
|
|
|
value = shr(value, 7)
|
|
|
|
func write_var_int(value: int, conn: StreamPeerTCP):
|
|
var result = 0
|
|
while true:
|
|
if (value & ~segment_bits) == 0:
|
|
conn.put_8(value)
|
|
print('%x' % value)
|
|
return
|
|
conn.put_8((value & segment_bits) | continue_bit)
|
|
print('%x' % ((value & segment_bits) | continue_bit))
|
|
|
|
value = shr(value, 7)
|
|
return result
|
|
|
|
func read_minecraft_string(conn: StreamPeerTCP):
|
|
var character_count = read_var_int(conn)
|
|
var str = ""
|
|
while character_count > 0:
|
|
var byte = conn.get_8()
|
|
character_count -= 1
|
|
if byte < 0x80:
|
|
# 1 byte sequence (ASCII)
|
|
str += char(byte)
|
|
elif byte < 0xE0:
|
|
str += char(((byte & 0x1F) << 6) | (conn.get_8() & 0x3F))
|
|
character_count -= 1
|
|
elif byte < 0xF0:
|
|
# 3 byte sequence
|
|
str += char(((byte & 0x0F) << 12) | ((conn.get_8() & 0x3F) << 6) | (conn.get_8() & 0x3F))
|
|
character_count -= 1
|
|
else:
|
|
# 4 byte sequence (very rare)
|
|
str += char(((byte & 0x07) << 18) | ((conn.get_8() & 0x3F) << 12) | ((conn.get_8() & 0x3F) << 6) | (conn.get_8() & 0x3F))
|
|
character_count -= 1
|
|
return str
|
|
|
|
func handle(conn: StreamPeerTCP):
|
|
var size = read_var_int(conn)
|
|
print('size %s' % size)
|
|
var packet_id = conn.get_8()
|
|
print('packet_id %s' % packet_id)
|
|
if packet_id != 0x00: return false
|
|
var protocol_version = read_var_int(conn)
|
|
print('Protocol version: ', protocol_version)
|
|
var host = read_minecraft_string(conn)
|
|
print('Host %s' % host)
|
|
var port = conn.get_16()
|
|
print('Port %s' % port)
|
|
var next_state = read_var_int(conn)
|
|
print('Next state %s' % next_state)
|
|
if next_state != 1: return false
|
|
|
|
size = read_var_int(conn)
|
|
print('size %s' % size)
|
|
packet_id = conn.get_8()
|
|
print('packet_id %s' % packet_id)
|
|
if packet_id != 0x00: return false
|
|
var response = str({
|
|
"version": {
|
|
"name": "1.19.3",
|
|
"protocol": protocol_version
|
|
},
|
|
"players": {
|
|
"max": 100,
|
|
"online": 5,
|
|
"sample": [
|
|
{
|
|
"name": "thinkofdeath",
|
|
"id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"
|
|
}
|
|
]
|
|
},
|
|
"description": {
|
|
"text": "Hello world"
|
|
},
|
|
"enforcesSecureChat": true
|
|
})
|
|
|
|
print('отправляем данные')
|
|
conn.put_8(0x00)
|
|
size = write_var_int_test(response.length())
|
|
print('size %s; ' % response.length(), '%x' % size)
|
|
write_var_int(response.length(), conn)
|
|
|
|
conn.poll()
|
|
print('status %s' % conn.get_status())
|
|
|
|
conn.put_data(response.to_utf8_buffer())
|
|
print('отправили данные')
|
|
|
|
print('client sent something')
|
|
return true
|
|
|
|
var conns: Array[StreamPeerTCP] = []
|
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
func _process(delta):
|
|
for i in range(conns.size() - 1, -1, -1):
|
|
var conn = conns[i]
|
|
conn.poll()
|
|
if conn.get_status() != 2:
|
|
print('Connection %s:%s has status %s, killing' % [conn.get_connected_host(), conn.get_connected_port(), conn.get_status()])
|
|
conns.remove_at(i)
|
|
|
|
if server.is_connection_available():
|
|
var conn: StreamPeerTCP = server.take_connection()
|
|
conn.big_endian = true
|
|
print('Took connection from %s:%s, status %s' % [conn.get_connected_host(), conn.get_connected_port(), conn.get_status()])
|
|
var status = handle(conn)
|
|
if not status:
|
|
print('Сервер отклонил подключение по причине пошёл нафиг')
|
|
conn.disconnect_from_host()
|
|
print()
|
|
conns.push_back(conn)
|