# Blender中运行SUWood客户端 - 接收和处理SUWood命令 import bpy import sys import threading import time from pathlib import Path print("🚀 Blender SUWood 客户端启动") print("=" * 50) # 添加SUWood模块路径 sys.path.insert(0, r"D:\XL\code\blender\blenderpython") # 全局变量 client_thread = None running = False suw_impl = None try: # 导入SUWood模块 from suw_impl import SUWImpl from suw_client import SUWClient, get_client print("✅ SUWood模块导入成功") # 初始化SUWImpl suw_impl = SUWImpl.get_instance() suw_impl.startup() print("✅ SUWImpl初始化完成") def process_suwood_command(cmd_type, data): """处理SUWood命令""" import datetime # 显示命令接收信息 timestamp = datetime.datetime.now().strftime("%H:%M:%S") print("=" * 60) print(f"📥 [{timestamp}] 接收到SUWood命令") print(f"🏷️ 原始命令类型: {cmd_type}") print(f"📦 原始命令数据: {data}") print("-" * 60) # 处理嵌套命令格式 actual_cmd_type = cmd_type actual_data = data # 如果是set_cmd格式,提取内部真实命令 if cmd_type == 'set_cmd' and isinstance(data, dict) and 'cmd' in data: actual_cmd_type = data.get('cmd') # 将除了cmd之外的所有数据作为参数传递 actual_data = {k: v for k, v in data.items() if k != 'cmd'} print(f"🔄 检测到嵌套命令格式,提取真实命令:") print(f" 实际命令类型: {actual_cmd_type}") print(f" 实际命令数据: {actual_data}") print("-" * 60) try: # 确保在主线程中执行Blender操作 def execute_in_main_thread(): start_time = time.time() try: if hasattr(suw_impl, actual_cmd_type): print(f"🔍 查找到命令方法: {actual_cmd_type}") method = getattr(suw_impl, actual_cmd_type) print(f"⚡ 开始执行命令...") result = method(actual_data) elapsed_time = time.time() - start_time print(f"✅ 命令 '{actual_cmd_type}' 执行成功!") print(f"⏱️ 执行耗时: {elapsed_time:.3f}秒") if result is not None: print(f"📋 执行结果: {result}") else: print(f"📋 执行结果: 无返回值") return result else: print(f"❌ 未找到命令方法: {actual_cmd_type}") print(f"🔍 可用方法列表:") available_methods = [attr for attr in dir(suw_impl) if not attr.startswith( '_') and callable(getattr(suw_impl, attr))] # 按字母顺序排序,方便查找 available_methods.sort() # 显示前15个避免输出过长 for i, method in enumerate(available_methods[:15]): print(f" - {method}") if len(available_methods) > 15: print( f" ... 还有 {len(available_methods) - 15} 个方法") # 查找相似命令 similar_commands = [m for m in available_methods if actual_cmd_type.lower( ) in m.lower() or m.lower() in actual_cmd_type.lower()] if similar_commands: print(f"🔍 相似命令建议:") for cmd in similar_commands[:5]: print(f" - {cmd}") return None except Exception as e: elapsed_time = time.time() - start_time print(f"❌ 命令 '{actual_cmd_type}' 执行失败!") print(f"⏱️ 执行耗时: {elapsed_time:.3f}秒") print(f"🚨 错误信息: {str(e)}") print(f"📍 错误详情:") import traceback traceback.print_exc() return None # 在主线程中执行 result = execute_in_main_thread() print("=" * 60) print() # 空行分隔 return result except Exception as e: print(f"❌ 命令处理框架异常: {e}") print("=" * 60) print() return None def client_worker(): """客户端工作线程""" global running print("🔄 启动SUWood客户端工作线程...") # 统计信息 total_commands = 0 successful_commands = 0 failed_commands = 0 start_time = time.time() try: # 连接SUWood服务器 client = get_client() if not client or not client.sock: print("❌ 无法连接到SUWood服务器") return print("✅ 已连接到SUWood服务器 (127.0.0.1:7999)") print("🎯 开始监听SUWood命令...") print("💡 提示: 在System Console (Window > Toggle System Console) 中查看详细输出") print() while running: try: # 获取命令 from suw_client import get_cmds commands = get_cmds() if commands and len(commands) > 0: print( f"🚀 [{time.strftime('%H:%M:%S')}] 接收到 {len(commands)} 个新命令") for i, cmd in enumerate(commands, 1): if not running: break # 支持多种命令格式 cmd_type = None cmd_data = {} # 格式1: {'type': '...', 'data': {...}} if 'type' in cmd: cmd_type = cmd.get('type') cmd_data = cmd.get('data', {}) print( f"\n📝 处理第 {i}/{len(commands)} 个命令 (格式1: type/data)...") # 格式2: {'cmd': '...', 'data': {...}} elif 'cmd' in cmd and 'data' in cmd: cmd_type = cmd.get('cmd') cmd_data = cmd.get('data', {}) print( f"\n📝 处理第 {i}/{len(commands)} 个命令 (格式2: cmd/data)...") # 格式3: 直接的命令数据 {'cmd': '...', ...} elif isinstance(cmd, dict) and len(cmd) > 0: # 查找可能的命令字段 for key in ['cmd', 'command', 'action', 'method']: if key in cmd: cmd_type = cmd.get(key) cmd_data = { k: v for k, v in cmd.items() if k != key} print( f"\n📝 处理第 {i}/{len(commands)} 个命令 (格式3: 直接命令)...") break if cmd_type: print(f"🔧 识别的命令格式: {cmd}") total_commands += 1 # 处理命令 result = process_suwood_command( cmd_type, cmd_data) # 判断执行是否成功 # c02是纹理命令,c09是删除命令等,这些命令通常正常返回None success_commands = ['c02', 'c03', 'c04', 'c05', 'c06', 'c07', 'c08', 'c09', 'c0a', 'c0c', 'c0d', 'c0e', 'c0f', 'c10', 'c11', 'c12', 'c13', 'c14', 'c15', 'c16', 'c17', 'c18', 'c1a', 'c1b', 'c23', 'c24', 'c25', 'c28', 'c30', 'set_cmd', 'startup', 'init', 'set_config', 'show_message', 'add_surf'] if result is not None or cmd_type in success_commands: successful_commands += 1 print(f"✅ 命令 {i} 处理成功") else: failed_commands += 1 print(f"❌ 命令 {i} 处理失败") else: failed_commands += 1 print(f"⚠️ 无法识别的命令格式: {cmd}") print(f" 💡 支持的格式:") print( f" - {{'type': 'command_name', 'data': {{...}}}}") print( f" - {{'cmd': 'command_name', 'data': {{...}}}}") print( f" - {{'cmd': 'command_name', ...其他参数...}}") # 显示统计信息 elapsed = time.time() - start_time print(f"\n📊 会话统计 (运行时长: {elapsed:.1f}秒):") print(f" 总命令数: {total_commands}") print(f" 成功执行: {successful_commands}") print(f" 执行失败: {failed_commands}") if total_commands > 0: success_rate = ( successful_commands / total_commands) * 100 print(f" 成功率: {success_rate:.1f}%") print() # 短暂休眠避免过度占用CPU time.sleep(0.1) except KeyboardInterrupt: print("\n🛑 接收到停止信号") break except Exception as e: print(f"⚠️ 客户端循环异常: {e}") print("🔄 1秒后重试...") time.sleep(1) # 出错时休眠长一点 except Exception as e: print(f"❌ 客户端工作线程异常: {e}") import traceback traceback.print_exc() finally: elapsed = time.time() - start_time print("\n" + "=" * 50) print("🛑 SUWood客户端工作线程已停止") print(f"📊 最终统计 (总运行时长: {elapsed:.1f}秒):") print(f" 总命令数: {total_commands}") print(f" 成功执行: {successful_commands}") print(f" 执行失败: {failed_commands}") if total_commands > 0: success_rate = (successful_commands / total_commands) * 100 print(f" 成功率: {success_rate:.1f}%") print("=" * 50) def start_client(): """启动客户端""" global client_thread, running if running: print("⚠️ 客户端已在运行中") return running = True client_thread = threading.Thread(target=client_worker, daemon=True) client_thread.start() print("✅ SUWood客户端已启动") def stop_client(): """停止客户端""" global running running = False print("🛑 正在停止SUWood客户端...") # 创建UI操作面板 class SUWoodClientPanel(bpy.types.Panel): """SUWood客户端控制面板""" bl_label = "SUWood客户端" bl_idname = "VIEW3D_PT_suwood_client" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = "SUWood" def draw(self, context): layout = self.layout layout.label(text="SUWood服务器连接:") row = layout.row() row.operator("suwood.start_client", text="启动客户端") row.operator("suwood.stop_client", text="停止客户端") layout.separator() layout.label(text="手动测试:") layout.operator("suwood.test_connection", text="测试连接") layout.operator("suwood.get_commands", text="获取命令") class SUWoodStartClient(bpy.types.Operator): """启动SUWood客户端操作""" bl_idname = "suwood.start_client" bl_label = "启动SUWood客户端" def execute(self, context): start_client() self.report({'INFO'}, "SUWood客户端已启动") return {'FINISHED'} class SUWoodStopClient(bpy.types.Operator): """停止SUWood客户端操作""" bl_idname = "suwood.stop_client" bl_label = "停止SUWood客户端" def execute(self, context): stop_client() self.report({'INFO'}, "SUWood客户端已停止") return {'FINISHED'} class SUWoodTestConnection(bpy.types.Operator): """测试SUWood连接操作""" bl_idname = "suwood.test_connection" bl_label = "测试SUWood连接" def execute(self, context): try: client = get_client() if client and client.sock: self.report({'INFO'}, "SUWood服务器连接正常") else: self.report({'ERROR'}, "无法连接到SUWood服务器") except Exception as e: self.report({'ERROR'}, f"连接测试失败: {e}") return {'FINISHED'} class SUWoodGetCommands(bpy.types.Operator): """手动获取SUWood命令操作""" bl_idname = "suwood.get_commands" bl_label = "获取SUWood命令" def execute(self, context): try: from suw_client import get_cmds commands = get_cmds() if commands and len(commands) > 0: self.report({'INFO'}, f"获取到 {len(commands)} 个命令") # 处理命令 for cmd in commands: cmd_type = cmd.get('type') cmd_data = cmd.get('data', {}) if cmd_type: process_suwood_command(cmd_type, cmd_data) else: self.report({'INFO'}, "当前没有待处理的命令") except Exception as e: self.report({'ERROR'}, f"获取命令失败: {e}") return {'FINISHED'} # 注册类 classes = [ SUWoodClientPanel, SUWoodStartClient, SUWoodStopClient, SUWoodTestConnection, SUWoodGetCommands ] for cls in classes: try: bpy.utils.register_class(cls) except: pass # 可能已经注册过了 print("\n🎉 SUWood客户端已初始化完成!") print("=" * 50) print("📋 使用方法:") print("1. 在3D视图右侧面板找到'SUWood'标签") print("2. 点击'启动客户端'开始接收命令") print("3. 或者手动点击'获取命令'测试") print("4. 在System Console中查看详细输出") print("\n🔧 或者直接运行:") print("start_client() # 启动自动客户端") print("stop_client() # 停止客户端") # 提供直接调用函数 globals()['start_client'] = start_client globals()['stop_client'] = stop_client globals()['process_suwood_command'] = process_suwood_command except Exception as e: print(f"❌ SUWood客户端初始化失败: {e}") import traceback traceback.print_exc() print("\n🔧 请检查:") print("1. SUWood服务器是否在端口7999运行") print("2. 模块路径是否正确") print("3. 网络连接是否正常") print("\n" + "=" * 50)