#include "MetaCoreRuntimeInput/MetaCoreInputMap.h" #include #include #include #include namespace MetaCore { std::vector MetaCoreValidateInputMap(const MetaCoreInputMapDocument& document) { std::vector issues; std::unordered_set actionIds, axisIds, bindingIds, contextIds; for (const auto& value : document.Actions) { if (value.Id.empty() || !actionIds.insert(value.Id).second) issues.push_back({true, value.Id, "Action ID 为空或重复"}); } for (const auto& value : document.Axes) { if (value.Id.empty() || !axisIds.insert(value.Id).second) issues.push_back({true, value.Id, "Axis ID 为空或重复"}); if (value.DeadZone < 0.0F || value.DeadZone >= 1.0F || value.Sensitivity < 0.0F || value.Minimum >= value.Maximum) issues.push_back({true, value.Id, "Axis 死区、灵敏度或取值范围无效"}); } for (const auto& value : document.Bindings) { if (value.BindingId.empty() || !bindingIds.insert(value.BindingId).second) issues.push_back({true, value.BindingId, "Binding ID 为空或重复"}); if (value.ControlPath.empty() || value.ControlPath.front() != '<' || value.ControlPath.find("/", 1) == std::string::npos) issues.push_back({true, value.BindingId, "控制路径无效"}); const bool targetExists = value.Target == MetaCoreInputBindingTarget::Action ? actionIds.contains(value.TargetId) : axisIds.contains(value.TargetId); if (!targetExists) issues.push_back({true, value.BindingId, "Binding 目标不存在"}); } for (const auto& value : document.Contexts) { if (value.Id.empty() || !contextIds.insert(value.Id).second) issues.push_back({true, value.Id, "Context ID 为空或重复"}); for (const auto& binding : value.BindingIds) if (!bindingIds.contains(binding)) issues.push_back({true, value.Id, "Context 引用了不存在的 Binding: " + binding}); } return issues; } bool MetaCoreWriteInputMap(const std::filesystem::path& path, const MetaCoreInputMapDocument& document, const MetaCoreTypeRegistry& registry) { const auto bytes = MetaCoreSerializeToBytes(document, registry); if (!bytes) return false; std::error_code error; std::filesystem::create_directories(path.parent_path(), error); std::ofstream output(path, std::ios::binary | std::ios::trunc); if (!output) return false; output.write(reinterpret_cast(bytes->data()), static_cast(bytes->size())); return output.good(); } std::optional MetaCoreReadInputMap(const std::filesystem::path& path, const MetaCoreTypeRegistry& registry) { std::ifstream input(path, std::ios::binary | std::ios::ate); if (!input) return std::nullopt; const auto size = static_cast(input.tellg()); input.seekg(0); std::vector bytes(size); if (size && !input.read(reinterpret_cast(bytes.data()), static_cast(size))) return std::nullopt; MetaCoreInputMapDocument result; if (!MetaCoreDeserializeFromBytes(std::span(bytes.data(), bytes.size()), result, registry)) return std::nullopt; return result; } MetaCoreInputMapDocument MetaCoreBuildDefaultInputMap() { MetaCoreInputMapDocument map; map.Actions = {{"Interact", "Interact"}, {"Cancel", "Cancel"}}; map.Axes = {{"MoveX", "Move X", 0.15F, 1.0F, -1.0F, 1.0F}, {"MoveY", "Move Y", 0.15F, 1.0F, -1.0F, 1.0F}, {"LookX", "Look X", 0.0F, 1.0F, -1.0F, 1.0F}, {"LookY", "Look Y", 0.0F, 1.0F, -1.0F, 1.0F}}; map.Bindings = { {"game.interact.mouse", "Interact", MetaCoreInputBindingTarget::Action, "/leftButton", 1.0F, {}}, {"game.cancel.escape", "Cancel", MetaCoreInputBindingTarget::Action, "/Escape", 1.0F, {}}, {"game.move.left", "MoveX", MetaCoreInputBindingTarget::Axis, "/A", -1.0F, {}}, {"game.move.right", "MoveX", MetaCoreInputBindingTarget::Axis, "/D", 1.0F, {}}, {"game.move.back", "MoveY", MetaCoreInputBindingTarget::Axis, "/S", -1.0F, {}}, {"game.move.forward", "MoveY", MetaCoreInputBindingTarget::Axis, "/W", 1.0F, {}}, {"game.look.x", "LookX", MetaCoreInputBindingTarget::Axis, "/delta/x", 1.0F, {}}, {"game.look.y", "LookY", MetaCoreInputBindingTarget::Axis, "/delta/y", 1.0F, {}}, {"game.pad.move.x", "MoveX", MetaCoreInputBindingTarget::Axis, "/leftStick/x", 1.0F, {}}, {"game.pad.move.y", "MoveY", MetaCoreInputBindingTarget::Axis, "/leftStick/y", 1.0F, {}} }; MetaCoreInputContextDefinition gameplay{"Gameplay", 0, true, false, {}}; for (const auto& binding : map.Bindings) gameplay.BindingIds.push_back(binding.BindingId); map.Contexts.push_back(std::move(gameplay)); return map; } } // namespace MetaCore