ue4 开放exec接口 vscode mcp铺垫 unreal.register_slate_post_tick_callback

有了这个py就可以为所欲为的调用ue4了

关键就是这个unreal.register_slate_post_tick_callback

我之前跑怎么搞都会报错线程问题

ue 二次开放 开放exec遇到线程问题IsInGameThread()_游戏-CSDN问答

python 复制代码
import unreal
import socket
import select
import threading
from queue import Queue
import os
import json

def execute_unreal_command(code_string):
    """
    执行传入的Python代码字符串
    """
    try:
        # 添加调试输出,完整记录执行的代码
       
        unreal.log(f"执行的代码:\n{code_string}")
        # 使用globals()和locals()提供当前环境的上下文
        # exec执行代码并捕获输出
        local_vars = {'unreal': unreal}
        # 使用compile来预编译代码,可以更好地处理多行代码
        compiled_code = compile(code_string, '<string>', 'exec')
        
        exec(compiled_code, globals(), local_vars)
        return "代码执行成功"
    except SyntaxError as e:
        error_msg = f"语法错误: {str(e)} (文件: {e.filename}, 行号: {e.lineno}, 文本: {e.text})"
        unreal.log_error(error_msg)
        return error_msg
    except Exception as e:
        error_msg = f"执行错误: {str(e)}"
        unreal.log_error(error_msg)
        return error_msg

class SimpleJsonServer:
    def __init__(self):
        self.socket = None
        self.clients = []
        self.should_stop = False
        self.tick_handle = None
        
    def start_server(self, port=8070):
        """启动基于Tick的简单JSON服务器"""
        try:
            # 创建非阻塞socket
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.socket.bind(('', port))
            self.socket.listen(5)
            self.socket.setblocking(False)  # 设置为非阻塞模式
            
            # 注册tick函数
            self.tick_handle = unreal.register_slate_post_tick_callback(
                self.process_requests
            )
            
            unreal.log(f"基于Tick的简单JSON服务器启动在端口 {port}")
            return True
            
        except Exception as e:
            unreal.log_error(f"服务器启动失败: {str(e)}")
            return False
    
    def process_requests(self, delta_time):
        """在UE的tick中处理请求"""
        if self.should_stop:
            self.stop_server()
            return
            
        try:
            # 检查是否有新的连接或数据
            ready, _, error = select.select([self.socket] + self.clients, [], self.clients, 0)
            
            # 处理错误的连接
            for err_sock in error:
                if err_sock in self.clients:
                    self.clients.remove(err_sock)
                    err_sock.close()
            
            for sock in ready:
                if sock == self.socket:
                    # 新连接
                    try:
                        client, addr = self.socket.accept()
                        client.setblocking(False)  # 客户端也设为非阻塞
                        self.clients.append(client)
                        unreal.log(f"新连接来自: {addr}")
                    except:
                        pass  # 非阻塞accept可能失败
                else:
                    # 处理客户端数据
                    try:
                        # 尝试接收完整的JSON数据
                        full_data = b""
                        while True:
                            try:
                                chunk = sock.recv(4096)  # 增加接收缓冲区大小
                                if not chunk:
                                    break
                                full_data += chunk
                                # 如果数据块小于缓冲区大小,可能数据接收完毕
                                if len(chunk) < 4096:
                                    break
                            except BlockingIOError:
                                # 非阻塞socket没有数据可读,跳出循环
                                break
                            except ConnectionResetError:
                                # 连接被重置
                                if sock in self.clients:
                                    self.clients.remove(sock)
                                sock.close()
                                raise
                            except Exception as e:
                                # 其他错误
                                unreal.log_error(f"接收数据时出错: {str(e)}")
                                if sock in self.clients:
                                    self.clients.remove(sock)
                                sock.close()
                                raise
                        
                        # 如果接收到数据
                        if full_data:
                            data_str = full_data.decode('utf-8')
                            self.handle_request(sock, data_str)
                        else:
                            # 客户端断开连接
                            if sock in self.clients:
                                self.clients.remove(sock)
                            sock.close()
                    except BlockingIOError:
                        # 非阻塞socket没有数据可读
                        pass
                    except ConnectionResetError:
                        # 连接被重置
                        if sock in self.clients:
                            self.clients.remove(sock)
                        sock.close()
                    except Exception as e:
                        # 其他错误
                        unreal.log_error(f"处理客户端数据时出错: {str(e)}")
                        if sock in self.clients:
                            self.clients.remove(sock)
                        sock.close()
                        
        except Exception as e:
            unreal.log_warning(f"处理请求时出错: {str(e)}")
    
    def handle_request(self, client_socket, data):
        """处理请求并发送响应 - 纯JSON格式"""
        try:
            # 直接解析JSON数据,不处理HTTP头部
            request_data = json.loads(data)
            code_to_execute = request_data.get('code', '')
            
            if code_to_execute:
                # 执行传入的代码
                result = execute_unreal_command(code_to_execute)
                # 直接返回结果,不使用HTTP响应格式
                client_socket.send(result.encode('utf-8'))
            else:
                error_msg = "错误: 未提供要执行的代码"
                client_socket.send(error_msg.encode('utf-8'))
            
        except json.JSONDecodeError as e:
            error_msg = f"错误: 无效的JSON格式 - {str(e)}"
            unreal.log_error(error_msg)
            try:
                client_socket.send(error_msg.encode('utf-8'))
            except:
                pass
        except Exception as e:
            error_msg = f"处理请求时发生未知错误: {str(e)}"
            unreal.log_error(error_msg)
            try:
                client_socket.send(error_msg.encode('utf-8'))
            except:
                pass
        finally:
            # 关闭连接
            if client_socket in self.clients:
                self.clients.remove(client_socket)
            try:
                client_socket.close()
            except:
                pass
    
    def stop_server(self):
        """停止服务器"""
        self.should_stop = True
        
        # 移除tick回调
        if self.tick_handle:
            unreal.unregister_slate_tick_callback(self.tick_handle)
            self.tick_handle = None
        
        # 关闭所有连接
        for client in self.clients:
            try:
                client.close()
            except:
                pass
        self.clients.clear()
        
        # 关闭服务器socket
        if self.socket:
            try:
                self.socket.close()
            except:
                pass
            self.socket = None
        
        unreal.log("简单JSON服务器已停止")

