网页雷达

写在前面

本项目完成于2025年9月,但是由于某些原因没有写成博客发不出来。现在风头过去了可以发了,所以把这篇文章发出来,也是记录一下学习。今后可能会回归web安全相关内容,暂时不搞逆向了。

项目

这里用一个前几年比较火的游戏————荒野行动 作为例子

效果图:

cf4b5fc8db448713b1ce2573577cc9e5.png

目录

|—–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>

最后呈现效果如图:

s877a-5dme5.gif

写在后面

Q:为什么不用绘制,而是写成网页雷达呢?

A:因为弥赛亚引擎是闭源引擎,目前找到的矩阵是尼玛3*4矩阵,市面上没有开源的转屏幕算法。我们这种散修师傅只能另寻出路,搞点简单的。

另外感谢网友车神,我和他一起研究的弥赛亚引擎,也是交上共同学习的好友了哈哈