联机版实现,先备份
This commit is contained in:
		
							
								
								
									
										125
									
								
								Tools/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								Tools/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| # UE头文件解析工具 | ||||
|  | ||||
| 这是一个用于扫描UE头文件并生成slua插件的emmy-lua注解的Python工具。 | ||||
|  | ||||
| ## 功能特性 | ||||
|  | ||||
| - 自动扫描指定目录下的所有UE头文件(.h) | ||||
| - 解析UCLASS、USTRUCT、UENUM、UFUNCTION、UPROPERTY等宏 | ||||
| - 生成符合emmy-lua标准的类型注解文件(.d.lua) | ||||
| - 支持C++类型到Lua类型的自动转换 | ||||
| - 支持递归扫描子目录 | ||||
|  | ||||
| ## 支持的UE宏 | ||||
|  | ||||
| - **UCLASS**: 解析类定义,包括继承关系 | ||||
| - **USTRUCT**: 解析结构体定义和属性 | ||||
| - **UENUM**: 解析枚举定义和值 | ||||
| - **UFUNCTION**: 解析函数声明,包括参数和返回值 | ||||
| - **UPROPERTY**: 解析属性声明 | ||||
| - **DECLARE_DYNAMIC_DELEGATE**: 解析委托声明 | ||||
|  | ||||
| ## 安装和使用 | ||||
|  | ||||
| ### 前置要求 | ||||
|  | ||||
| - Python 3.6+ | ||||
| - 无需额外依赖 | ||||
|  | ||||
| ### 基本用法 | ||||
|  | ||||
| ```bash | ||||
| # 扫描Source目录并生成注解文件到Content/Lua/@types目录 | ||||
| python ue_header_parser.py Source/BusyRabbit -o Content/Lua/@types | ||||
|  | ||||
| # 扫描当前目录并生成注解文件到同目录 | ||||
| python ue_header_parser.py . | ||||
|  | ||||
| # 递归扫描整个项目 | ||||
| python ue_header_parser.py Source --recursive -o Content/Lua/@types | ||||
| ``` | ||||
|  | ||||
| ### 命令行参数 | ||||
|  | ||||
| - `directory`: 要扫描的目录路径(必需) | ||||
| - `-o, --output`: 输出目录路径(可选,默认为源文件同目录) | ||||
| - `--recursive`: 递归扫描子目录(可选) | ||||
|  | ||||
| ## 生成的注解格式 | ||||
|  | ||||
| 工具会根据UE头文件生成对应的emmy-lua注解: | ||||
|  | ||||
| ### 类注解示例 | ||||
| ```lua | ||||
| ---@class UInventoryComponent : ULuaActorComponent | ||||
| ---@field Capacity integer | ||||
| ---@field InventoryList table<FInventoryGrid> | ||||
|  | ||||
| ---@param ItemID integer | ||||
| ---@param Count integer | ||||
| ---@return boolean | ||||
| function UInventoryComponent:IsCanContain(ItemID, Count) end | ||||
| ``` | ||||
|  | ||||
| ### 结构体注解示例 | ||||
| ```lua | ||||
| ---@class FInventoryGrid | ||||
| ---@field ItemID integer | ||||
| ---@field CurrentCount integer | ||||
| ---@field MaxCount integer | ||||
| ---@field Priority integer | ||||
| local FInventoryGrid = {} | ||||
| ``` | ||||
|  | ||||
| ### 枚举注解示例 | ||||
| ```lua | ||||
| ---@enum EBusyRoleState | ||||
| local EBusyRoleState = { | ||||
|     BonfireIdle = 0, | ||||
|     Searching = 1, | ||||
|     Picking = 2, | ||||
|     PickFinished = 3, | ||||
|     BackBonfire = 4 | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### 委托注解示例 | ||||
| ```lua | ||||
| ---@class FOnInventoryChanged | ||||
| ---@field Call fun(ItemID: integer) | ||||
| local FOnInventoryChanged = {} | ||||
| ``` | ||||
|  | ||||
| ## 类型映射 | ||||
|  | ||||
| 工具会自动将C++类型映射到Lua类型: | ||||
|  | ||||
| | C++类型 | Lua类型 | | ||||
| |---------|---------| | ||||
| | int32, int64 | integer | | ||||
| | float, double | number | | ||||
| | bool | boolean | | ||||
| | FString, FText, FName | string | | ||||
| | void | nil | | ||||
| | TArray, TMap, TSet | table | | ||||
| | 其他类型 | any | | ||||
|  | ||||
| ## 注意事项 | ||||
|  | ||||
| 1. 工具会跳过没有UE宏的普通头文件 | ||||
| 2. 生成的注解文件会保存在`.d.lua`文件中 | ||||
| 3. 如果输出目录不存在,工具会自动创建 | ||||
| 4. 工具会处理编码问题,但建议确保头文件使用UTF-8编码 | ||||
| 5. 对于复杂的模板类型,工具会尝试解析内部类型 | ||||
|  | ||||
| ## 故障排除 | ||||
|  | ||||
| 如果遇到解析错误,请检查: | ||||
| - 头文件语法是否正确 | ||||
| - UE宏格式是否符合标准 | ||||
| - 文件编码是否为UTF-8 | ||||
| - 是否有语法错误或缺失的分号 | ||||
|  | ||||
| ## 贡献 | ||||
|  | ||||
| 欢迎提交问题和改进建议! | ||||
							
								
								
									
										402
									
								
								Tools/ue_header_parser.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								Tools/ue_header_parser.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,402 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
| """ | ||||
| UE头文件解析工具 | ||||
| 用于扫描UE头文件并生成slua插件的emmy-lua注解 | ||||
| """ | ||||
|  | ||||
| import os | ||||
| import re | ||||
| import argparse | ||||
| from pathlib import Path | ||||
| from typing import List, Dict, Set, Optional | ||||
|  | ||||
| class UEHeaderParser: | ||||
|     def __init__(self): | ||||
|         self.classes = [] | ||||
|         self.structs = [] | ||||
|         self.enums = [] | ||||
|         self.delegates = [] | ||||
|          | ||||
|     def parse_header_file(self, file_path: str) -> Dict: | ||||
|         """解析单个头文件""" | ||||
|         with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: | ||||
|             content = f.read() | ||||
|          | ||||
|         result = { | ||||
|             'classes': [], | ||||
|             'structs': [], | ||||
|             'enums': [], | ||||
|             'delegates': [], | ||||
|             'file_path': file_path | ||||
|         } | ||||
|          | ||||
|         # 解析UCLASS | ||||
|         class_pattern = r'UCLASS\s*\([^)]*\)\s*\n\s*class\s+[A-Z_]+\s+(\w+)\s*:\s*public\s+(\w+)' | ||||
|         classes = re.findall(class_pattern, content) | ||||
|         for class_name, parent_class in classes: | ||||
|             result['classes'].append({ | ||||
|                 'name': class_name, | ||||
|                 'parent': parent_class, | ||||
|                 'functions': self._parse_functions(content, class_name), | ||||
|                 'properties': self._parse_properties(content, class_name) | ||||
|             }) | ||||
|          | ||||
|         # 解析USTRUCT | ||||
|         struct_pattern = r'USTRUCT\s*\([^)]*\)\s*\n\s*struct\s+[A-Z_]+\s+(\w+)' | ||||
|         structs = re.findall(struct_pattern, content) | ||||
|         for struct_name in structs: | ||||
|             result['structs'].append({ | ||||
|                 'name': struct_name, | ||||
|                 'properties': self._parse_struct_properties(content, struct_name) | ||||
|             }) | ||||
|          | ||||
|         # 解析USTRUCT (BlueprintType变体) | ||||
|         struct_pattern2 = r'USTRUCT\s*\([^)]*\)\s*\n\s*struct\s+F(\w+)' | ||||
|         structs2 = re.findall(struct_pattern2, content) | ||||
|         for struct_name in structs2: | ||||
|             result['structs'].append({ | ||||
|                 'name': f'F{struct_name}', | ||||
|                 'properties': self._parse_struct_properties(content, f'F{struct_name}') | ||||
|             }) | ||||
|          | ||||
|         # 解析UENUM | ||||
|         enum_pattern = r'UENUM\s*\([^)]*\)\s*\n\s*enum\s+class\s+(\w+)' | ||||
|         enums = re.findall(enum_pattern, content) | ||||
|         for enum_name in enums: | ||||
|             result['enums'].append({ | ||||
|                 'name': enum_name, | ||||
|                 'values': self._parse_enum_values(content, enum_name) | ||||
|             }) | ||||
|          | ||||
|         # 解析委托 | ||||
|         delegate_pattern = r'DECLARE_DYNAMIC_(MULTICAST_)?DELEGATE(?:_\w+)?\s*\(\s*(\w+)\s*' | ||||
|         delegates = re.findall(delegate_pattern, content) | ||||
|         for is_multicast, delegate_name in delegates: | ||||
|             result['delegates'].append({ | ||||
|                 'name': delegate_name, | ||||
|                 'is_multicast': bool(is_multicast), | ||||
|                 'params': self._parse_delegate_params(content, delegate_name) | ||||
|             }) | ||||
|          | ||||
|         return result | ||||
|      | ||||
|     def _parse_functions(self, content: str, class_name: str) -> List[Dict]: | ||||
|         """解析UFUNCTION""" | ||||
|         functions = [] | ||||
|          | ||||
|         # 匹配UFUNCTION声明 | ||||
|         func_pattern = r'UFUNCTION\s*\([^)]*\)\s*\n\s*(\w+)\s+(\w+)\s*\(([^)]*)\)' | ||||
|         matches = re.findall(func_pattern, content) | ||||
|          | ||||
|         for return_type, func_name, params in matches: | ||||
|             # 解析参数 | ||||
|             param_list = [] | ||||
|             if params.strip(): | ||||
|                 for param in params.split(','): | ||||
|                     param = param.strip() | ||||
|                     if param: | ||||
|                         # 简单的参数解析 | ||||
|                         parts = param.split() | ||||
|                         if len(parts) >= 2: | ||||
|                             param_type = parts[-2] if len(parts) > 2 else parts[0] | ||||
|                             param_name = parts[-1] | ||||
|                             param_list.append({ | ||||
|                                 'type': param_type, | ||||
|                                 'name': param_name | ||||
|                             }) | ||||
|              | ||||
|             functions.append({ | ||||
|                 'name': func_name, | ||||
|                 'return_type': return_type, | ||||
|                 'params': param_list | ||||
|             }) | ||||
|          | ||||
|         return functions | ||||
|      | ||||
|     def _parse_properties(self, content: str, class_name: str) -> List[Dict]: | ||||
|         """解析UPROPERTY""" | ||||
|         properties = [] | ||||
|          | ||||
|         # 匹配UPROPERTY声明 | ||||
|         prop_pattern = r'UPROPERTY\s*\([^)]*\)\s*\n\s*(\w+(?:<[^>]*>)?)\s+(\w+);' | ||||
|         matches = re.findall(prop_pattern, content) | ||||
|          | ||||
|         for prop_type, prop_name in matches: | ||||
|             properties.append({ | ||||
|                 'name': prop_name, | ||||
|                 'type': prop_type | ||||
|             }) | ||||
|          | ||||
|         return properties | ||||
|      | ||||
|     def _parse_struct_properties(self, content: str, struct_name: str) -> List[Dict]: | ||||
|         """解析结构体属性""" | ||||
|         properties = [] | ||||
|          | ||||
|         # 在结构体定义范围内查找属性 | ||||
|         struct_start = content.find(f'struct {struct_name}') | ||||
|         if struct_start == -1: | ||||
|             return properties | ||||
|          | ||||
|         # 找到结构体结束位置 | ||||
|         brace_count = 0 | ||||
|         struct_content = "" | ||||
|         for i in range(struct_start, len(content)): | ||||
|             char = content[i] | ||||
|             if char == '{': | ||||
|                 brace_count += 1 | ||||
|             elif char == '}': | ||||
|                 brace_count -= 1 | ||||
|                 if brace_count == 0: | ||||
|                     struct_content = content[struct_start:i+1] | ||||
|                     break | ||||
|          | ||||
|         if not struct_content: | ||||
|             return properties | ||||
|          | ||||
|         # 在结构体内容中查找UPROPERTY | ||||
|         prop_pattern = r'UPROPERTY\s*\([^)]*\)\s*\n\s*(\w+(?:<[^>]*>)?)\s+(\w+);' | ||||
|         matches = re.findall(prop_pattern, struct_content) | ||||
|          | ||||
|         for prop_type, prop_name in matches: | ||||
|             properties.append({ | ||||
|                 'name': prop_name, | ||||
|                 'type': prop_type | ||||
|             }) | ||||
|          | ||||
|         return properties | ||||
|      | ||||
|     def _parse_enum_values(self, content: str, enum_name: str) -> List[Dict]: | ||||
|         """解析枚举值""" | ||||
|         values = [] | ||||
|          | ||||
|         # 找到枚举定义 | ||||
|         enum_start = content.find(f'enum class {enum_name}') | ||||
|         if enum_start == -1: | ||||
|             return values | ||||
|          | ||||
|         # 找到枚举内容 | ||||
|         brace_start = content.find('{', enum_start) | ||||
|         if brace_start == -1: | ||||
|             return values | ||||
|          | ||||
|         brace_end = content.find('}', brace_start) | ||||
|         if brace_end == -1: | ||||
|             return values | ||||
|          | ||||
|         enum_content = content[brace_start+1:brace_end] | ||||
|          | ||||
|         # 解析枚举值 | ||||
|         value_pattern = r'(\w+)\s*(?:=\s*(\d+))?' | ||||
|         matches = re.findall(value_pattern, enum_content) | ||||
|          | ||||
|         current_value = 0 | ||||
|         for name, explicit_value in matches: | ||||
|             if explicit_value: | ||||
|                 current_value = int(explicit_value) | ||||
|              | ||||
|             values.append({ | ||||
|                 'name': name, | ||||
|                 'value': current_value | ||||
|             }) | ||||
|              | ||||
|             current_value += 1 | ||||
|          | ||||
|         return values | ||||
|      | ||||
|     def _parse_delegate_params(self, content: str, delegate_name: str) -> List[Dict]: | ||||
|         """解析委托参数""" | ||||
|         params = [] | ||||
|          | ||||
|         # 找到委托声明 | ||||
|         delegate_pattern = f'DECLARE_DYNAMIC_(MULTICAST_)?DELEGATE(?:_\\w+)?\\s*\\(\\s*{delegate_name}' | ||||
|         match = re.search(delegate_pattern, content) | ||||
|         if not match: | ||||
|             return params | ||||
|          | ||||
|         # 查找参数列表 | ||||
|         param_start = content.find('(', match.end()) | ||||
|         if param_start == -1: | ||||
|             return params | ||||
|          | ||||
|         param_end = content.find(')', param_start) | ||||
|         if param_end == -1: | ||||
|             return params | ||||
|          | ||||
|         param_content = content[param_start+1:param_end] | ||||
|          | ||||
|         # 解析参数 | ||||
|         param_parts = [p.strip() for p in param_content.split(',') if p.strip()] | ||||
|         for i, param in enumerate(param_parts): | ||||
|             parts = param.split() | ||||
|             if len(parts) >= 2: | ||||
|                 param_type = ' '.join(parts[:-1]) | ||||
|                 param_name = parts[-1] | ||||
|                 params.append({ | ||||
|                     'type': param_type, | ||||
|                     'name': param_name | ||||
|                 }) | ||||
|          | ||||
|         return params | ||||
|      | ||||
|     def generate_emmy_lua_annotations(self, parsed_data: Dict) -> str: | ||||
|         """生成emmy-lua注解""" | ||||
|         output = [] | ||||
|          | ||||
|         # 文件头注释 | ||||
|         output.append(f'-- 自动生成的emmy-lua注解文件') | ||||
|         output.append(f'-- 源文件: {parsed_data["file_path"]}') | ||||
|         output.append('') | ||||
|          | ||||
|         # 生成枚举注解 | ||||
|         for enum in parsed_data['enums']: | ||||
|             output.append(f'---@enum {enum["name"]}') | ||||
|             output.append(f'local {enum["name"]} = {{') | ||||
|             for value in enum['values']: | ||||
|                 output.append(f'    {value["name"]} = {value["value"]},') | ||||
|             output.append('}') | ||||
|             output.append('') | ||||
|          | ||||
|         # 生成结构体注解 | ||||
|         for struct in parsed_data['structs']: | ||||
|             output.append(f'---@class {struct["name"]}') | ||||
|             for prop in struct['properties']: | ||||
|                 lua_type = self._cpp_to_lua_type(prop['type']) | ||||
|                 output.append(f'---@field {prop["name"]} {lua_type}') | ||||
|             output.append(f'local {struct["name"]} = {{}}') | ||||
|             output.append('') | ||||
|          | ||||
|         # 生成类注解 | ||||
|         for cls in parsed_data['classes']: | ||||
|             output.append(f'---@class {cls["name"]} : {cls["parent"]}') | ||||
|              | ||||
|             # 添加属性 | ||||
|             for prop in cls['properties']: | ||||
|                 lua_type = self._cpp_to_lua_type(prop['type']) | ||||
|                 output.append(f'---@field {prop["name"]} {lua_type}') | ||||
|              | ||||
|             # 添加方法 | ||||
|             for func in cls['functions']: | ||||
|                 lua_return_type = self._cpp_to_lua_type(func['return_type']) | ||||
|                 param_annotations = [] | ||||
|                 for param in func['params']: | ||||
|                     lua_param_type = self._cpp_to_lua_type(param['type']) | ||||
|                     param_annotations.append(f'---@param {param["name"]} {lua_param_type}') | ||||
|                  | ||||
|                 if param_annotations: | ||||
|                     output.extend(param_annotations) | ||||
|                 output.append(f'---@return {lua_return_type}') | ||||
|                 output.append(f'function {cls["name"]}:{func["name"]}({", ".join(p["name"] for p in func["params"])}) end') | ||||
|                 output.append('') | ||||
|              | ||||
|             output.append('') | ||||
|          | ||||
|         # 生成委托注解 | ||||
|         for delegate in parsed_data['delegates']: | ||||
|             output.append(f'---@class {delegate["name"]}') | ||||
|             param_types = [] | ||||
|             for param in delegate['params']: | ||||
|                 lua_type = self._cpp_to_lua_type(param['type']) | ||||
|                 param_types.append(f'{param["name"]}: {lua_type}') | ||||
|              | ||||
|             if param_types: | ||||
|                 output.append(f'---@field Call fun({", ".join(param_types)})') | ||||
|             else: | ||||
|                 output.append('---@field Call fun()') | ||||
|             output.append(f'local {delegate["name"]} = {{}}') | ||||
|             output.append('') | ||||
|          | ||||
|         return '\n'.join(output) | ||||
|      | ||||
|     def _cpp_to_lua_type(self, cpp_type: str) -> str: | ||||
|         """将C++类型转换为Lua类型""" | ||||
|         type_mapping = { | ||||
|             'int32': 'integer', | ||||
|             'int64': 'integer', | ||||
|             'float': 'number', | ||||
|             'double': 'number', | ||||
|             'bool': 'boolean', | ||||
|             'FString': 'string', | ||||
|             'FText': 'string', | ||||
|             'FName': 'string', | ||||
|             'void': 'nil', | ||||
|             'TArray': 'table', | ||||
|             'TMap': 'table', | ||||
|             'TSet': 'table' | ||||
|         } | ||||
|          | ||||
|         # 处理模板类型 | ||||
|         if '<' in cpp_type and '>' in cpp_type: | ||||
|             base_type = cpp_type.split('<')[0] | ||||
|             inner_type = cpp_type.split('<')[1].split('>')[0] | ||||
|             lua_inner_type = self._cpp_to_lua_type(inner_type) | ||||
|             return f'{type_mapping.get(base_type, "any")}<{lua_inner_type}>' | ||||
|          | ||||
|         return type_mapping.get(cpp_type, 'any') | ||||
|      | ||||
|     def scan_directory(self, directory: str, output_dir: str = None): | ||||
|         """扫描目录或单个文件并生成注解文件""" | ||||
|         header_files = [] | ||||
|          | ||||
|         if os.path.isfile(directory) and directory.endswith('.h'): | ||||
|             # 单个文件 | ||||
|             header_files = [directory] | ||||
|         elif os.path.isdir(directory): | ||||
|             # 目录 | ||||
|             for root, dirs, files in os.walk(directory): | ||||
|                 for file in files: | ||||
|                     if file.endswith('.h'): | ||||
|                         header_files.append(os.path.join(root, file)) | ||||
|         else: | ||||
|             print(f'错误: {directory} 不是有效的文件或目录') | ||||
|             return | ||||
|          | ||||
|         print(f'找到 {len(header_files)} 个头文件') | ||||
|          | ||||
|         for header_file in header_files: | ||||
|             try: | ||||
|                 print(f'正在解析: {header_file}') | ||||
|                 parsed_data = self.parse_header_file(header_file) | ||||
|                  | ||||
|                 if any([parsed_data['classes'], parsed_data['structs'], parsed_data['enums'], parsed_data['delegates']]): | ||||
|                     annotations = self.generate_emmy_lua_annotations(parsed_data) | ||||
|                      | ||||
|                     # 确定输出文件路径 | ||||
|                     if output_dir: | ||||
|                         if os.path.isfile(directory): | ||||
|                             # 单个文件的情况 | ||||
|                             output_file = os.path.join(output_dir, os.path.basename(header_file).replace('.h', '.d.lua')) | ||||
|                         else: | ||||
|                             # 目录的情况 | ||||
|                             relative_path = os.path.relpath(header_file, directory) | ||||
|                             output_file = os.path.join(output_dir, relative_path.replace('.h', '.d.lua')) | ||||
|                         os.makedirs(os.path.dirname(output_file), exist_ok=True) | ||||
|                     else: | ||||
|                         output_file = header_file.replace('.h', '.d.lua') | ||||
|                      | ||||
|                     with open(output_file, 'w', encoding='utf-8') as f: | ||||
|                         f.write(annotations) | ||||
|                      | ||||
|                     print(f'已生成: {output_file}') | ||||
|                  | ||||
|             except Exception as e: | ||||
|                 print(f'解析文件 {header_file} 时出错: {e}') | ||||
|  | ||||
| def main(): | ||||
|     parser = argparse.ArgumentParser(description='UE头文件解析工具 - 生成slua插件的emmy-lua注解') | ||||
|     parser.add_argument('directory', help='要扫描的目录路径') | ||||
|     parser.add_argument('-o', '--output', help='输出目录路径(默认为源文件同目录)') | ||||
|     parser.add_argument('--recursive', action='store_true', help='递归扫描子目录') | ||||
|      | ||||
|     args = parser.parse_args() | ||||
|      | ||||
|     if not os.path.exists(args.directory): | ||||
|         print(f'错误: 目录 {args.directory} 不存在') | ||||
|         return | ||||
|      | ||||
|     parser = UEHeaderParser() | ||||
|     parser.scan_directory(args.directory, args.output) | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
							
								
								
									
										104
									
								
								Tools/使用示例.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								Tools/使用示例.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| # UE头文件解析工具使用示例 | ||||
|  | ||||
| ## 基本用法 | ||||
|  | ||||
| ### 扫描整个项目 | ||||
| ```bash | ||||
| python Tools/ue_header_parser.py Source/BusyRabbit/Public -o Content/Lua/@types | ||||
| ``` | ||||
|  | ||||
| ### 扫描特定目录 | ||||
| ```bash | ||||
| # 扫描Components目录 | ||||
| python Tools/ue_header_parser.py Source/BusyRabbit/Public/Components -o Content/Lua/@types | ||||
|  | ||||
| # 扫描Level目录 | ||||
| python Tools/ue_header_parser.py Source/BusyRabbit/Public/Level -o Content/Lua/@types | ||||
| ``` | ||||
|  | ||||
| ### 扫描单个文件 | ||||
| ```bash | ||||
| # 直接指定文件路径(需要先确保输出目录存在) | ||||
| python Tools/ue_header_parser.py Source/BusyRabbit/Public/Components/InventoryComponent.h -o Content/Lua/@types | ||||
| ``` | ||||
|  | ||||
| ## 生成结果示例 | ||||
|  | ||||
| ### 输入头文件 (InventoryComponent.h) | ||||
| ```cpp | ||||
| USTRUCT(BlueprintType) | ||||
| struct FInventoryGrid { | ||||
|     GENERATED_BODY() | ||||
| public: | ||||
|     UPROPERTY(BlueprintReadOnly, DisplayName = "物品ID") | ||||
|     int32 ItemID; | ||||
|  | ||||
|     UPROPERTY(BlueprintReadWrite, DisplayName = "当前的数量") | ||||
|     int32 CurrentCount; | ||||
|  | ||||
|     UPROPERTY(BlueprintReadWrite, DisplayName = "最大堆叠限制") | ||||
|     int32 MaxCount; | ||||
|  | ||||
|     UPROPERTY(BlueprintReadWrite, DisplayName = "优先级") | ||||
|     int32 Priority; | ||||
| }; | ||||
|  | ||||
| UCLASS() | ||||
| class BUSYRABBIT_API UInventoryComponent : public ULuaActorComponent { | ||||
|     GENERATED_BODY() | ||||
| public: | ||||
|     UFUNCTION(BlueprintCallable) | ||||
|     bool IsCanContain(int32 ItemID, int32 Count); | ||||
|      | ||||
|     // ... 其他函数和属性 | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| ### 输出注解文件 (InventoryComponent.d.lua) | ||||
| ```lua | ||||
| -- 自动生成的emmy-lua注解文件 | ||||
| -- 源文件: Source/BusyRabbit/Public/Components\InventoryComponent.h | ||||
|  | ||||
| ---@class FInventoryGrid | ||||
| ---@field ItemID integer | ||||
| ---@field CurrentCount integer | ||||
| ---@field MaxCount integer | ||||
| ---@field Priority integer | ||||
| local FInventoryGrid = {} | ||||
|  | ||||
| ---@class UInventoryComponent : ULuaActorComponent | ||||
| ---@field Capacity integer | ||||
| ---@field InventoryList table<any> | ||||
| ---@param ItemID integer | ||||
| ---@param Count integer | ||||
| ---@return boolean | ||||
| function UInventoryComponent:IsCanContain(ItemID, Count) end | ||||
|  | ||||
| -- ... 其他函数注解 | ||||
| ``` | ||||
|  | ||||
| ## 集成到开发流程 | ||||
|  | ||||
| ### 1. 定期生成注解 | ||||
| 建议在每次UE头文件更新后运行工具重新生成注解。 | ||||
|  | ||||
| ### 2. 版本控制 | ||||
| 将生成的`.d.lua`文件添加到版本控制中,方便团队共享。 | ||||
|  | ||||
| ### 3. IDE配置 | ||||
| 确保IDE(如VSCode)能够识别`Content/Lua/@types`目录中的注解文件。 | ||||
|  | ||||
| ## 注意事项 | ||||
|  | ||||
| 1. **类型映射**: 工具会自动将C++类型映射到Lua类型 | ||||
| 2. **模板类型**: 支持`TArray<FInventoryGrid>`等模板类型的解析 | ||||
| 3. **委托支持**: 自动生成委托类型的Call函数注解 | ||||
| 4. **错误处理**: 工具会跳过无法解析的文件并继续处理其他文件 | ||||
|  | ||||
| ## 故障排除 | ||||
|  | ||||
| 如果遇到问题,请检查: | ||||
| - 头文件语法是否正确 | ||||
| - UE宏格式是否符合标准 | ||||
| - 输出目录权限是否足够 | ||||
| - Python版本是否为3.6+ | ||||
		Reference in New Issue
	
	Block a user