当前位置: 首页 > web >正文

[游戏实时地图] 地图数据 | 兴趣点数据 | 虚幻引擎SDK接口

黑神话·悟空-内置实时地图

在这里插入图片描述

一个为《黑神话:悟空》设计的小地图插件,提供实时位置追踪和导航功能。

  • GitHub 源代码: https://github.com/jaskang/wukong-minimap

更新日志

  • v1.7
    • 调整 UI
    • 添加大量点位
  • v1.6
    • 修复 AMD 显卡渲染问题
    • 添加点位

按键说明:

  • + 放大 小地图窗口
  • - 缩小 小地图窗口
  • Shift + + 放大 小地图比例
  • Shift + - 缩小 小地图比例
  • 0 显示/隐藏 地图

演示截图

在这里插入图片描述

安装说明

wukong-minimap.zip 直接解压至黑神话的安装文件夹下面的 b1\Binaries\Win64 中 (steam 的安装文件夹可以通过右键黑神话 -> 管理 -> 浏览本地文件找到)

在这里插入图片描述

本插件包含以下文件:

  • wukong_minimap.dll 插件功能核心文件
  • dwmapi.dll 加载器 - 通过代理系统功能来加载 wukong_minimap.dll
  • maps 地图文件夹

使用 UE4SS 的用户

由于 ue4ss 自带的 dwmapi.dll 拦截了系统 api 会导致插件无法顺利加载,我们使用 wukong-minimap 中的 dwmapi.dll 就行了。

卸载

删除 wukong_minimap.dll 文件即可

学习点:rust跨语言操作cpp,通过调库接口


教程:wukong-minimap

本项目为游戏《黑神话:悟空》提供小地图覆盖层
它通过钩取游戏渲染系统展示实时地图,显示玩家位置与朝向,以及从外部数据收集的各类兴趣点
使用游戏内部*SDK*读取玩家信息,并通过*钩子基础设施*与图形API交互绘制覆盖层

视觉概览

在这里插入图片描述

章节列表

  1. 地图数据
  2. 兴趣点数据
  3. 虚幻引擎SDK接口
  4. 游戏状态
  5. 小地图渲染器
  6. 钩子基础设施

第一章:地图数据

欢迎来到wukong-minimap教程的第一章!

  • 本章我们将通过理解插件如何识别游戏中的不同地图,探索小地图插件的基础构建模块。

  • 想象你有一叠纸质地图,每张显示不同区域或城市。

  • 要找到当前位置,首先需要确定哪张纸质地图对应当前位置。本插件的"地图数据"正是实现这一功能。

地图数据解决了什么问题?

小地图最基本的功能是展示当前位置在周边区域地图上的位置。但游戏世界庞大,可能包含多个关卡、地牢或开放区域。插件如何知道何时显示哪张地图?

这正是地图数据的作用!这是一组信息集合,告知插件游戏中每个特定区域对应的地图图像。

游戏世界可能如下结构:

在这里插入图片描述

每个位置(城镇广场、森林小径等)可能有专属地图。插件需要的数据应包含:

  • “城镇广场"地图对应游戏区域"Level_Town_01”
  • "黑暗洞穴"地图对应游戏区域"Level_Cave_01"特定XYZ坐标范围

地图数据建立了游戏内位置与地图图像的关联

地图数据结构

插件通过MapInfo结构体存储每个地图信息(见src/utils.rs):

// src/utils.rs(简化版)#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Area {pub start: [f32; 3], // X,Y,Z最小坐标pub end: [f32; 3],   // X,Y,Z最大坐标
}#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MapInfo {pub key: String,    // 唯一标识符(常为图片文件名)pub level: String,  // 所属游戏关卡名称pub range: Area,    // 主地理边界(游戏坐标系)pub scale: f32,     // 游戏坐标与图像像素比例pub areas: Vec<Area>, // 可选:主范围内的子区域pub url: String,    // 地图图像文件路径
}

关键字段解析:

  • key:地图条目唯一名称(如"forest_map.webp")
  • level:游戏引擎内部关卡名(如"Town_Level_01")
  • range:3D游戏世界的矩形边界框
  • areas:关卡内具体子区域(如城镇中的建筑)
  • url:地图图像文件相对路径

插件启动时通过load_data()加载数据:

// src/utils.rs(简化版)pub fn load_data() -> Vec<MapInfo> {let data = include_str!("./../includes/data.json"); // 从嵌入式文件读取let maps: Vec<MapInfo> = serde_json::from_str(data).unwrap(); // 解析JSONmaps // 返回地图列表
}

地图匹配逻辑

插件通过以下流程确定当前适用地图:

在这里插入图片描述

核心匹配逻辑见src/render.rs

// src/render.rs(简化版)impl MiniMap {fn update_map(&mut self) -> Option<MapInfo> {self.game = wukong::game_state(); // 获取游戏状态self.maps.iter().rev().find(|map| {// 检查关卡名称匹配self.game.level == map.level &&// 检查坐标是否在主范围self.game.x >= map.range.start[0] && ... // 检查子区域(如有)map.areas.is_empty() || map.areas.iter().any(|area| ... )}).cloned()}
}

