客戶端的地圖文件探索

୧༼✿ ͡◕ д ◕͡ ༽୨ 法蘭城的約定
回覆文章
fantastic
技術組
文章: 33
註冊時間: 2020-08-25, 14:03

客戶端的地圖文件探索

文章 fantastic »

最近一個骨灰級的老玩家向我提問:
網上流傳一個工具能夠分析當前迷宮的出入口資訊是怎麼做到的
本來我不相信怎麼想都不可能, 後來這個玩家給我發了個圖是這個工具的樣貌,
我馬上想到查看客戶端的地圖文件是怎麼保存的, 我們將在下面解開這個謎題...

下載2.jpg
下載2.jpg (90.6 KiB) 已瀏覽 604 次

下面我們將進入一個迷宮
開始分析:




測試目標地圖: 31*48
出口水晶(7,14)---> 文件中的物理地址6854D 數據為03 測試對象為: 黃色傳送水晶
NPC及寶箱數據尚待確認 用地面資料:2來找也可以

文件大小(8948-20(文件首))/3 = 2976
8948-2976 = 5972(求得地面資料:3 的起始地址)
6854-5972 = 882 //

(1,1) (2,1).....................(31,1) -->31組數據 (往東走1步x+1 往西走1步x-1)
(1,2) (2,2).....................|
(1,3) (2,3).....................|
(1,14),(2,14)...(7,14)
// 2*31*(7-1)+14=386*2=上面的882 來到(7,14)


模擬搜索數據, 並計算樓梯座標:
第一步: 獲取當前地圖編號 獲取當前程序路徑 獲取當前程序路徑的Map\1\{地圖編號}.dat文件 並獲取迷宮W及H值 上例為W:=31; H:=48;
第二步: 獲取地圖文件大小8948後扣除常量20(文件首大小)再除以3(分割成三等分)得2976
第三步: 文件大小減去我們求得的2976 得5972為地面資料:3的起始點
第四步: 從文件5972至文件尾搜尋 如果發現03獲取該位置並到第五步
第五步: (獲取03的位置)6855-5972=882 // (882/2) mod 62 =14 (Y座標), (386-14)/62=6 6+1=7 (X座標)
#註 對於4.0以後的地圖 這個標記是0A 1C
20170518_b3811246344676974a7ePwLrfXhFJ3Wy.jpg
20170518_b3811246344676974a7ePwLrfXhFJ3Wy.jpg (48.53 KiB) 已瀏覽 604 次
20170519_eafc46de1734bc0035837Prs3Ww82WUS.jpg
20170519_eafc46de1734bc0035837Prs3Ww82WUS.jpg (9.81 KiB) 已瀏覽 604 次
20170519_c53b2c1e712f92d9d12ezL1n17HuH52U.jpg
20170519_c53b2c1e712f92d9d12ezL1n17HuH52U.jpg (84.5 KiB) 已瀏覽 604 次

代碼: 選擇全部

unit Unit1;
   
interface
   
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
   
type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
   
var
  Form1: TForm1;
   
const HEAD = 20; TwoBytes =2;
   
implementation
   
{$R *.dfm}
   
procedure TForm1.Button1Click(Sender: TObject);
var
  Stream: TFileStream;
  buf: pchar;
  Temp: Byte;
  East,West: integer;
  FileSize: longint;
  StartFromThree: longint;
  i:integer;
  X,Y:integer;
begin
  Memo1.Text:= '';
  buf := 'C:\Program Files (x86)\SOFTSTAR\魔力寶貝\map\1\3\1527.dat';
  if FileExists(buf) then
  begin
    Stream := TFileStream.Create(buf, fmOpenRead);
    with Stream do
    begin
      Position := 0;
      Position := Stream.Position + 12;
    end;
    Stream.Read(East, SizeOf(East));
    // showmessage(format('%d',[East])); // H
    { Position 移動一個integer單位 }
    Stream.Read(West, SizeOf(West));
    // showmessage(format('%d',[West])); // W
    FileSize := integer(Stream.Size);
    StartFromThree := FileSize - ((FileSize - HEAD) div 3); // 地面資料:3 起始點
    // showmessage(inttostr(StartFromThree));
    Stream.Position := StartFromThree;
   
    for i := 1 to (FileSize - StartFromThree) * 2 do // 從地面資料:3 起始點開始搜尋到文件末
    begin
      Stream.Read(Temp, 1);
      if Temp = $02 then // 如果找到 $02標記
      begin
        // showmessage(inttostr((Stream.Position) - 1));
        X := ((Stream.Position - StartFromThree) div 2) mod (East);
        Y := (((((Stream.Position - StartFromThree) div 2) - X)) div East);
        // Showmessage(format(' 東: %d 南: %d', [X, Y]));
        Memo1.Lines.Add(format(' 發現! 未知對象: 座標:(%3d,%3d)', [X, Y]))
      end;
      if Temp = $03 then // 如果找到 Warp標記
      begin
        // showmessage(inttostr((Stream.Position) - 1));
        X := ((Stream.Position - StartFromThree) div 2) mod (East);
        Y := (((((Stream.Position - StartFromThree) div 2) - X)) div East);
        // Showmessage(format(' 東: %d 南: %d', [X, Y]));
        Memo1.Lines.Add(format(' 發現! 場景轉換: 座標:(%3d,%3d)', [X, Y]))
      end;
    end;
    Stream.Free;
  end;
end;
   
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Text := '';
  Memo1.ReadOnly := True;
  Form1.BorderIcons:= [biSystemMenu,biMinimize];
end;
   
end.
回覆文章