mc-server-gdscript/main.gd

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)