总结

地图数据是wukong-minimap插件理解游戏世界布局的基础,通过:

  1. 定义游戏位置与地图图像的关联
  2. 使用三维坐标范围精确定位
  3. 支持多层次区域划分

下一章我们将探讨如何通过**兴趣点数据**标记地图上的关键位置。


第二章:兴趣点数据

欢迎回来!

  • 在第一章:地图数据中,我们学习了wukong-minimap插件如何根据玩家在游戏世界中的位置确定显示哪个地图图像

  • 现在既然已显示正确的地图,我们需要知道地图上有什么内容

  • 想象您正在使用手机地图应用。它不只显示道路,还会显示餐厅、地标、商店和其他重要地点。这些就是"兴趣点"。

兴趣点数据解决了什么问题?

游戏中充满了重要位置:下一任务点、强大BOSS所在地、隐藏宝藏点或材料采集点。在空白地图上仅显示玩家位置对寻找这些目标并无帮助。

**兴趣点数据(POI Data)**是告知插件地图上特定重要位置的信息集合。通过该数据,插件能绘制以下图标:

  • 需要击败的BOSS
  • 快速传送点
  • 特殊收集品(葫芦、酒食、仙丹)
  • 活动点(如打坐点)

若无POI数据,小地图仅是带玩家标记的图片。有了它,则成为实用的导航工具

兴趣点的定义

在本插件中,兴趣点是通过以下要素表示的简单概念:

  1. 位置:3D游戏世界坐标(X, Y, Z)
  2. 名称:描述性标签(如"森林BOSS"、“隐藏宝藏”)
  3. 类别:决定图标类型的分类(如"boss"、"baoxiang"宝箱、"teleport"传送)

代码中通过src/utils.rsPoint结构体表示:

// src/utils.rs(简化版)#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Point {pub name: String,pub category: String, // 决定图标类型pub x: f32,           // 游戏世界X坐标pub y: f32,           // 游戏世界Y坐标pub z: f32,           // 游戏世界Z坐标
}

数据加载机制

插件启动时通过src/utils.rsload_points()函数加载兴趣点数据:

// src/utils.rs(简化版)pub fn load_points() -> HashMap<String, Vec<Point>> {let data = include_str!("./../includes/data_points.json");let points: HashMap<String, Vec<Point>> = serde_json::from_str(data).unwrap();points // 返回按关卡分组的兴趣点
}

数据存储结构说明:

  • 哈希映射键:游戏关卡名(如"Level_Forest_01")
  • 哈希映射值:该关卡所有兴趣点的Point结构体列表

插件通过MiniMap结构体的points字段存储数据:

// src/render.rs(MiniMap结构体部分)pub struct MiniMap {// ... 其他字段 ...points: HashMap<String, Vec<Point>>, // 按关卡分组的兴趣点// ... 其他字段 ...
}

兴趣点渲染流程

  1. 确定当前地图:使用第一章逻辑获取匹配玩家位置的MapInfo
  2. 获取关联兴趣点:根据MapInfo.levelpoints哈希映射提取当前关卡所有兴趣点
  3. 区域过滤:通过is_in_map()函数筛选出当前地图范围内的兴趣点
  4. 图标选择:根据point.category匹配预加载的图标纹理
  5. 坐标转换:结合MapInfo.rangescale将游戏坐标转换为屏幕坐标
  6. 图形绘制:在地图背景上绘制图标

在这里插入图片描述

核心渲染代码段(src/render.rs):

// src/render.rs(简化版)if let Some(map) = self.map.as_ref() {self.points.get(map.level.as_str()).unwrap_or(&vec![]).iter().filter(|point| is_in_map(point, &map)).for_each(|point| {let icon = match point.category.as_str() {"teleport" => self.textures.teleport.id,"boss" => self.textures.boss.id,// ... 其他类别处理 ..._ => None,};if let Some(id) = icon {// 坐标转换与绘制逻辑draw_list.add_image(id, ...).build();}});
}

区域验证函数:

// src/utils.rs(简化版)pub fn is_in_map(point: &Point, map: &MapInfo) -> bool {if map.areas.is_empty() {point.x >= map.range.start[0] && ... // 主区域验证} else {map.areas.iter().any(|area| ... )    // 子区域验证}
}

总结

  • 兴趣点数据通过精准的坐标绑定和分类系统,将游戏内关键位置可视化为导航图标。

  • 结合地图数据的位置过滤机制,实现了动态的关卡兴趣点加载与渲染。

  • 下一章将深入解析如何通过**虚幻引擎SDK接口**获取实时游戏状态。


第三章:虚幻引擎SDK接口

在前两章中,我们探讨了wukong-minimap插件的静态数据基础

  • 第一章:地图数据揭示了不同区域对应的地图图像
  • 第二章:兴趣点数据则解析了地图上的关键标记。然而这些数据都是静态的(运行时不会改变)
  • 插件需要获取游戏实时动态信息才能发挥作用——这正是虚幻引擎SDK接口的核心使命。