def start_simple_json_server():
    """启动简单JSON服务器"""
    server = SimpleJsonServer()
    if server.start_server(8070):
        # 保存服务器实例以便后续控制
        if not hasattr(start_simple_json_server, 'server_instance'):
            start_simple_json_server.server_instance = server
        return server
    return None

def stop_simple_json_server():
    """停止简单JSON服务器"""
    if hasattr(start_simple_json_server, 'server_instance'):
        start_simple_json_server.server_instance.stop_server()
        start_simple_json_server.server_instance = None
        return True
    return False

# 使用示例
if __name__ == "__main__":
    # 启动简单JSON服务器
    server = start_simple_json_server()
    if server:
        unreal.log("简单JSON服务器已启动")
    else:
        unreal.log_error("服务器启动失败")
python 复制代码
import socket
import json

def send_json_request(host="localhost", port=8070, code=None):
    """
    发送Python代码执行请求到服务器 - 使用纯JSON格式
    """
    try:
        # 创建socket连接
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((host, port))
        
        # 准备数据
        payload = {
            "code": code or "unreal.SystemLibrary.print_string(None, 'Hello from remote execution!', True, True, unreal.LinearColor(0,1,0,1), 5.0)"
        }
        
        # 发送JSON数据
        json_data = json.dumps(payload)
        sock.send(json_data.encode('utf-8'))
        
        # 接收响应
        response = sock.recv(4096).decode('utf-8')
        print(f"服务器响应: {response}")
        
        sock.close()
        return True
        
    except Exception as e:
        print(f"发送请求时出错: {str(e)}")
        return False

def send_fbx_import_request(host="localhost", port=8070):
    """
    发送FBX导入请求到服务器 - 使用固定路径
    """
    code = """
import unreal
import os

# 检查文件是否存在
fbx_path = "E:\\\\blender\\\\SK_W_MainChar_01.fbx"
destination_path = "/Game/Characters/MainChar/W/Meshes/"

if not os.path.exists(fbx_path):
    result = "文件路径无效: " + fbx_path
else:
    # 创建导入任务
    import_task = unreal.AssetImportTask()
    import_task.set_editor_property('filename', fbx_path)
    import_task.set_editor_property('destination_path', destination_path)
    import_task.set_editor_property('save', True)
    import_task.set_editor_property('automated', True)
    import_task.set_editor_property('replace_existing', True)
    
    # 执行导入任务
    asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
    asset_tools.import_asset_tasks([import_task])
    
    # 获取文件名
    filename = os.path.basename(fbx_path)
    result = "成功导入文件: " + filename + " 到 " + destination_path

result
"""
    return send_json_request(host, port, code)

# 使用示例
if __name__ == "__main__":

    # 发送FBX导入请求 - 使用固定路径
    print("\n发送FBX导入请求...")
    success = send_fbx_import_request()

    if success:
        print("FBX导入请求发送成功")
    else:
        print("FBX导入请求发送失败")
相关推荐
jun_bai15 小时前
VSCode使用
ide·vscode·编辑器
猫头虎17 小时前
OpenClaw-VSCode:在 VS Code 里玩转 OpenClaw,远程管理+SSH 双剑合璧
ide·vscode·开源·ssh·github·aigc·ai编程
手揽回忆怎么睡19 小时前
opencode和TRAE使用Superpowers 和ui-ux-pro-max skillls
ide·ui·ai·ux
CaracalTiger19 小时前
OpenClaw-VSCode:在 VS Code 中通过 WebSocket 远程管理 OpenClaw 网关的完整方案
运维·ide·人工智能·vscode·websocket·开源·编辑器
CS创新实验室20 小时前
Pandas 3 的新功能
android·ide·pandas
-嘟囔着拯救世界-21 小时前
【2026 最新版】OpenAI 祭出王炸 GPT-5.3-Codex!Win11 + VSCode 部署保姆级教程
vscode·gpt·chatgpt·node.js·node·codex·gpt5
先跑起来再说2 天前
Git 入门到实战:一篇搞懂安装、命令、远程仓库与 IDEA 集成
ide·git·后端·elasticsearch·golang·intellij-idea
嵌入小生0072 天前
标准IO---核心函数接口延续(嵌入式Linux)
c语言·vscode·vim·嵌入式·小白·标准io·函数接口
LYOBOYI1232 天前
vscode界面美化
ide·vscode·编辑器
mailangduoduo2 天前
零基础教学连接远程服务器部署项目——VScode版本
服务器·pytorch·vscode·深度学习·ssh·gpu算力