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导入请求发送失败")
相关推荐
Diligently_5 天前
idea 中vm option 配置
java·ide·intellij-idea
我命由我123455 天前
在 Android Studio 中,新建 AIDL 文件按钮是灰色
android·ide·android studio·安卓·android jetpack·android-studio·android runtime
Hello World . .5 天前
Linux:线程间通信
linux·开发语言·vscode
AC赳赳老秦5 天前
云原生AI故障排查新趋势:利用DeepSeek实现高效定位部署报错与性能瓶颈
ide·人工智能·python·云原生·prometheus·ai-native·deepseek
被制作时长两年半的个人练习生5 天前
claude code for vscode 配置 qwen3.5
ide·vscode·claude code·qwen3.5
圣心5 天前
Visual Studio Code 中的 AI 智能操作
ide·人工智能·vscode
吹牛不交税5 天前
关于vscode左侧资源管理器目录层级疑似异常的问题
ide·vscode·编辑器
xixi09245 天前
selenium IDE安装使用教程
ide·selenium·测试工具
嵌入小生0075 天前
线程间通信---嵌入式(Linux)
linux·c语言·vscode·嵌入式·互斥锁·线程间通信·信号量
西门吹-禅5 天前
【eclipse 升级】
java·ide·eclipse