310 lines
10 KiB
Python
310 lines
10 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)
|
|
return exists
|
|
|
|
def _panda3d_normalize(self, filepath):
|
|
"""使用Panda3D标准化路径"""
|
|
for ctor_name in ("fromOsSpecificW", "from_os_specific_w", "fromOsSpecific", "from_os_specific"):
|
|
ctor = getattr(Filename, ctor_name, None)
|
|
if not ctor:
|
|
continue
|
|
try:
|
|
panda_filename = ctor(filepath)
|
|
normalized_path = panda_filename.get_fullpath()
|
|
if normalized_path:
|
|
print(f"✓ Panda3D标准化: {normalized_path}")
|
|
return normalized_path
|
|
except Exception:
|
|
continue
|
|
try:
|
|
panda_filename = Filename(filepath)
|
|
normalized_path = panda_filename.get_fullpath()
|
|
if normalized_path:
|
|
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)
|