网页雷达
写在前面
本项目完成于2025年9月,但是由于某些原因没有写成博客发不出来。现在风头过去了可以发了,所以把这篇文章发出来,也是记录一下学习。今后可能会回归web安全相关内容,暂时不搞逆向了。
项目
这里用一个前几年比较火的游戏————荒野行动 作为例子
效果图:
目录
|—–GameMaps
|–ConnectController.py
|–hy_web.e
|–XLC.html
|–XLC.png
hy_web.e
本地端:hy_web.e
本地端用e语言,主要是有现成的驱动,本人也是很早学过的,正好能熟练运用
这里主要是两个额外线程:读取数据线程和矩阵线程
数据读取模块:
.版本 2
PlayerControler = 读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (模块地址 + #PlayerAddr) + 88) + 192) + 984) + 96) + 56) + 984) + 96)
' 调试输出 (“playcontroler”, PlayerControler, 进制_十到十六 (PlayerControler))
.判断循环首 (真)
count = 读整数型 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (模块地址 + #PlayerAddr) + 88) + 192) + 984) + 96) + 56) + 984) + 104)
' 调试输出 (“count”, count, PlayerControler)
.计次循环首 (count, i)
playerOffset = 读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (读长整数 (PlayerControler + 0 + (i - 1) × 8) + 224) + 48) + 64) + 64) + 8) + 208)
' 调试输出 (“player”, playerOffset, 进制_十到十六 (playerOffset))
playerPos = GetPos (playerOffset)
' 调试输出 (“playerpos”, playerPos.x, playerPos.y, playerPos.z)
加入成员 (临时数组, playerOffset)
.计次循环尾 ()
全_对象数组 = 临时数组
' 调试输出 (全_对象数组)
清除数组 (临时数组)
延时 (1000)
.判断循环尾 ()
矩阵读取:
.版本 2
.版本 2
.子程序 Matrix
.局部变量 head, 长整数型
.局部变量 矩阵集合, 字节集
.局部变量 临时矩阵, 小数型, , "4,4"
.局部变量 Martixaddr, 长整数型
.判断循环首 (真)
Martixaddr = 进制_十六到十 (“0C7EF728”)
矩阵集合 = 读字节集 (Martixaddr, 64)
临时矩阵 [1] [1] = 取字节集数据 (矩阵集合, #小数型, 1)
临时矩阵 [1] [2] = 取字节集数据 (矩阵集合, #小数型, 5)
临时矩阵 [1] [3] = 取字节集数据 (矩阵集合, #小数型, 9)
临时矩阵 [1] [4] = 取字节集数据 (矩阵集合, #小数型, 13)
临时矩阵 [2] [1] = 取字节集数据 (矩阵集合, #小数型, 17)
临时矩阵 [2] [2] = 取字节集数据 (矩阵集合, #小数型, 21)
临时矩阵 [2] [3] = 取字节集数据 (矩阵集合, #小数型, 25)
临时矩阵 [2] [4] = 取字节集数据 (矩阵集合, #小数型, 29)
临时矩阵 [3] [1] = 取字节集数据 (矩阵集合, #小数型, 33)
临时矩阵 [3] [2] = 取字节集数据 (矩阵集合, #小数型, 37)
临时矩阵 [3] [3] = 取字节集数据 (矩阵集合, #小数型, 41)
临时矩阵 [3] [4] = 取字节集数据 (矩阵集合, #小数型, 45)
临时矩阵 [4] [1] = 取字节集数据 (矩阵集合, #小数型, 49)
临时矩阵 [4] [2] = 取字节集数据 (矩阵集合, #小数型, 53)
临时矩阵 [4] [3] = 取字节集数据 (矩阵集合, #小数型, 57)
临时矩阵 [4] [4] = 取字节集数据 (矩阵集合, #小数型, 61)
矩阵数组 = 临时矩阵
延时 (1)
' 调试输出 (“矩阵”, 临时矩阵)
.判断循环尾 ()
主线程负责转换成json并分发数据,这里采用tcp连接。按照需求应该用udp更好,不过这里对udp不太支持,所以只能略微牺牲一下速度了。
主线程:
.版本 2
.子程序 Drew
.局部变量 Aaary, 长整数型, , "0"
.局部变量 count, 整数型
.局部变量 i, 整数型
.局部变量 Object, 长整数型
.局部变量 pos, Vector3D
.局部变量 rect, Vector4D
.局部变量 数据, 类_json
' 绘制文本 (50, 50, “花蕊绘制-开源版”, #绿色, 30)
移动窗口 (句柄, 窗口矩形.左边, 窗口矩形.顶边, 窗口矩形.宽度 - 窗口矩形.左边, 窗口矩形.高度 - 窗口矩形.顶边, 假)
取窗口矩形_ (窗口句柄, 窗口矩形)
屏幕X = (窗口矩形.宽度 - 窗口矩形.左边) ÷ 2
屏幕Y = (窗口矩形.高度 - 窗口矩形.顶边) ÷ 2
Aaary = 全_对象数组
count = 取数组成员数 (Aaary)
.计次循环首 (count, i)
Object = Aaary [i]
pos = GetPos (Object)
数据.清除 ()
数据.置属性数值 (“id”, Object)
数据.置属性数值 (“x”, pos.x)
数据.置属性数值 (“y”, pos.y)
客户1.发送数据 (数据.取数据文本 () + #换行符)
.计次循环尾 ()
COnnectController.py
服务端,比较简陋,用ssti搭建,用于接受json并且返回给前端。
import asyncio
import json
import websockets
web_clients = set()
# === 1. WebSocket 服务器,给前端用 ===
async def websocket_handler(websocket):
print("前端连接成功")
web_clients.add(websocket)
try:
async for _ in websocket:
pass
finally:
web_clients.remove(websocket)
print("前端断开连接")
async def handle_tcp(reader, writer):
addr = writer.get_extra_info('peername')
print(f"TCP客户端连接: {addr}")
buffer = ""
try:
while True:
data = await reader.read(1024)
if not data:
break
buffer += data.decode()
while "\n" in buffer:
msg, buffer = buffer.split("\n", 1)
msg = msg.strip()
if not msg:
continue
print(f"收到 TCP 消息: {msg}")
try:
player_data = json.loads(msg) # JSON 格式: {"id":"p1","x":100,"y":200}
if web_clients:
await asyncio.gather(*[
ws.send(json.dumps(player_data))
for ws in web_clients
])
except json.JSONDecodeError:
print("收到的不是有效 JSON:", msg)
except Exception as e:
print("TCP错误:", e)
finally:
print("TCP客户端断开:", addr)
writer.close()
await writer.wait_closed()
# === 3. 主入口 ===
async def main():
ws_server = await websockets.serve(websocket_handler, "0.0.0.0", 8765)
tcp_server = await asyncio.start_server(handle_tcp, "0.0.0.0", 9000)
print("✅ WebSocket 服务器运行在 ws://0.0.0.0:8765")
print("✅ TCP 服务器运行在 tcp://0.0.0.0:9000")
async with ws_server, tcp_server:
await asyncio.gather(ws_server.wait_closed(), tcp_server.serve_forever())
if __name__ == "__main__":
asyncio.run(main())
前端
前端这一块主要使用leaflet.js作为地图引擎。这个还真挺不错的
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>游戏实时地图</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
<style>
#map {
height: 100vh;
width: 100vw;
}
.player-marker {
width: 12px;
height: 12px;
background: red;
border-radius: 50%;
border: 2px solid white;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
const minX = -3989, maxX = -3563;
const minY = -21, maxY = 405;
const map = L.map('map', {
crs: L.CRS.Simple,
minZoom: -2,
maxZoom: 4,
zoomSnap: 0.1,
});
const imageUrl = 'XLC.png';
const imageBounds = [[minY, minX], [maxY, maxX]];
L.imageOverlay(imageUrl, imageBounds).addTo(map);
map.fitBounds(imageBounds);
const players = {};
function updatePlayer(id, x, y) {
if (players[id]) {
players[id].setLatLng([y, x]);
} else {
const marker = L.marker([y, x], {
icon: L.divIcon({ className: 'player-marker' })
}).addTo(map);
players[id] = marker;
}
}
const ws = new WebSocket("ws://localhost:8765");
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
// 例如: { "id": "player1", "x": 123, "y": 456 }
updatePlayer(data.id, data.x, data.y);
};
</script>
</body>
</html>
最后呈现效果如图:
写在后面
Q:为什么不用绘制,而是写成网页雷达呢?
A:因为弥赛亚引擎是闭源引擎,目前找到的矩阵是尼玛3*4矩阵,市面上没有开源的转屏幕算法。我们这种散修师傅只能另寻出路,搞点简单的。
另外感谢网友车神,我和他一起研究的弥赛亚引擎,也是交上共同学习的好友了哈哈