Files
whale_town/Scripts/AutoLoad/NetworkManager.gd
WangXiang 6119faf53e init
2025-12-22 18:57:51 +08:00

170 lines
4.3 KiB
GDScript

extends Node
signal connected
signal disconnected
signal login_ok(my_id, players)
signal player_joined(id, name, x, y, skin_id)
signal player_left(id)
signal player_moved(id, x, y, flip_h, frame)
signal chat_message_received(sender_id, text)
signal private_chat_message_received(sender_id, text)
signal notices_received(data)
const DEFAULT_SERVER_URL = "ws://127.0.0.1:8910"
var socket := WebSocketPeer.new()
var my_id: int = -1
var player_info := {"name": "Player", "skin_id": 0}
var players := {} # id -> {name, x, y, skin_id}
var _connected := false
var next_spawn_position: Vector2 = Vector2.ZERO
func _ready():
process_mode = Node.PROCESS_MODE_ALWAYS
func _process(_delta):
socket.poll()
var state = socket.get_ready_state()
if state == WebSocketPeer.STATE_OPEN:
if not _connected:
_connected = true
_on_connected()
while socket.get_available_packet_count():
var packet = socket.get_packet()
_on_message(packet.get_string_from_utf8())
elif state == WebSocketPeer.STATE_CLOSED:
if _connected:
_connected = false
_on_disconnected()
func connect_to_server(url: String = ""):
if url.is_empty():
url = DEFAULT_SERVER_URL
var err = socket.connect_to_url(url)
if err != OK:
print("Failed to connect: ", err)
return err
func _on_connected():
print("Connected to server!")
# Send login
send_json({
"type": "login",
"name": player_info["name"],
"skin_id": player_info["skin_id"]
})
connected.emit()
func _on_disconnected():
print("Disconnected from server")
my_id = -1
players.clear()
disconnected.emit()
func _on_message(data: String):
var json = JSON.new()
var err = json.parse(data)
if err != OK:
print("JSON parse error: ", data)
return
var msg = json.data
# if msg.get("type") == "player_move" and int(msg.get("id", -1)) != my_id:
# print("RAW NET: ", data)
var msg_type = msg.get("type", "")
match msg_type:
"login_ok":
my_id = int(msg["id"])
for p in msg["players"]:
players[int(p["id"])] = {
"name": p["name"],
"x": p["x"],
"y": p["y"],
"skin_id": p["skin_id"]
}
login_ok.emit(my_id, players)
"player_join":
var id = int(msg["id"])
players[id] = {
"name": msg["name"],
"x": msg["x"],
"y": msg["y"],
"skin_id": msg["skin_id"]
}
player_joined.emit(id, msg["name"], msg["x"], msg["y"], msg["skin_id"])
"player_leave":
var id = int(msg["id"])
players.erase(id)
player_left.emit(id)
"player_move":
var id = int(msg["id"])
if id != my_id: # Only log others to reduce spam, or log all? Let's log all for now if issue is critical
print("Net: Recv Move for ID: ", id, " Frame: ", msg.get("frame", 1))
if players.has(id):
players[id]["x"] = msg["x"]
players[id]["y"] = msg["y"]
player_moved.emit(id, msg["x"], msg["y"], msg.get("flip_h", false), int(msg.get("frame", 1)))
"chat":
var id = int(msg["id"])
chat_message_received.emit(id, msg["text"])
"private_chat":
var id = int(msg["sender_id"])
private_chat_message_received.emit(id, msg["text"])
"notices_list":
notices_received.emit(msg.get("data", []))
"scene_peers":
# Refresh player list for new scene
players.clear()
for p in msg["players"]:
players[int(p["id"])] = {
"name": p["name"],
"x": p["x"],
"y": p["y"],
"skin_id": p["skin_id"]
}
# Emit login_ok to trigger refresh (or we could add a scene_loaded signal)
login_ok.emit(my_id, players)
func send_json(obj: Dictionary):
if socket.get_ready_state() == WebSocketPeer.STATE_OPEN:
socket.send_text(JSON.stringify(obj))
func send_move(x: float, y: float, flip_h: bool, frame: int):
send_json({"type": "move", "x": x, "y": y, "flip_h": flip_h, "frame": frame})
func send_change_scene(scene_name: String, pos: Vector2 = Vector2(-20000, -20000)):
var data = {"type": "change_scene", "scene": scene_name}
if pos.x != -20000:
data["x"] = pos.x
data["y"] = pos.y
send_json(data)
func send_message(text: String):
send_json({"type": "chat", "text": text})
func send_private_message(target_id: int, text: String):
send_json({"type": "private_chat", "target_id": target_id, "text": text})
func request_notices():
send_json({"type": "get_notices"})
func set_player_name(n: String):
player_info["name"] = n
func set_skin_id(id: int):
player_info["skin_id"] = id