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导入请求发送失败")
相关推荐
你知道“铁甲小宝”吗丶6 小时前
VSCode使用Claude Code
vscode·ai·ai编程
浪潮IT馆7 小时前
在 VSCode 中调试 JavaScript 的 Jest 测试用例
javascript·ide·vscode
椰汁菠萝7 小时前
VSCode中properties文件读写
ide·vscode·properties
weixin_550083158 小时前
QTdesigner配置在pycharm里使用anaconda环境配置安装成功
ide·python·pycharm
dvlinker9 小时前
C/C++编程开发工具及实用软件推荐
ide·vscode·visual studio·qt creator·c/c++·source insight·编程工具
Kazefuku10 小时前
VS Code 和Visual Studio:简单易懂的区别
ide·windows·visual studio
gsgbgxp10 小时前
通过tailscale配置ssh远程实现wsl系统VSCode编程
vscode·深度学习·ubuntu·ssh
Boxsc_midnight10 小时前
【一款支持Ollama本地部署的Visual Studio 2022 编程助手插件的编译和生成之路】解决打包安装问题
ide·visual studio·vs插件
-凌凌漆-10 小时前
vscode运行npm报错,npm : 无法加载文件 xxxxx/npm.ps1,因为在此系统上禁止运行脚本。
ide·vscode·npm
lingzhilab10 小时前
零知IDE——基于ESP32的ADS1115 多通道数据采集系统:从差分测量到Web实时监控
ide