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导入请求发送失败")
相关推荐
环黄金线HHJX.6 分钟前
【MCP: Tuan编程 + Qt架构 + QoS - 量子-经典混合计算管理控制平台】
ide·人工智能·qt·编辑器·量子计算
小江村儿的文杰1 小时前
UE4 PSO介绍一:PSO的定义(编辑中)
ue4·pso
tiandyoin1 小时前
visual studio 克隆 github 时,如何保持行尾符与 github 一致
ide·github·visual studio
FL16238631292 小时前
Visual Studio Installer无法启动安装程序。错误:系统找不到指定的文件。
ide·visual studio
不染尘.2 小时前
线程编程模型和进程间通信概述
linux·windows·vscode·ssh·信息与通信
love530love2 小时前
EPGF 新手教程 11在 PyCharm(中文版 GUI)中创建 uv 环境,并把 uv 做到“项目自包含”(工具本地化为必做环节)
ide·人工智能·python·pycharm·conda·uv·epgf
火星牛5 小时前
AI IDE试用(一)
javascript·ide
love530love16 小时前
EPGF 新手教程 12在 PyCharm(中文版 GUI)中创建 Poetry 项目环境,并把 Poetry 做成“项目自包含”(工具本地化为必做环节)
开发语言·ide·人工智能·windows·python·pycharm·epgf
White_Can17 小时前
《C++11:列表初始化》
c语言·开发语言·c++·vscode·stl
Aevget17 小时前
智能高效Go开发工具GoLand v2025.3全新上线——新增资源泄漏分析
开发语言·ide·后端·golang·go