SDK接口解决的问题

  • 想象游戏如同精密运转的机械系统,而我们的插件则是需要与之交互的外部设备

  • 如何询问"主齿轮位置"或"引擎转速"?

虚幻引擎SDK接口正是实现这种跨语言(Rust插件与C++游戏引擎)、跨进程通信的关键桥梁

其核心功能可概括为:

  1. 解析引擎结构:通过逆向工程生成的SDK代码,识别游戏对象(如玩家角色、关卡实例)的类定义与内存布局
  2. 实时数据捕获获取玩家坐标(X/Y/Z)、朝向角度、当前关卡名称等动态信息
  3. 引擎功能调用:控制鼠标显隐、调整输入模式等交互操作

核心应用场景:玩家状态捕获

插件最频繁的SDK调用是获取玩家实时状态,数据结构定义如下(b1sdk/src/b1sdk.h):

// b1sdk/src/b1sdk.h(简化版)
struct PlayerInfo {float x, y, z;       // 三维坐标float angle;          // 朝向角度uint8_t bShowMouse;   // 鼠标显隐状态char level[256];      // 当前关卡名
};

该结构通过FFI(外部函数接口)在C++与Rust间传递,需确保内存布局一致

插件与SDK的交互架构

在这里插入图片描述

关键步骤解析

  1. Rust FFI调用通过b1sdk_sys模块触发C++函数getPlayerInfo()实现跨语言操作
  2. 引擎对象获取
    • 使用SDK::UWorld::GetWorld()获取游戏世界实例
    • 通过UGameplayStatics获取玩家控制器(PlayerController)
  3. 数据采集
    // 获取玩家坐标
    SDK::FVector loc = playerCharacter->K2_GetActorLocation(); 
    // 获取关卡名称
    std::string level = GameplayStatics->GetCurrentLevelName();
    
  4. 状态控制
    // 设置鼠标显隐(示例代码)
    playerController->bShowMouseCursor = show ? 1 : 0;
    SDK::UGSE_EngineFuncLib::SetInputModeUIOnly(...);
    

SDK代码生成机制

逆向工程工具通过分析游戏内存结构,自动生成包含数千个类/函数的SDK代码库,例如:

// SDK/CoreUObject_functions.cpp(片段)
class UObject* FindObjectFastImpl(const std::string& Name) {// 遍历GObjects全局数组匹配对象
}

这些生成代码为插件提供了与虚幻引擎交互的"指令手册"

总结

虚幻引擎SDK接口通过三层架构实现数据贯通:

  1. 生成层逆向工程产出SDK定义文件(.h/.cpp
  2. 适配层C++包装代码(b1sdk)调用SDK函数
  3. 应用层:Rust插件通过FFI获取结构化数据,实现插件操作

此设计使得插件既能实时捕获玩家位置(用于地图渲染),又能控制游戏交互状态(如鼠标锁定)。下一章将深入探讨如何利用这些数据构建完整的**游戏状态系统**。

http://www.xdnf.cn/news/14426.html

相关文章:

  • 软考 系统架构设计师系列知识点之杂项集萃(89)
  • UFS Layout Guide (UFS 2.x)
  • 第11章:Neo4j实际应用案例
  • 把Cmakelist.txt转化为Qt Pro文件的方法
  • 如何让 AI 接入自己的 API?我开发了一个将 OpenAPI 文档转为 MCP 服务的工具
  • 深入理解Kafka Consumer:从理论到实战
  • 简化您的工作流程:在 Azure 中构建高效的逻辑应用程序
  • 电池预测 | 第32讲 Matlab基于CNN-BiLSTM-Attention的锂电池剩余寿命预测,附锂电池最新文章汇集
  • Zustand:小而美的React状态管理库详解
  • React 实现卡牌翻牌游戏
  • AI医生24小时在线:你的健康新‘算法监护人
  • 项目 : 基于正倒排的boost搜索引擎
  • 基于n8n快速开发股票舆情监控对话系统
  • Servlet完整笔记
  • 通过 BLE 和 Wi-Fi 交换优化基于 ID 的远程无人机通信的延迟
  • Bootstrap 5学习教程,从入门到精通, Bootstrap 5 列表组(List Group)语法知识点及案例(14)
  • 【图像处理入门】8. 数学基础与优化:线性代数、概率与算法调优实战
  • Python----OpenCV(图像的绘制——绘制椭圆,绘制文本,添加文字水印,添加图片水印)
  • Nginx限速配置详解
  • LeetCode 高频 SQL 50 题(基础版)【题解】合集
  • 高效开发REST API:Django REST Framework序列化器深度指南
  • 搭建K8s集群平台(详细版)
  • SQL Server 2025 预览版发布:AI深度集成、开发者体验飞跃与混合云新篇章
  • Java对象中的MarkWord
  • 【大厂机试题解法笔记】字符串加密
  • java 设计模式_行为型_18解释器模式
  • 【MySQL】TencentOS 安装登录MySQL
  • 【Flutter】解决小米澎湃系统迷你窗口、缩小窗口后界面空白问题
  • 电阻篇---常见作用
  • Rviz2中,在rviz和launch文件中都需要配置urdf文件,二者作用上的区别?