1
0
forked from Rowland/EG
EG/scene/util.py

300 lines
9.8 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
跨平台路径处理工具
"""
import os
import platform
from pathlib import Path
from panda3d.core import Filename
class CrossPlatformPathHandler:
"""跨平台路径处理器"""
def __init__(self):
self.system = platform.system()
self.is_windows = self.system == "Windows"
self.is_linux = self.system == "Linux"
self.is_mac = self.system == "Darwin"
print(f"路径处理器初始化 - 系统: {self.system}")
def normalize_model_path(self, filepath):
"""标准化模型文件路径"""
try:
print(f"\n=== 路径标准化处理 ===")
print(f"原始路径: {filepath}")
print(f"当前系统: {self.system}")
# 步骤1: 检查原始路径是否存在
if self._check_file_exists(filepath):
return self._panda3d_normalize(filepath)
# 步骤2: 路径修复尝试
fixed_path = self._attempt_path_fixes(filepath)
if fixed_path:
return self._panda3d_normalize(fixed_path)
# 步骤3: 智能搜索
found_path = self._smart_file_search(filepath)
if found_path:
return self._panda3d_normalize(found_path)
# 步骤4: 用户友好的错误处理
self._handle_path_not_found(filepath)
return filepath
except Exception as e:
print(f"❌ 路径标准化失败: {e}")
return filepath
def _check_file_exists(self, filepath):
"""检查文件是否存在"""
exists = os.path.exists(filepath)
if exists:
print(f"✓ 文件存在: {filepath}")
else:
print(f"⚠️ 文件不存在: {filepath}")
return exists
def _panda3d_normalize(self, filepath):
"""使用Panda3D标准化路径"""
try:
panda_filename = Filename.from_os_specific(filepath)
normalized_path = panda_filename.get_fullpath()
print(f"✓ Panda3D标准化: {normalized_path}")
return normalized_path
except Exception as e:
print(f"⚠️ Panda3D标准化失败: {e}")
return filepath
def _attempt_path_fixes(self, filepath):
"""尝试各种路径修复方法"""
print("🔧 尝试路径修复...")
# 修复方法1: 处理Windows/Linux路径分隔符
fixed_path = self._fix_path_separators(filepath)
if fixed_path and self._check_file_exists(fixed_path):
return fixed_path
# 修复方法2: 处理绝对路径到相对路径的转换
relative_path = self._convert_to_relative_path(filepath)
if relative_path and self._check_file_exists(relative_path):
return relative_path
# 修复方法3: 处理路径中的特殊字符
cleaned_path = self._clean_special_characters(filepath)
if cleaned_path and self._check_file_exists(cleaned_path):
return cleaned_path
return None
def _fix_path_separators(self, filepath):
"""修复路径分隔符"""
try:
if self.is_windows:
# Windows: 将正斜杠转换为反斜杠
fixed = filepath.replace('/', '\\')
else:
# Linux/Mac: 将反斜杠转换为正斜杠
fixed = filepath.replace('\\', '/')
if fixed != filepath:
print(f" 路径分隔符修复: {fixed}")
return fixed
return None
except Exception as e:
print(f" 路径分隔符修复失败: {e}")
return None
def _convert_to_relative_path(self, filepath):
"""转换绝对路径为相对路径"""
try:
# 如果是绝对路径,尝试转换为相对路径
if os.path.isabs(filepath):
filename = os.path.basename(filepath)
print(f" 尝试相对路径: {filename}")
return filename
return None
except Exception as e:
print(f" 相对路径转换失败: {e}")
return None
def _clean_special_characters(self, filepath):
"""清理路径中的特殊字符"""
try:
# 处理路径中的特殊字符(如中文路径中的+号)
import urllib.parse
# URL解码
decoded = urllib.parse.unquote(filepath)
if decoded != filepath:
print(f" URL解码: {decoded}")
return decoded
return None
except Exception as e:
print(f" 特殊字符清理失败: {e}")
return None
def _smart_file_search(self, filepath):
"""智能文件搜索"""
print("🔍 开始智能文件搜索...")
filename = os.path.basename(filepath)
print(f" 搜索文件名: {filename}")
# 搜索策略1: 在常见目录中搜索
found_path = self._search_in_common_directories(filename)
if found_path:
return found_path
# 搜索策略2: 递归搜索当前目录
found_path = self._recursive_search(filename)
if found_path:
return found_path
# 搜索策略3: 搜索用户常用目录
found_path = self._search_user_directories(filename)
if found_path:
return found_path
return None
def _search_in_common_directories(self, filename):
"""在常见目录中搜索"""
common_dirs = [
"models",
"assets",
"assets/models",
"resources",
"data",
"scene",
".",
"..",
"../models",
"../assets"
]
for directory in common_dirs:
if os.path.exists(directory):
potential_path = os.path.join(directory, filename)
if os.path.exists(potential_path):
print(f" ✓ 在常见目录中找到: {potential_path}")
return potential_path
return None
def _recursive_search(self, filename, max_depth=3):
"""递归搜索文件"""
try:
current_depth = 0
for root, dirs, files in os.walk("."):
# 限制搜索深度
depth = root.replace(".", "").count(os.sep)
if depth > max_depth:
continue
if filename in files:
found_path = os.path.join(root, filename)
print(f" ✓ 递归搜索找到: {found_path}")
return found_path
return None
except Exception as e:
print(f" 递归搜索失败: {e}")
return None
def _search_user_directories(self, filename):
"""搜索用户常用目录"""
try:
user_dirs = []
if self.is_windows:
# Windows常用目录
user_dirs.extend([
os.path.expanduser("~/Desktop"),
os.path.expanduser("~/Documents"),
"C:/模型",
"D:/模型",
"E:/模型"
])
else:
# Linux/Mac常用目录
user_dirs.extend([
os.path.expanduser("~/Desktop"),
os.path.expanduser("~/Documents"),
os.path.expanduser("~/models"),
"/tmp",
"/var/tmp"
])
for directory in user_dirs:
if os.path.exists(directory):
potential_path = os.path.join(directory, filename)
if os.path.exists(potential_path):
print(f" ✓ 在用户目录中找到: {potential_path}")
return potential_path
return None
except Exception as e:
print(f" 用户目录搜索失败: {e}")
return None
def _handle_path_not_found(self, filepath):
"""处理路径未找到的情况"""
print(f"\n❌ 无法找到文件: {filepath}")
print("💡 建议解决方案:")
print("1. 检查文件路径是否正确")
print("2. 确保文件确实存在")
print("3. 尝试使用相对路径而不是绝对路径")
print("4. 检查文件名中是否包含特殊字符")
print("5. 将模型文件复制到项目的 models/ 目录下")
# 显示当前工作目录
print(f"当前工作目录: {os.getcwd()}")
# 显示Panda3D模型搜索路径
try:
from panda3d.core import getModelPath
model_path = getModelPath()
print(f"Panda3D模型搜索路径: {model_path}")
except:
pass
def suggest_file_placement(self, filename):
"""建议文件放置位置"""
suggestions = []
# 创建推荐的目录结构
recommended_dirs = ["models", "assets/models", "resources"]
for directory in recommended_dirs:
if not os.path.exists(directory):
try:
os.makedirs(directory, exist_ok=True)
suggestions.append(f"已创建目录: {directory}")
except:
pass
suggested_path = os.path.join(directory, filename)
suggestions.append(f"建议放置位置: {suggested_path}")
return suggestions
# 全局路径处理器实例
path_handler = CrossPlatformPathHandler()
def normalize_model_path(filepath):
"""便捷函数:标准化模型路径"""
return path_handler.normalize_model_path(filepath)
def suggest_file_placement(filename):
"""便捷函数:建议文件放置位置"""
return path_handler.suggest_file_placement(filename)