客戶端的地圖文件探索
發表於 : 2020-09-18, 22:04
最近一個骨灰級的老玩家向我提問:
網上流傳一個工具能夠分析當前迷宮的出入口資訊是怎麼做到的
本來我不相信怎麼想都不可能, 後來這個玩家給我發了個圖是這個工具的樣貌,
我馬上想到查看客戶端的地圖文件是怎麼保存的, 我們將在下面解開這個謎題...
下面我們將進入一個迷宮
開始分析:
測試目標地圖: 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
網上流傳一個工具能夠分析當前迷宮的出入口資訊是怎麼做到的
本來我不相信怎麼想都不可能, 後來這個玩家給我發了個圖是這個工具的樣貌,
我馬上想到查看客戶端的地圖文件是怎麼保存的, 我們將在下面解開這個謎題...
下面我們將進入一個迷宮
開始分析:
測試目標地圖: 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
代碼: 選擇全部
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.