refactor(debug-mod): 使用原生 System 替换 QuMod
删除未使用的大型 QuMod 加载框架,改为直接注册客户端和服务端 System,并显式管理按键监听、输出包装与双端销毁。 IPC 网络线程仅负责收包,所有 ModAPI 回调由游戏线程 Update 派发,同时补充断线重连、分帧读取和幂等关闭。
This commit is contained in:
@@ -4,6 +4,7 @@ import mod.client.extraClientApi as clientApi
|
||||
from .Config import GET_DEBUG_IPC_PORT
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
import json
|
||||
|
||||
def U16_BE(b):
|
||||
@@ -24,74 +25,162 @@ class IPCSystem:
|
||||
self.port = port
|
||||
self.sock = None
|
||||
self.mLock = threading.Lock()
|
||||
self.handers = {}
|
||||
self.handlers = {}
|
||||
self.pendingLock = threading.Lock()
|
||||
self.pendingClient = []
|
||||
self.pendingServer = []
|
||||
self.running = False
|
||||
self.generation = 0
|
||||
self.thread = None
|
||||
self.nextStartTime = 0.0
|
||||
|
||||
def registerHandler(self, typeID, handler):
|
||||
# type: (int, callable) -> None
|
||||
self.handers[typeID] = handler
|
||||
self.handlers[typeID] = handler
|
||||
|
||||
def updateHandlers(self, handlers):
|
||||
# type: (dict[int, callable]) -> None
|
||||
self.handers.update(handlers)
|
||||
self.handlers.update(handlers)
|
||||
|
||||
def start(self):
|
||||
if self.sock or not self.port:
|
||||
return
|
||||
threading.Thread(target=self._threadListenLoop).start()
|
||||
now = time.time()
|
||||
with self.mLock:
|
||||
if self.running or not self.port or now < self.nextStartTime:
|
||||
return
|
||||
self.running = True
|
||||
self.nextStartTime = now + 1.0
|
||||
self.generation += 1
|
||||
generation = self.generation
|
||||
thread = threading.Thread(
|
||||
target=self._threadListenLoop,
|
||||
args=(generation,),
|
||||
)
|
||||
thread.daemon = True
|
||||
self.thread = thread
|
||||
thread.start()
|
||||
|
||||
def close(self):
|
||||
sock = None
|
||||
with self.mLock:
|
||||
self.running = False
|
||||
self.generation += 1
|
||||
self.nextStartTime = 0.0
|
||||
sock = self.sock
|
||||
self.sock = None
|
||||
thread = self.thread
|
||||
if sock:
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
sock.close()
|
||||
|
||||
def _threadListenLoop(self):
|
||||
with self.mLock:
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock = self.sock
|
||||
sock.connect(("localhost", self.port))
|
||||
sock.settimeout(0.05)
|
||||
print("[IPCSystem] 已连接到调试服务器,端口:" + str(self.port))
|
||||
# [2B TypeID][4B DataLength][Data]
|
||||
def _recvAll(sock, length):
|
||||
# type: (socket.socket, int) -> bytearray
|
||||
buf = bytearray()
|
||||
while len(buf) < length:
|
||||
more = sock.recv(length - len(buf))
|
||||
if not more:
|
||||
raise EOFError("Socket closed before receiving all data")
|
||||
buf.extend(more)
|
||||
return buf
|
||||
while 1:
|
||||
try:
|
||||
header = _recvAll(sock, 6)
|
||||
typeID = U16_BE(header[0:2])
|
||||
dataLength = U32_BE(header[2:6])
|
||||
data = _recvAll(sock, dataLength)
|
||||
except socket.timeout:
|
||||
continue
|
||||
except EOFError:
|
||||
break
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
except socket.error:
|
||||
break
|
||||
pass
|
||||
try:
|
||||
sock.close()
|
||||
except socket.error:
|
||||
pass
|
||||
if thread:
|
||||
thread.join(1.0)
|
||||
with self.pendingLock:
|
||||
self.pendingClient = []
|
||||
self.pendingServer = []
|
||||
|
||||
def updateClient(self):
|
||||
self.start()
|
||||
with self.pendingLock:
|
||||
pending = self.pendingClient
|
||||
self.pendingClient = []
|
||||
self._runPending(pending)
|
||||
|
||||
def updateServer(self):
|
||||
with self.pendingLock:
|
||||
pending = self.pendingServer
|
||||
self.pendingServer = []
|
||||
self._runPending(pending)
|
||||
|
||||
@staticmethod
|
||||
def _runPending(pending):
|
||||
for handler, data in pending:
|
||||
try:
|
||||
handler(data)
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
break
|
||||
if typeID in self.handers:
|
||||
try:
|
||||
self.handers[typeID](data)
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
else:
|
||||
print("[IPCSystem] 未知的TypeID数据包:" + str(typeID))
|
||||
|
||||
def _threadListenLoop(self, generation):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
with self.mLock:
|
||||
self.sock = None
|
||||
print("[IPCSystem] 连接已关闭")
|
||||
if not self.running or generation != self.generation:
|
||||
sock.close()
|
||||
return
|
||||
self.sock = sock
|
||||
|
||||
try:
|
||||
sock.settimeout(2.0)
|
||||
sock.connect(("localhost", self.port))
|
||||
sock.settimeout(0.2)
|
||||
print("[IPCSystem] 已连接到调试服务器,端口:" + str(self.port))
|
||||
while self._isCurrent(generation, sock):
|
||||
header = self._recvAll(generation, sock, 6)
|
||||
typeID = U16_BE(header[0:2])
|
||||
dataLength = U32_BE(header[2:6])
|
||||
data = self._recvAll(generation, sock, dataLength)
|
||||
self._queueHandler(generation, typeID, data)
|
||||
except EOFError:
|
||||
pass
|
||||
except socket.error:
|
||||
if self._isCurrent(generation, sock):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
try:
|
||||
sock.close()
|
||||
except socket.error:
|
||||
pass
|
||||
with self.mLock:
|
||||
if self.sock is sock:
|
||||
self.sock = None
|
||||
if self.thread is threading.currentThread():
|
||||
self.thread = None
|
||||
if generation == self.generation:
|
||||
self.running = False
|
||||
print("[IPCSystem] 连接已关闭")
|
||||
|
||||
def _isCurrent(self, generation, sock):
|
||||
with self.mLock:
|
||||
return (
|
||||
self.running
|
||||
and generation == self.generation
|
||||
and self.sock is sock
|
||||
)
|
||||
|
||||
def _queueHandler(self, generation, typeID, data):
|
||||
handler = self.handlers.get(typeID)
|
||||
if handler is None:
|
||||
print("[IPCSystem] 未知的TypeID数据包:" + str(typeID))
|
||||
return
|
||||
with self.mLock:
|
||||
if not self.running or generation != self.generation:
|
||||
return
|
||||
with self.pendingLock:
|
||||
if typeID == 4:
|
||||
self.pendingServer.append((handler, data))
|
||||
else:
|
||||
self.pendingClient.append((handler, data))
|
||||
|
||||
def _recvAll(self, generation, sock, length):
|
||||
buf = bytearray()
|
||||
while len(buf) < length:
|
||||
try:
|
||||
more = sock.recv(length - len(buf))
|
||||
except socket.timeout:
|
||||
if not self._isCurrent(generation, sock):
|
||||
raise EOFError("IPC connection stopped")
|
||||
continue
|
||||
if not more:
|
||||
raise EOFError("Socket closed before receiving all data")
|
||||
buf.extend(more)
|
||||
return buf
|
||||
|
||||
_CL_GAME_COMP = None
|
||||
_SR_GAME_COMP = None
|
||||
@@ -168,14 +257,25 @@ _IPCSYSTEM.updateHandlers(
|
||||
}
|
||||
)
|
||||
|
||||
def UPDATE_CLIENT():
|
||||
_IPCSYSTEM.updateClient()
|
||||
|
||||
def UPDATE_SERVER():
|
||||
_IPCSYSTEM.updateServer()
|
||||
|
||||
def ON_CLIENT_INIT():
|
||||
global _CL_GAME_COMP
|
||||
_CL_GAME_COMP = clientApi.GetEngineCompFactory().CreateGame(clientApi.GetLevelId())
|
||||
_IPCSYSTEM.start()
|
||||
|
||||
def ON_CLIENT_EXIT():
|
||||
global _CL_GAME_COMP
|
||||
_IPCSYSTEM.close()
|
||||
_CL_GAME_COMP = None
|
||||
|
||||
def ON_SERVER_INIT():
|
||||
global _SR_GAME_COMP
|
||||
_SR_GAME_COMP = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())
|
||||
_SR_GAME_COMP = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())
|
||||
|
||||
def ON_SERVER_EXIT():
|
||||
global _SR_GAME_COMP
|
||||
_SR_GAME_COMP = None
|
||||
|
||||
Reference in New Issue
Block a user