Merge pull request 'chore: �������������������ʲ������ű�' (#36) from chore/misc-updates into main
This commit was merged in pull request #36.
This commit is contained in:
@@ -2,3 +2,4 @@
|
||||
|
||||
- [Gitea Token Permission](gitea-token-permission.md) — reviewer token 仅可评论,标签操作需用 PM token
|
||||
- [P-006 Review](p006-review-note.md) — Issue #17 白模搭建审查通过记录
|
||||
- [P-009 Review](p009-review-note.md) — Issue #20 收集系统程序设计审查通过记录
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: p009-review-note
|
||||
description: Issue #20 P-009 收集系统程序设计审查通过记录
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
|
||||
## P-009 收集系统程序设计审查 (2026-06-10)
|
||||
|
||||
- Issue: #20
|
||||
- 审查类型: 程序设计(质量门 2)
|
||||
- 产出文件: `docs/technical/收集系统-技术方案.md`
|
||||
- 结果: **通过**
|
||||
|
||||
### 审查要点
|
||||
- 技术方案文档路径实际为中文文件名 `收集系统-技术方案.md`(非 Issue 中标注的 `collection-system-tech.md`)
|
||||
- 执行案文件名也是中文:`收集系统-执行案.md`(非 `collection-system-execution.md`)
|
||||
- 6 个检查维度全部通过:执行案覆盖度、美术资源需求、架构清晰度、数据流、技术风险、工作量与拆分建议
|
||||
- 标签操作:移除了 gate:art-fail(30) 和 status:in-review(14),添加了 review:pass(33)
|
||||
@@ -1,20 +1,19 @@
|
||||
"""UE5 编辑器 Python 脚本:创建 v0.1 角色控制所需的 InputAction 资产并更新 IMC。
|
||||
|
||||
由 setup_input.bat 通过 UE5 的 -ExecutePythonScript 参数调用。
|
||||
在 UE5 编辑器 Python 环境中运行。
|
||||
使用方式:
|
||||
方式1 — 在编辑器 Python 控制台运行:
|
||||
py "E:/MiceCola/work/ChildHood/tools/input-setup/setup_input_assets.py"
|
||||
方式2 — 通过 setup_input.bat 启动编辑器执行
|
||||
|
||||
功能:
|
||||
1. 创建 3 个 InputAction 资产:IA_Interact, IA_Cancel, IA_SwitchInteract
|
||||
2. 更新 IMC_Default:添加 E / ESC / Tab 按键映射
|
||||
2. 尝试更新 IMC_Default:添加 E / ESC / Tab 按键映射
|
||||
3. 保存所有修改的资产
|
||||
|
||||
环境变量(由 setup_input.bat 设置):
|
||||
INPUT_PROJECT_ROOT — 项目根目录绝对路径
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import traceback
|
||||
|
||||
# ---- 检查 unreal 模块 ----
|
||||
try:
|
||||
@@ -23,36 +22,54 @@ except ImportError:
|
||||
print("[InputSetup] FATAL: unreal 模块不可用,必须在 UE5 编辑器环境中运行")
|
||||
sys.exit(1)
|
||||
|
||||
# ---- 项目根目录 ----
|
||||
_project_root_str = os.environ.get("INPUT_PROJECT_ROOT", "")
|
||||
if _project_root_str:
|
||||
PROJECT_ROOT = Path(_project_root_str)
|
||||
else:
|
||||
print("[InputSetup] FATAL: INPUT_PROJECT_ROOT 环境变量未设置")
|
||||
sys.exit(1)
|
||||
|
||||
# ---- 资产路径配置 ----
|
||||
IA_PACKAGE = "/Game/Input/Actions"
|
||||
IMC_PATH = "/Game/Input/IMC_Default"
|
||||
TEMPLATE_IA = f"{IA_PACKAGE}/IA_Look" # 用已存在的 IA 作为复制模板
|
||||
|
||||
# 新增 InputAction 定义
|
||||
NEW_INPUT_ACTIONS = {
|
||||
"IA_Interact": {
|
||||
"description": "E 键交互输入动作",
|
||||
"key": unreal.Key.E,
|
||||
"triggers": [unreal.InputTriggerDown()],
|
||||
},
|
||||
"IA_Cancel": {
|
||||
"description": "ESC 取消输入动作",
|
||||
"key": unreal.Key.ESCAPE,
|
||||
"triggers": [unreal.InputTriggerDown()],
|
||||
},
|
||||
"IA_SwitchInteract": {
|
||||
"description": "Tab 切换交互目标输入动作",
|
||||
"key": unreal.Key.TAB,
|
||||
"triggers": [unreal.InputTriggerDown()],
|
||||
},
|
||||
}
|
||||
# 新增 InputAction 定义(key_name 为字符串,运行时解析)
|
||||
NEW_INPUT_ACTIONS = [
|
||||
{"name": "IA_Interact", "desc": "E 键交互输入动作", "key_name": "E"},
|
||||
{"name": "IA_Cancel", "desc": "ESC 取消输入动作", "key_name": "Escape"},
|
||||
{"name": "IA_SwitchInteract", "desc": "Tab 切换交互目标", "key_name": "Tab"},
|
||||
]
|
||||
|
||||
# 按键名 → UE5 Key 对象的多种尝试路径
|
||||
KEY_RESOLVE_ORDER = ["E", "Escape", "Tab"]
|
||||
|
||||
|
||||
def resolve_key(key_name: str):
|
||||
"""尝试多种方式从 UE5 Python API 获取 Key 对象。
|
||||
|
||||
UE5 各版本的 Python 绑定对 Key 的暴露方式不同,
|
||||
这里依次尝试多种路径,找到可用的那一个。
|
||||
"""
|
||||
attempts = [
|
||||
# 方式1: unreal.Key 枚举属性 (如 unreal.Key.E, unreal.Key.Escape)
|
||||
lambda: getattr(unreal.Key, key_name),
|
||||
# 方式2: unreal.Keys 类 (部分版本用这个)
|
||||
lambda: getattr(unreal.Keys, key_name),
|
||||
# 方式3: 全大写 (如 ESCAPE, TAB)
|
||||
lambda: getattr(unreal.Key, key_name.upper()),
|
||||
lambda: getattr(unreal.Keys, key_name.upper()),
|
||||
# 方式4: KEY_ 前缀 (如 KEY_E, KEY_ESCAPE)
|
||||
lambda: getattr(unreal.Key, f"KEY_{key_name.upper()}"),
|
||||
lambda: getattr(unreal.Keys, f"KEY_{key_name.upper()}"),
|
||||
# 方式5: 构造函数 (部分版本支持从字符串构造)
|
||||
lambda: unreal.Key(key_name),
|
||||
]
|
||||
|
||||
for i, attempt in enumerate(attempts, 1):
|
||||
try:
|
||||
key = attempt()
|
||||
if key is not None:
|
||||
print(f"[InputSetup] Key('{key_name}') 解析成功 (方式{i})")
|
||||
return key
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
print(f"[InputSetup] Key('{key_name}') 所有解析方式均失败")
|
||||
return None
|
||||
|
||||
|
||||
def asset_exists(asset_path: str) -> bool:
|
||||
@@ -60,161 +77,249 @@ def asset_exists(asset_path: str) -> bool:
|
||||
return unreal.EditorAssetLibrary.does_asset_exist(asset_path)
|
||||
|
||||
|
||||
def create_input_action(name: str, description: str) -> unreal.InputAction:
|
||||
"""创建 InputAction 资产"""
|
||||
def create_input_action_by_duplicate(name: str, desc: str) -> object:
|
||||
"""通过复制已有 IA 模板创建新 InputAction 资产。
|
||||
|
||||
这是最可靠的方式——不依赖 Factory 类的 Python 绑定。
|
||||
"""
|
||||
asset_path = f"{IA_PACKAGE}/{name}"
|
||||
|
||||
if asset_exists(asset_path):
|
||||
print(f"[InputSetup] 资产已存在,跳过创建: {asset_path}")
|
||||
print(f"[InputSetup] 已存在,跳过: {asset_path}")
|
||||
return unreal.load_asset(asset_path)
|
||||
|
||||
# 确保目录存在
|
||||
unreal.EditorAssetLibrary.make_directory(IA_PACKAGE)
|
||||
# 确保目标目录存在
|
||||
if not unreal.EditorAssetLibrary.does_directory_exist(IA_PACKAGE):
|
||||
unreal.EditorAssetLibrary.make_directory(IA_PACKAGE)
|
||||
|
||||
# 使用 AssetTools 创建
|
||||
asset_tools = unreal.get_editor_subsystem(unreal.EditorAssetSubsystem)
|
||||
if asset_tools:
|
||||
# 尝试通过 EditorAssetSubsystem 创建
|
||||
# 复制模板资产
|
||||
new_asset = unreal.EditorAssetLibrary.duplicate_asset(TEMPLATE_IA, asset_path)
|
||||
if new_asset:
|
||||
print(f"[InputSetup] 复制创建成功: {asset_path} — {desc}")
|
||||
return new_asset
|
||||
|
||||
print(f"[InputSetup] 复制创建失败: {name}")
|
||||
return None
|
||||
|
||||
|
||||
def create_input_action_by_factory(name: str, desc: str) -> object:
|
||||
"""通过 AssetTools + Factory 创建 InputAction(备用方案)。"""
|
||||
asset_path = f"{IA_PACKAGE}/{name}"
|
||||
|
||||
if asset_exists(asset_path):
|
||||
return unreal.load_asset(asset_path)
|
||||
|
||||
try:
|
||||
factory = unreal.InputActionFactory()
|
||||
new_asset = asset_tools.create_asset(name, IA_PACKAGE, unreal.InputAction, factory)
|
||||
if new_asset:
|
||||
print(f"[InputSetup] 创建成功: {asset_path} — {description}")
|
||||
return new_asset
|
||||
except Exception:
|
||||
print("[InputSetup] InputActionFactory 不可用")
|
||||
return None
|
||||
|
||||
# 备用方案:使用 Python BPLib 或直接构造
|
||||
print(f"[InputSetup] 尝试备用方案创建: {name}")
|
||||
factory = unreal.InputActionFactory()
|
||||
new_asset = unreal.AssetToolsHelpers.get_asset_tools().create_asset(
|
||||
name, IA_PACKAGE[5:], # 去掉 /Game/ 前缀
|
||||
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
|
||||
if not asset_tools:
|
||||
return None
|
||||
|
||||
# create_asset 的 package_path 需要去掉 /Game/ 前缀
|
||||
new_asset = asset_tools.create_asset(
|
||||
name,
|
||||
IA_PACKAGE[5:], # "Input/Actions"
|
||||
unreal.InputAction,
|
||||
factory
|
||||
)
|
||||
if new_asset:
|
||||
print(f"[InputSetup] 备用方案创建成功: {asset_path}")
|
||||
return new_asset
|
||||
print(f"[InputSetup] Factory 创建成功: {asset_path} — {desc}")
|
||||
return new_asset
|
||||
|
||||
print(f"[InputSetup] ERROR: 无法创建 {name}")
|
||||
|
||||
def create_input_action(name: str, desc: str) -> object:
|
||||
"""创建 InputAction 资产,依次尝试多种方法。"""
|
||||
asset_path = f"{IA_PACKAGE}/{name}"
|
||||
|
||||
# 已存在则直接加载
|
||||
if asset_exists(asset_path):
|
||||
print(f"[InputSetup] 已存在: {asset_path}")
|
||||
return unreal.load_asset(asset_path)
|
||||
|
||||
print(f"[InputSetup] 尝试创建: {name} — {desc}")
|
||||
|
||||
# 方法1: 复制已有模板(最可靠)
|
||||
result = create_input_action_by_duplicate(name, desc)
|
||||
if result:
|
||||
return result
|
||||
|
||||
# 方法2: Factory 创建
|
||||
result = create_input_action_by_factory(name, desc)
|
||||
if result:
|
||||
return result
|
||||
|
||||
print(f"[InputSetup] ERROR: 所有创建方法均失败: {name}")
|
||||
return None
|
||||
|
||||
|
||||
def add_key_mapping_to_imc(imc: unreal.InputMappingContext, ia: unreal.InputAction, key: unreal.Key):
|
||||
"""向 IMC 添加按键映射"""
|
||||
mapping = unreal.InputMapping()
|
||||
mapping.set_editor_property("action", ia)
|
||||
def try_update_imc(created_ias: dict) -> bool:
|
||||
"""尝试更新 IMC_Default 添加按键映射。
|
||||
|
||||
key_mapping = unreal.KeyMapping()
|
||||
key_mapping.set_editor_property("key", key)
|
||||
key_mapping.set_editor_property("scale", 1.0)
|
||||
|
||||
# 设置触发器
|
||||
# key_mapping 的 triggers 由 IMC 内部管理
|
||||
|
||||
# 使用 IMC 的 API 添加映射
|
||||
try:
|
||||
# UE5.7: 使用 mappings 属性
|
||||
existing_mappings = imc.get_editor_property("mappings")
|
||||
new_mapping = unreal.InputMapping()
|
||||
new_mapping.set_editor_property("action", ia)
|
||||
|
||||
km = unreal.KeyMapping()
|
||||
km.set_editor_property("key", key)
|
||||
km.set_editor_property("scale", 1.0)
|
||||
|
||||
# 设置 triggers
|
||||
triggers = [unreal.InputTriggerDown()]
|
||||
km.set_editor_property("triggers", triggers)
|
||||
new_mapping.set_editor_property("key_mappings", [km])
|
||||
|
||||
existing_mappings.append(new_mapping)
|
||||
imc.set_editor_property("mappings", existing_mappings)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"[InputSetup] 添加映射失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 50)
|
||||
print("[InputSetup] v0.1 角色控制 Input 资产创建脚本")
|
||||
print(f"[InputSetup] 项目: {PROJECT_ROOT}")
|
||||
print("=" * 50)
|
||||
|
||||
# ---- Step 1: 创建 InputAction 资产 ----
|
||||
print("\n[InputSetup] Step 1: 创建 InputAction 资产")
|
||||
created_ias = {}
|
||||
for name, config in NEW_INPUT_ACTIONS.items():
|
||||
ia = create_input_action(name, config["description"])
|
||||
if ia:
|
||||
created_ias[name] = ia
|
||||
else:
|
||||
print(f"[InputSetup] WARNING: {name} 创建失败,后续 IMC 映射将跳过此 IA")
|
||||
|
||||
if not created_ias:
|
||||
print("[InputSetup] ERROR: 没有成功创建任何 IA,终止")
|
||||
return False
|
||||
|
||||
# ---- Step 2: 保存新创建的 IA 资产 ----
|
||||
print("\n[InputSetup] Step 2: 保存新创建的资产")
|
||||
for name, ia in created_ias.items():
|
||||
asset_path = f"{IA_PACKAGE}/{name}"
|
||||
unreal.EditorAssetLibrary.save_asset(asset_path)
|
||||
print(f"[InputSetup] 已保存: {asset_path}")
|
||||
|
||||
# ---- Step 3: 更新 IMC_Default ----
|
||||
print(f"\n[InputSetup] Step 3: 更新 IMC: {IMC_PATH}")
|
||||
返回 True 表示成功,False 表示需要手动操作。
|
||||
由于 UE5 Python API 对 Enhanced Input 的暴露有限,
|
||||
此功能可能失败——失败时提供手动操作指引。
|
||||
"""
|
||||
print(f"[InputSetup] 加载 IMC: {IMC_PATH}")
|
||||
|
||||
if not asset_exists(IMC_PATH):
|
||||
print(f"[InputSetup] ERROR: IMC 不存在: {IMC_PATH}")
|
||||
print(f"[InputSetup] ERROR: IMC 不存在: {IMC_PATH}")
|
||||
return False
|
||||
|
||||
imc = unreal.load_asset(IMC_PATH)
|
||||
if not imc:
|
||||
print(f"[InputSetup] ERROR: 无法加载 IMC: {IMC_PATH}")
|
||||
print(f"[InputSetup] ERROR: 无法加载 IMC")
|
||||
return False
|
||||
|
||||
# 读取当前映射数量
|
||||
try:
|
||||
current_mappings = imc.get_editor_property("mappings")
|
||||
print(f"[InputSetup] 当前 IMC 映射数: {len(current_mappings)}")
|
||||
print(f"[InputSetup] 当前映射数: {len(current_mappings)}")
|
||||
except Exception as e:
|
||||
print(f"[InputSetup] WARNING: 无法读取映射: {e}")
|
||||
current_mappings = []
|
||||
print(f"[InputSetup] 无法读取 mappings 属性: {e}")
|
||||
return False
|
||||
|
||||
# 添加新映射
|
||||
for name, config in NEW_INPUT_ACTIONS.items():
|
||||
if name not in created_ias:
|
||||
# 解析所有需要的 Key
|
||||
key_map = {}
|
||||
for ia_info in NEW_INPUT_ACTIONS:
|
||||
if ia_info["name"] not in created_ias:
|
||||
continue
|
||||
key = resolve_key(ia_info["key_name"])
|
||||
if key is None:
|
||||
print(f"[InputSetup] 无法解析按键: {ia_info['key_name']},跳过 IMC 自动更新")
|
||||
return False
|
||||
key_map[ia_info["name"]] = key
|
||||
|
||||
# 尝试添加映射
|
||||
success_count = 0
|
||||
for ia_info in NEW_INPUT_ACTIONS:
|
||||
name = ia_info["name"]
|
||||
if name not in created_ias or name not in key_map:
|
||||
continue
|
||||
|
||||
ia = created_ias[name]
|
||||
key = config["key"]
|
||||
success = add_key_mapping_to_imc(imc, ia, key)
|
||||
if success:
|
||||
print(f"[InputSetup] 已添加映射: {name} → {key}")
|
||||
key = key_map[name]
|
||||
|
||||
try:
|
||||
new_mapping = unreal.InputMapping()
|
||||
new_mapping.set_editor_property("action", ia)
|
||||
|
||||
km = unreal.KeyMapping()
|
||||
km.set_editor_property("key", key)
|
||||
|
||||
# 尝试设置触发器(可能不支持)
|
||||
try:
|
||||
km.set_editor_property("triggers", [unreal.InputTriggerDown()])
|
||||
except Exception:
|
||||
pass # 触发器使用默认值
|
||||
|
||||
new_mapping.set_editor_property("key_mappings", [km])
|
||||
|
||||
current_mappings.append(new_mapping)
|
||||
imc.set_editor_property("mappings", current_mappings)
|
||||
success_count += 1
|
||||
print(f"[InputSetup] 映射已添加: {name} → {ia_info['key_name']}")
|
||||
except Exception as e:
|
||||
print(f"[InputSetup] 映射添加失败: {name} — {e}")
|
||||
return False
|
||||
|
||||
if success_count == len(created_ias):
|
||||
# 保存 IMC
|
||||
unreal.EditorAssetLibrary.save_asset(IMC_PATH)
|
||||
print(f"[InputSetup] IMC 已保存")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("[InputSetup] v0.1 角色控制 Input 资产创建脚本")
|
||||
print("=" * 60)
|
||||
|
||||
# ---- Step 1: 创建 InputAction 资产 ----
|
||||
print("\n[InputSetup] Step 1/4: 创建 InputAction 资产")
|
||||
print(f"[InputSetup] 模板: {TEMPLATE_IA}")
|
||||
|
||||
if not asset_exists(TEMPLATE_IA):
|
||||
print(f"[InputSetup] ERROR: 模板 IA 不存在: {TEMPLATE_IA}")
|
||||
print("[InputSetup] 可用 IA 资产:")
|
||||
# 尝试列出 Actions 目录下的资产作为替代
|
||||
try:
|
||||
assets = unreal.EditorAssetLibrary.list_assets(IA_PACKAGE)
|
||||
for a in assets:
|
||||
print(f"[InputSetup] {a}")
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
created_ias = {}
|
||||
for ia_info in NEW_INPUT_ACTIONS:
|
||||
ia = create_input_action(ia_info["name"], ia_info["desc"])
|
||||
if ia:
|
||||
created_ias[ia_info["name"]] = ia
|
||||
else:
|
||||
print(f"[InputSetup] WARNING: 映射添加失败: {name}")
|
||||
print(f"[InputSetup] WARNING: {ia_info['name']} 创建失败")
|
||||
|
||||
# ---- Step 4: 保存 IMC ----
|
||||
print("\n[InputSetup] Step 4: 保存 IMC")
|
||||
unreal.EditorAssetLibrary.save_asset(IMC_PATH)
|
||||
print(f"[InputSetup] 已保存: {IMC_PATH}")
|
||||
if not created_ias:
|
||||
print("[InputSetup] ERROR: 没有成功创建任何 IA")
|
||||
return False
|
||||
|
||||
# ---- Step 5: 验证 ----
|
||||
print("\n[InputSetup] Step 5: 验证")
|
||||
try:
|
||||
updated_mappings = imc.get_editor_property("mappings")
|
||||
print(f"[InputSetup] 更新后 IMC 映射数: {len(updated_mappings)}")
|
||||
except:
|
||||
pass
|
||||
|
||||
# 验证 IA 资产
|
||||
for name in NEW_INPUT_ACTIONS:
|
||||
# ---- Step 2: 保存新创建的 IA 资产 ----
|
||||
print(f"\n[InputSetup] Step 2/4: 保存资产 ({len(created_ias)} 个)")
|
||||
for name in created_ias:
|
||||
asset_path = f"{IA_PACKAGE}/{name}"
|
||||
exists = asset_exists(asset_path)
|
||||
print(f"[InputSetup] {name}: {'✅ 存在' if exists else '❌ 不存在'}")
|
||||
unreal.EditorAssetLibrary.save_asset(asset_path)
|
||||
print(f"[InputSetup] 已保存: {asset_path}")
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("[InputSetup] 完成!请在 UE5 编辑器中验证。")
|
||||
print("[InputSetup] 注意:需要在 BP_ChildHoodCharacter 中将新增 IA 属性指向对应资产")
|
||||
print("=" * 50)
|
||||
# ---- Step 3: 尝试更新 IMC ----
|
||||
print(f"\n[InputSetup] Step 3/4: 更新 IMC_Default")
|
||||
imc_ok = False
|
||||
try:
|
||||
imc_ok = try_update_imc(created_ias)
|
||||
except Exception as e:
|
||||
print(f"[InputSetup] IMC 更新异常: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
if not imc_ok:
|
||||
print("[InputSetup] ⚠️ IMC 自动更新未成功,需要手动操作(见下方指引)")
|
||||
|
||||
# ---- Step 4: 验证 ----
|
||||
print(f"\n[InputSetup] Step 4/4: 验证")
|
||||
all_ok = True
|
||||
for ia_info in NEW_INPUT_ACTIONS:
|
||||
asset_path = f"{IA_PACKAGE}/{ia_info['name']}"
|
||||
exists = asset_exists(asset_path)
|
||||
status = "✅" if exists else "❌"
|
||||
print(f"[InputSetup] {status} {ia_info['name']}")
|
||||
if not exists:
|
||||
all_ok = False
|
||||
|
||||
# ---- 总结 ----
|
||||
print("\n" + "=" * 60)
|
||||
if imc_ok:
|
||||
print("[InputSetup] ✅ 全部完成(IA 创建 + IMC 更新)")
|
||||
print("[InputSetup] ⚠️ 仍需手动:BP_ChildHoodCharacter → Details → Input → 绑定 IA 属性")
|
||||
else:
|
||||
print("[InputSetup] ⚠️ IA 资产已创建,IMC 需手动配置")
|
||||
print()
|
||||
print("[InputSetup] === 手动操作指引 ===")
|
||||
print()
|
||||
print("1. 打开 IMC_Default (Content/Input/IMC_Default)")
|
||||
print(" 添加 3 个映射:")
|
||||
for ia_info in NEW_INPUT_ACTIONS:
|
||||
print(f" - {ia_info['key_name']} → {ia_info['name']}")
|
||||
print()
|
||||
print("2. 打开 BP_ChildHoodCharacter (Content/BP/Character/)")
|
||||
print(" Details → Input → 设置以下属性:")
|
||||
print(" - Interact Action → IA_Interact")
|
||||
print(" - Cancel Action → IA_Cancel")
|
||||
print(" - Switch Interact Action → IA_SwitchInteract")
|
||||
print()
|
||||
print("=" * 60)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user