从一开始学编程接触的是JAVA,然后就是C#,现在看这C++代码实在是不太明白。简单来说这是一段分析星际争霸2游戏录像文件的程序,从replay中提取玩家的ID,游戏种族,APM,游戏时间等数据。代码比较长,不要求全部转换成C#,只要说明思路,我该怎么去改,或者给个简短的例子只把游戏玩家的ID提取出来就可以。 现在主要的问题是我不知道怎么从录像文件中去找这些数据的位置。需要的话这里有一个录像文件作为例子:
http://img.sc2.cc/uenbbsattachments/attachments/mon_201002/25/20_4b864be73f4b7.sc2replay
C++源码[code=C++] SC2_REP(char* sc2rep)
{
Initialize();
Open(sc2rep);
} SC2_REP()
{
Initialize();
} void Initialize()
{
//Initialize
analysed = false;
isrep = false;
mapexist = false;
countmessage = 0;
maxmessage = 100;
playercount = 0;
message = ALLOCMEM(SC2MessageEntry, maxmessage);
} void Open(char* sc2rep)
{
strcpy(FileName,sc2rep);
int nError = 1;
DWORD t;
HANDLE hMPQ, hMessage, hInfo, hSync, hEvent; nError = SFileOpenArchive(sc2rep, 0, 0, &hMPQ); if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.message.events", 0, &hMessage);
else
{
printf("File can`t open\n");
nError = 0;
return;
} if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.info", 0, &hInfo);
else
nError = 0; if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.sync.events", 0, &hSync);
else
nError = 0; if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.game.events", 0, &hEvent);
else
nError = 0; if(nError == 1 && hMessage && hInfo && hSync && hEvent)
{
SizeMessage = SFileGetFileSize(hMessage, &t);
SizeInfo = SFileGetFileSize(hInfo, &t);
SizeEvent = SFileGetFileSize(hEvent, &t);
ElapseTime = SFileGetFileSize(hSync, &t);
ElapseTime /= 64;
}
else
{
printf("File %s is not a SC2Replay file\n");
nError = 0;
return;
} if(nError == 1)
{
if(SizeMessage)
{
BMessage = ALLOCMEM(BYTE, SizeMessage);
if(BMessage)
SFileReadFile(hMessage, BMessage, SizeMessage);
}
if(SizeInfo)
{
BInfo = ALLOCMEM(BYTE, SizeInfo);
if(BInfo)
SFileReadFile(hInfo, BInfo, SizeInfo);
}
if(SizeEvent)
{
BEvent = ALLOCMEM(BYTE, SizeEvent);
if(BEvent)
SFileReadFile(hEvent, BEvent, SizeEvent);
}
} if(nError == 1)
{
SFileCloseFile(hMessage);
SFileCloseFile(hInfo);
SFileCloseFile(hSync);
SFileCloseFile(hEvent);
SFileCloseArchive(hMPQ);
isrep=true;
analyse();
}
else
{
printf("%s is not SC2Replay file\n", sc2rep);
}
} int BigEndian(BYTE *in)
{
BYTE t[4];
for(int i=0;i<4;i++)
t[i]=in[3-i];
return *(int*)t;
}
void analyse(void)
{
//Read Player Slot
int InfoPointer=0;
int n=0;//Total 6
while(*(int*)(BInfo + InfoPointer) != 0x746C6644)
InfoPointer++; //cache
InfoPointer += 0x12;
memmove(MapFile, BInfo + InfoPointer + 1, *(BYTE*)(BInfo + InfoPointer));
MapFile[*(BYTE*)(BInfo + InfoPointer)] = 0;
//set map path
char tstr[100];
for(int i = 0; i < strlen(MapFile); i++)
if(MapFile[i] == '/')
MapFile[i] = '\\'; FullMapFile[0] = 0;
GetEnvironmentVariableA("HOMEDRIVE", tstr, 100);
strcat(FullMapFile, tstr);
GetEnvironmentVariableA("HOMEPATH", tstr, 100);
strcat(FullMapFile, tstr);
strcat(FullMapFile, "\\Local Settings\\Application Data\\Blizzard Entertainment\\Battle.net\\cache\\");
strcat(FullMapFile, MapFile);
//Open Map File
HANDLE hMap;
mapexist = SFileOpenArchive(FullMapFile, 0, 0, &hMap);
if(!mapexist || !hMap)
mapexist = false; if(mapexist)
{
SFileCloseArchive(hMap);
map.Open(FullMapFile);
}
while(n<6)
{//Search 6th "s2ma"
InfoPointer++;
if(*(int*)(BInfo + InfoPointer)==0x616D3273)
n++;
}
memmove(BattleNet, BInfo + InfoPointer + 5, 2);
BattleNet[2] = 0;
InfoPointer += 0x41;//Map Name
strcpy(MapName, (char*)(BInfo+InfoPointer));
InfoPointer += strlen((char*)BInfo+InfoPointer) + 5;
//Player Slots
while(playercount<16)
{
int tint[4];
n=*(BYTE*)(BInfo + InfoPointer);
if(!n)
break;
memmove(Player[playercount].ID, BInfo+InfoPointer + 1, n);
Player[playercount].ID[n] = 0;
InfoPointer += n + 1; n=*(BYTE*)(BInfo + InfoPointer);
memmove(Player[playercount].Race, BInfo + InfoPointer + 1, n);
Player[playercount].Race[n] = 0;
InfoPointer += n + 1; n=*(BYTE*)(BInfo + InfoPointer);
sscanf((char*)(BInfo + InfoPointer + 1),"%d,%d,%d,%d", tint, tint+1, tint+2, tint+3);
Player[playercount].A = tint[0];
Player[playercount].R = tint[1];
Player[playercount].G = tint[2];
Player[playercount].B = tint[3];
InfoPointer += n + 1;
playercount++;
}
//Read Message
if(SizeMessage)
{
int HeadPointer = 0, ContentPointer = 0;
do
HeadPointer += sizeof(SC2MessageHead);
while(BMessage[HeadPointer]==0 && BMessage[HeadPointer+2]==0x80 && BMessage[HeadPointer+3]==0 && BMessage[HeadPointer+4]==0); messagehead = ALLOCMEM(SC2MessageHead, HeadPointer / sizeof(SC2MessageHead));
memmove(messagehead, BMessage, HeadPointer); ContentPointer = HeadPointer;
char tinv[2];//Invert Big-Endian
SC2MessageEntry tEntry;
unsigned __int16 tframe;
int framecount = 0;
int tinvert; while(ContentPointer < SizeMessage)
{
if(BMessage[ContentPointer + 3] ==0)
{
//2byte , Invert
tinv[1] = BMessage[ContentPointer];
tinv[0] = BMessage[ContentPointer+1];
tinvert = 2;
}
else
{
//1
tinv[1] = 0;
tinv[0] = BMessage[ContentPointer];
tinvert = 1;
}
tframe = *(unsigned __int16*)tinv;
framecount += tframe;
tEntry.Frame = framecount;
tEntry.Sender = BMessage[ContentPointer + tinvert];
tEntry.Content = ALLOCMEM(char, BMessage[ContentPointer + tinvert + 2] + 1);
memmove(tEntry.Content,BMessage + ContentPointer + tinvert + 3, BMessage[ContentPointer + tinvert + 2]);
tEntry.Content[BMessage[ContentPointer + tinvert + 2]] = 0;
pushmessage(tEntry);
ContentPointer += tinvert + 3 + BMessage[ContentPointer + tinvert + 2];
}
}
analysed=true;
}
};void main(int argc, char ** argv)
{
if(argc==2)
{
SC2_REP rep(argv[1]);
rep.printrep();
rep.printplayer();
rep.printmessage();
}
else
{
char str[300]="";
printf("Input replay file path:\n");
scanf("%s",str);
SC2_REP rep(str);
rep.printrep();
rep.printplayer();
rep.printmessage();
}
system("pause");
}[/code]
http://img.sc2.cc/uenbbsattachments/attachments/mon_201002/25/20_4b864be73f4b7.sc2replay
C++源码[code=C++] SC2_REP(char* sc2rep)
{
Initialize();
Open(sc2rep);
} SC2_REP()
{
Initialize();
} void Initialize()
{
//Initialize
analysed = false;
isrep = false;
mapexist = false;
countmessage = 0;
maxmessage = 100;
playercount = 0;
message = ALLOCMEM(SC2MessageEntry, maxmessage);
} void Open(char* sc2rep)
{
strcpy(FileName,sc2rep);
int nError = 1;
DWORD t;
HANDLE hMPQ, hMessage, hInfo, hSync, hEvent; nError = SFileOpenArchive(sc2rep, 0, 0, &hMPQ); if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.message.events", 0, &hMessage);
else
{
printf("File can`t open\n");
nError = 0;
return;
} if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.info", 0, &hInfo);
else
nError = 0; if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.sync.events", 0, &hSync);
else
nError = 0; if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.game.events", 0, &hEvent);
else
nError = 0; if(nError == 1 && hMessage && hInfo && hSync && hEvent)
{
SizeMessage = SFileGetFileSize(hMessage, &t);
SizeInfo = SFileGetFileSize(hInfo, &t);
SizeEvent = SFileGetFileSize(hEvent, &t);
ElapseTime = SFileGetFileSize(hSync, &t);
ElapseTime /= 64;
}
else
{
printf("File %s is not a SC2Replay file\n");
nError = 0;
return;
} if(nError == 1)
{
if(SizeMessage)
{
BMessage = ALLOCMEM(BYTE, SizeMessage);
if(BMessage)
SFileReadFile(hMessage, BMessage, SizeMessage);
}
if(SizeInfo)
{
BInfo = ALLOCMEM(BYTE, SizeInfo);
if(BInfo)
SFileReadFile(hInfo, BInfo, SizeInfo);
}
if(SizeEvent)
{
BEvent = ALLOCMEM(BYTE, SizeEvent);
if(BEvent)
SFileReadFile(hEvent, BEvent, SizeEvent);
}
} if(nError == 1)
{
SFileCloseFile(hMessage);
SFileCloseFile(hInfo);
SFileCloseFile(hSync);
SFileCloseFile(hEvent);
SFileCloseArchive(hMPQ);
isrep=true;
analyse();
}
else
{
printf("%s is not SC2Replay file\n", sc2rep);
}
} int BigEndian(BYTE *in)
{
BYTE t[4];
for(int i=0;i<4;i++)
t[i]=in[3-i];
return *(int*)t;
}
void analyse(void)
{
//Read Player Slot
int InfoPointer=0;
int n=0;//Total 6
while(*(int*)(BInfo + InfoPointer) != 0x746C6644)
InfoPointer++; //cache
InfoPointer += 0x12;
memmove(MapFile, BInfo + InfoPointer + 1, *(BYTE*)(BInfo + InfoPointer));
MapFile[*(BYTE*)(BInfo + InfoPointer)] = 0;
//set map path
char tstr[100];
for(int i = 0; i < strlen(MapFile); i++)
if(MapFile[i] == '/')
MapFile[i] = '\\'; FullMapFile[0] = 0;
GetEnvironmentVariableA("HOMEDRIVE", tstr, 100);
strcat(FullMapFile, tstr);
GetEnvironmentVariableA("HOMEPATH", tstr, 100);
strcat(FullMapFile, tstr);
strcat(FullMapFile, "\\Local Settings\\Application Data\\Blizzard Entertainment\\Battle.net\\cache\\");
strcat(FullMapFile, MapFile);
//Open Map File
HANDLE hMap;
mapexist = SFileOpenArchive(FullMapFile, 0, 0, &hMap);
if(!mapexist || !hMap)
mapexist = false; if(mapexist)
{
SFileCloseArchive(hMap);
map.Open(FullMapFile);
}
while(n<6)
{//Search 6th "s2ma"
InfoPointer++;
if(*(int*)(BInfo + InfoPointer)==0x616D3273)
n++;
}
memmove(BattleNet, BInfo + InfoPointer + 5, 2);
BattleNet[2] = 0;
InfoPointer += 0x41;//Map Name
strcpy(MapName, (char*)(BInfo+InfoPointer));
InfoPointer += strlen((char*)BInfo+InfoPointer) + 5;
//Player Slots
while(playercount<16)
{
int tint[4];
n=*(BYTE*)(BInfo + InfoPointer);
if(!n)
break;
memmove(Player[playercount].ID, BInfo+InfoPointer + 1, n);
Player[playercount].ID[n] = 0;
InfoPointer += n + 1; n=*(BYTE*)(BInfo + InfoPointer);
memmove(Player[playercount].Race, BInfo + InfoPointer + 1, n);
Player[playercount].Race[n] = 0;
InfoPointer += n + 1; n=*(BYTE*)(BInfo + InfoPointer);
sscanf((char*)(BInfo + InfoPointer + 1),"%d,%d,%d,%d", tint, tint+1, tint+2, tint+3);
Player[playercount].A = tint[0];
Player[playercount].R = tint[1];
Player[playercount].G = tint[2];
Player[playercount].B = tint[3];
InfoPointer += n + 1;
playercount++;
}
//Read Message
if(SizeMessage)
{
int HeadPointer = 0, ContentPointer = 0;
do
HeadPointer += sizeof(SC2MessageHead);
while(BMessage[HeadPointer]==0 && BMessage[HeadPointer+2]==0x80 && BMessage[HeadPointer+3]==0 && BMessage[HeadPointer+4]==0); messagehead = ALLOCMEM(SC2MessageHead, HeadPointer / sizeof(SC2MessageHead));
memmove(messagehead, BMessage, HeadPointer); ContentPointer = HeadPointer;
char tinv[2];//Invert Big-Endian
SC2MessageEntry tEntry;
unsigned __int16 tframe;
int framecount = 0;
int tinvert; while(ContentPointer < SizeMessage)
{
if(BMessage[ContentPointer + 3] ==0)
{
//2byte , Invert
tinv[1] = BMessage[ContentPointer];
tinv[0] = BMessage[ContentPointer+1];
tinvert = 2;
}
else
{
//1
tinv[1] = 0;
tinv[0] = BMessage[ContentPointer];
tinvert = 1;
}
tframe = *(unsigned __int16*)tinv;
framecount += tframe;
tEntry.Frame = framecount;
tEntry.Sender = BMessage[ContentPointer + tinvert];
tEntry.Content = ALLOCMEM(char, BMessage[ContentPointer + tinvert + 2] + 1);
memmove(tEntry.Content,BMessage + ContentPointer + tinvert + 3, BMessage[ContentPointer + tinvert + 2]);
tEntry.Content[BMessage[ContentPointer + tinvert + 2]] = 0;
pushmessage(tEntry);
ContentPointer += tinvert + 3 + BMessage[ContentPointer + tinvert + 2];
}
}
analysed=true;
}
};void main(int argc, char ** argv)
{
if(argc==2)
{
SC2_REP rep(argv[1]);
rep.printrep();
rep.printplayer();
rep.printmessage();
}
else
{
char str[300]="";
printf("Input replay file path:\n");
scanf("%s",str);
SC2_REP rep(str);
rep.printrep();
rep.printplayer();
rep.printmessage();
}
system("pause");
}[/code]
解决方案 »
- tablelayoutpanel 怎样合并单元格
- 如何将datatable中的rows随机划分
- C#中Interface和泛型一起使用后,有一个问题,因为本人不了解Interface和泛型,自己写了一个实例来测试,现在遇到难题了。
- 类继承System.IDisposable的写法
- 如何控制 EXCEL 插入复制单元格?
- (糊涂的我真的不懂)C#中的""和NULL和String.Empty之间到底有什么区别?
- 求助,关于excel数据读取的问题
- 编译时生成的.exe文件名是由什么决定的?
- NET中的TREEVIEW中的图标在XP中丢失了,是VS的BUG,现在有补丁嗎
- 请教:初学c#,应该怎么学?
- ARCGIS ENGINE中怎么设置图层的alpha值?
- C#操作html源码问题,获取name或id对应的value怎么写比较好呢?
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <iostream>
#include <math.h>
#pragma pack(1)
#define FPS 63
using namespace std;typedef unsigned char BYTE;#define __STORMLIB_SELF__
#define __LINK_STORM_DLL__
#include "StormLib.h" //这个库是操作MPQ文档的库
typedef struct _SC2MessageHead//录像文件的消息头
{
BYTE unknown1;//一直是 00
BYTE unknown2;//0x21 or 0x22
BYTE unknown3;//一直是 80
BYTE unknown4;//一直是 00
BYTE unknown5;//一直是 00
USHORT unknown6;// 变量,小头在前的格式
}SC2MessageHead,*pSC2MessageHead;
typedef struct _SC2MessageEntry//自定义的消息入口
{
DWORD Frame;
BYTE Sender;
char *Content;
}SC2MessageEntry,*pSC2MessageEntry;
typedef struct _SC2_Action//游戏操作
{
int frame; //帧数
char type[20]; //估计是行为的ID或名字
}SC2_Action,*pSC2_Action;
typedef struct _SC2_Camera//游戏镜头的信息结构
{
int x; //横坐标
int y; //纵坐标
int hor;
int vet;
int un;
}SC2_Camera,*pSC2_Camera;
class SC2_Player//游戏玩家的信息结构
{
public:
char ID[60]; //玩家ID
char Race[20];
int startlocation; //玩家起始位置
int HPrate; //可能是种族
BYTE A; //玩家颜色
BYTE R;
BYTE G;
BYTE B;
pSC2_Action action;
pSC2_Camera camera;
int countaction,maxaction;
int countcamera,maxcamera; SC2_Player(void) //初始化玩家信息
{
startlocation = 0;
countaction = 0;
maxaction = 100;
countcamera = 0;
HPrate = 0;
maxcamera = 100;
action=ALLOCMEM(SC2_Action,maxaction);
camera=ALLOCMEM(SC2_Camera,maxcamera);
}
void pushaction(SC2_Action a)//填充玩家的操作信息
{
if(countaction==maxaction)
{
pSC2_Action t = ALLOCMEM(SC2_Action, maxaction*2);
if(!t)
t=t;
memmove(t,action,maxaction*sizeof(SC2_Action));
maxaction*=2;
free(action);
action = t;
}
action[countaction++] = a;
}
void pushcamera(SC2_Camera a)//填充添加玩家镜头信息
{
if(countcamera+1>maxcamera)
{
pSC2_Camera t = ALLOCMEM(SC2_Camera, maxcamera*2);
memmove(t,camera,maxcamera*sizeof(SC2_Camera));
maxcamera*=2;
free(camera);
camera = t;
}
camera[countcamera++] = a;
} double APM(int frame)//计算APM
{
return countaction*66.0/(frame);
}
};class SC2_MAP //游戏地图信息
{
public:
int height, width;//大小
bool opened; //是否打开或者说本地存在
SC2_MAP(void)
{
Initialize();
}
SC2_MAP(char *map)
{
Initialize();
Open(map);
}
void Initialize(void)//初始化
{
height = 0;
width = 0;
opened = false;
}
void Open(char* map)//打开地图文件获取地图大小
{
HANDLE hMap, hFile;
int filelen;
DWORD t;
DWORD nError;
BYTE buffer[16];
nError = SFileOpenArchive(map, 0, 0, &hMap);//根据地图文件名打开地图文件(MPQ格式文档)
if(nError == 1 && hMap)
nError = SFileOpenFileEx(hMap, "mapinfo", 0, &hFile);//从中找到mapinfo文件并读取
else
nError = 0;
if(nError == 1 && hMap && hFile)
{
filelen = SFileGetFileSize(hFile, &t);//确定mapinfo文件存在
if(filelen)
{
SFileReadFile(hFile, buffer, 16);//读取文件的前16BYTE位
height = *(int*)(buffer + 8);//偏移8byte读取int地图高度
width = *(int*)(buffer + 12);//偏移12byte读取int地图宽度
opened = true;//置标识位
}
else
nError = 0;
}
else
nError = 0; SFileCloseFile(hFile);//关闭mapinfo文件
SFileCloseArchive(hMap);//关闭地图文件 }};
class SC2_REP//录像文档
{public:
SC2_MAP map;
SC2_Player Player[16];
int playercount; //玩家总数
pSC2MessageHead messagehead;
pSC2MessageEntry message;
int countmessage,maxmessage;
int SizeMessage,SizeSync,SizeInfo,SizeEvent;
BYTE *BMessage,*BSync,*BInfo, *BEvent;
int ElapseTime; //录像时长
char MapName[100];
char FileName[300];
char MapFile[300];
char FullMapFile[500];
char BattleNet[4];
bool analysed;
bool isrep;
bool mapexist;
int mapwidth;
int mapheight;
void pushmessage(SC2MessageEntry a)//填充游戏信息
{
if(countmessage + 1 > maxmessage)//数组不够就扩大1倍
{
pSC2MessageEntry t = ALLOCMEM(SC2MessageEntry, maxmessage*2);
memmove(t,message,maxmessage*sizeof(SC2MessageEntry));
maxmessage*=2;
free(message);
message = t;
}
message[countmessage++] = a;
} void printrep()
{
if(isrep && analysed)//判断是录像并分析过了
{
int hour,minute,second;
hour = ElapseTime / 3600;
minute = (ElapseTime - hour * 3600) / 60;
second = (ElapseTime - hour * 3600 - minute * 60) ;
printf("Starcraft2 replay file: %s\n", FileName);//打印录像文件名
printf("MAP: %s\n", MapName);//打印地图名
printf("Cache: %s (%s)\n", FullMapFile, mapexist ? "Exist" : "Doesn`t Exist");//打印地图地址和是否存在此地图
printf("BattleNet: %s\n", BattleNet);//战网名
printf("Elapse Time: %02d:%02d:%02d\n", hour, minute, second);//打印录像的时长
} }
void printplayer()
{
if(isrep && analysed)
{
//show
printf("\nPlayer: \n");
for(int i = 0; i < playercount; i++)//打印全部玩家信息
{
printf("%s", Player[i].ID);
if(strlen(Player[i].ID)>7)//对齐
printf("\t");
else
printf("\t\t"); printf("%s\tStart:%02d\tAPM: %.2lf", Player[i].Race, Player[i].startlocation, Player[i].APM(ElapseTime));//打印玩家的Race(不清楚),玩家起始位置和平均APM值。
printf("\tARGB:(%d, %d, %d, %d)\n", Player[i].A, Player[i].R, Player[i].G, Player[i].B);//玩家颜色的ARGB格式码
}
}
}
void printmessage()
{
if(isrep && analysed)
{
if(SizeMessage)
{
int hour,minute,second;
printf("\nMessage\n");
for(int i = 0; i < countmessage; i++)//打印全部玩家的聊天信息
{
hour = message[i].Frame / (3600 * FPS);
minute = (message[i].Frame - hour * 3600 * FPS) / (60 * FPS);
second = (message[i].Frame - hour * 3600 * FPS - minute * 60 * FPS ) / FPS;
printf("%02d:%02d:%02d %s: %s\n", hour, minute, second, Player[message[i].Sender-1].ID, message[i].Content);//打印玩家聊天信息
}
}
else
{
printf("\nNo message\n");
}
}
}
SC2_REP(char* sc2rep)
{
Initialize();
Open(sc2rep);
} SC2_REP()
{
Initialize();
} void Initialize() //初始化
{
//Initialize
analysed = false;
isrep = false;
mapexist = false;
countmessage = 0;
maxmessage = 100;
playercount = 0;
message = ALLOCMEM(SC2MessageEntry, maxmessage);
} void Open(char* sc2rep)//打开录像文件
{
strcpy(FileName,sc2rep);
int nError = 1;
DWORD t;
HANDLE hMPQ, hMessage, hInfo, hSync, hEvent; nError = SFileOpenArchive(sc2rep, 0, 0, &hMPQ);//打开录像文档(MPQ格式) if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.message.events", 0, &hMessage);//读取玩家聊天信息文档
else
{
printf("File can`t open\n");
nError = 0;
return;
} if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.info", 0, &hInfo);//读取录像信息文档
else
nError = 0; if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.sync.events", 0, &hSync);//读取同步信息文档,但后面好像没用
else
nError = 0; if(nError == 1 && hMPQ)
nError = SFileOpenFileEx(hMPQ, "replay.game.events", 0, &hEvent);//读取录像中事件信息文档
else
nError = 0; if(nError == 1 && hMessage && hInfo && hSync && hEvent)//确认文件全部打开并获取文件大小
{
SizeMessage = SFileGetFileSize(hMessage, &t);
SizeInfo = SFileGetFileSize(hInfo, &t);
SizeEvent = SFileGetFileSize(hEvent, &t);
ElapseTime = SFileGetFileSize(hSync, &t);
ElapseTime /= 64; //计算录像时长
}
else
{
printf("File %s is not a SC2Replay file\n");
nError = 0;
return;
} if(nError == 1)
{
if(SizeMessage)
{
BMessage = ALLOCMEM(BYTE, SizeMessage);
if(BMessage)
SFileReadFile(hMessage, BMessage, SizeMessage);//读取聊天信息文件到信息数组
}
if(SizeInfo)
{
BInfo = ALLOCMEM(BYTE, SizeInfo);
if(BInfo)
SFileReadFile(hInfo, BInfo, SizeInfo);//读取信息文件到信息数组
}
if(SizeEvent)
{
BEvent = ALLOCMEM(BYTE, SizeEvent);
if(BEvent)
SFileReadFile(hEvent, BEvent, SizeEvent);//读取事件文件中事件到数组
}
} if(nError == 1) //读取完成关闭文档
{
SFileCloseFile(hMessage);
SFileCloseFile(hInfo);
SFileCloseFile(hSync);
SFileCloseFile(hEvent);
SFileCloseArchive(hMPQ);
isrep=true;
analyse(); //对文档进行分析
}
else
{
printf("%s is not SC2Replay file\n", sc2rep);
}
} int BigEndian(BYTE *in)//大端BigEndian换位
{
BYTE t[4];
for(int i=0;i<4;i++)
t[i]=in[3-i];
return *(int*)t;
}
void analyse(void)//分析方法
{
//读取玩家信息入口
int InfoPointer=0;
int n=0;//Total 6
while(*(int*)(BInfo + InfoPointer) != 0x746C6644)//从“replay.info”内容中找到0x746C6644
InfoPointer++; //cache
InfoPointer += 0x12;//偏移0x12
memmove(MapFile, BInfo + InfoPointer + 1, *(BYTE*)(BInfo + InfoPointer));//读取地图文件名字
MapFile[*(BYTE*)(BInfo + InfoPointer)] = 0;
//开始拼地图文件的全路径
char tstr[100];
for(int i = 0; i < strlen(MapFile); i++)
if(MapFile[i] == '/')
MapFile[i] = '\\'; FullMapFile[0] = 0;
GetEnvironmentVariableA("HOMEDRIVE", tstr, 100);
strcat(FullMapFile, tstr);
GetEnvironmentVariableA("HOMEPATH", tstr, 100);
strcat(FullMapFile, tstr);
strcat(FullMapFile, "\\Local Settings\\Application Data\\Blizzard Entertainment\\Battle.net\\cache\\");
strcat(FullMapFile, MapFile)
//打开地图文件
HANDLE hMap;
mapexist = SFileOpenArchive(FullMapFile, 0, 0, &hMap);
if(!mapexist || !hMap)
mapexist = false;//地图是否存在 if(mapexist)
{
SFileCloseArchive(hMap);
map.Open(FullMapFile);//map对象打开分析地图信息
}
while(n<6) //从“replay.info”内容中继续找到第6个s2ma
{//Search 6th "s2ma"
InfoPointer++;
if(*(int*)(BInfo + InfoPointer)==0x616D3273)
n++;
}
memmove(BattleNet, BInfo + InfoPointer + 5, 2);//应该该是战网缩写
BattleNet[2] = 0;
InfoPointer += 0x41;//偏移至地图名称
strcpy(MapName, (char*)(BInfo+InfoPointer));
InfoPointer += strlen((char*)BInfo+InfoPointer) + 5;
//获取玩家信息
while(playercount<16)
{
int tint[4];
n=*(BYTE*)(BInfo + InfoPointer);
if(!n) //判断是否有第n个玩家
break;
memmove(Player[playercount].ID, BInfo+InfoPointer + 1, n);//获取玩家ID
Player[playercount].ID[n] = 0;
InfoPointer += n + 1; n=*(BYTE*)(BInfo + InfoPointer);
memmove(Player[playercount].Race, BInfo + InfoPointer + 1, n);//获取玩家Race
Player[playercount].Race[n] = 0;
InfoPointer += n + 1; n=*(BYTE*)(BInfo + InfoPointer);
sscanf((char*)(BInfo + InfoPointer + 1),"%d,%d,%d,%d", tint, tint+1, tint+2, tint+3); //获取玩家颜色
Player[playercount].A = tint[0];
Player[playercount].R = tint[1];
Player[playercount].G = tint[2];
Player[playercount].B = tint[3];
InfoPointer += n + 1;
playercount++;
}
//读取聊天信息
if(SizeMessage)
{
int HeadPointer = 0, ContentPointer = 0;
do
HeadPointer += sizeof(SC2MessageHead);
while(BMessage[HeadPointer]==0 && BMessage[HeadPointer+2]==0x80 && BMessage[HeadPointer+3]==0 && BMessage[HeadPointer+4]==0); messagehead = ALLOCMEM(SC2MessageHead, HeadPointer / sizeof(SC2MessageHead));
memmove(messagehead, BMessage, HeadPointer); ContentPointer = HeadPointer;
char tinv[2];//Invert Big-Endian
SC2MessageEntry tEntry;
unsigned __int16 tframe;
int framecount = 0;
int tinvert; while(ContentPointer < SizeMessage)
{
if(BMessage[ContentPointer + 3] ==0)
{
//2byte , Invert
tinv[1] = BMessage[ContentPointer];
tinv[0] = BMessage[ContentPointer+1];
tinvert = 2;
}
else
{
//1
tinv[1] = 0;
tinv[0] = BMessage[ContentPointer];
tinvert = 1;
}
tframe = *(unsigned __int16*)tinv;
framecount += tframe;
tEntry.Frame = framecount;
tEntry.Sender = BMessage[ContentPointer + tinvert];
tEntry.Content = ALLOCMEM(char, BMessage[ContentPointer + tinvert + 2] + 1);
memmove(tEntry.Content,BMessage + ContentPointer + tinvert + 3, BMessage[ContentPointer + tinvert + 2]);
tEntry.Content[BMessage[ContentPointer + tinvert + 2]] = 0;
pushmessage(tEntry);
ContentPointer += tinvert + 3 + BMessage[ContentPointer + tinvert + 2];
}
}
//APM
int p=0;
BYTE *t;
int frame=0;
int cframe=0;
int framelength=0;
int t1,t2;
BYTE Big_Endian[4];
int cPlayer;
SC2_Action tAction;
SC2_Camera tCamera; while(p<SizeEvent) //从"replay.game.events"文件中读取游戏事件
{
t=BEvent+p;
if(p>=0x7758)
p=p;
if(t[0]==0 && t[2]==0x1b) //初始化偏移位置
p+=3;
else if(t[0]==0 && t[1]==0x10 && t[2]==0x05) //开始
p+=3;
else
{
//游戏的帧数
framelength = 1;
while(1)
{
if(t[framelength+1]==0x0B)
break;
if(t[framelength+1]%16==0x0C && t[framelength+1]/16<=10)
break;
if(t[framelength+1]%16==0x0D && t[framelength+1]/16<=9)
break;
if(t[framelength+1]==0x81)
break;
framelength++;
}
if(framelength>=3)
{
t += framelength - 1;
p += framelength - 1;
framelength = 1;
}
memset(Big_Endian, 0, 4);
for(int i=0;i< framelength;i++)
Big_Endian[i] = t[framelength - 1 - i];
t1=*(int *)Big_Endian;
if(t1>500)
{
t+=framelength-2;
p+=framelength-2;
framelength=2;
memset(Big_Endian,0,4);
for(int i=0;i< framelength - 1;i++)
Big_Endian[i] = t[framelength - 2 - i];
t1=*(int *)Big_Endian;
}
//获取玩家
if(t[framelength]==0x81)
{
cframe+=t1;
cPlayer=t[framelength-1]-0x61;
}
else
{
frame+=t1;
cPlayer=t[framelength-1]-0x21;
}
if(cPlayer<0||cPlayer>0xF)
{
p++;
continue;
}
//获取玩家操作类型
if(t[framelength]==0x81)
{
//改变镜头
p+=framelength+21;
tCamera.x=BigEndian(t+framelength+1);
tCamera.y=BigEndian(t+framelength+5);
tCamera.hor=BigEndian(t+framelength+9);
tCamera.vet=BigEndian(t+framelength+13);
tCamera.un=BigEndian(t+framelength+17);
Player[cPlayer].pushcamera(tCamera);
}
else if(t[framelength]==0xAC || t[framelength]>=0x0C && t[framelength]<=0x9C)
{
//选择单位
if(t[framelength+1]==0 && t[framelength+4]==0 && t[framelength+5]==0)
{
p+=framelength+4;
tAction.frame=cframe;
sprintf(tAction.type,"Shift Del Slot %d", t[framelength+2]);
Player[cPlayer].pushaction(tAction);
}
else
{
t1=t[framelength+8];//单位
t2=8+4*t1+framelength;
while(t[t2]!=1&&t[t2]!=2&&t[t2]!=3)
t2++;//Ending with 0x01 if(t[t2+3]==0x89)
{
while(t[t2+3]==0x89)
t2+=7;
}
else if(t[t2+4]==0x89)
{
t2++;
while(t[t2+3]==0x89)
t2+=7;
} p+=t2+1;
tAction.frame=cframe;
if(t[framelength+4]==0x48 || t[framelength+5]==0x48)
sprintf(tAction.type,"Shift Add %d",t1);//续编
else
sprintf(tAction.type,"Select %d",t1);//选中某单位
Player[cPlayer].pushaction(tAction);
}
}
else if(t[framelength]==0x0B)
{
//操作指令(攻击,维修等)
int relative=33;
if(*(int*)(t+framelength+4)==0)
relative-=6;
if(relative==33)
{
if(t[framelength+19])
relative++;
else
relative=relative;
}
if(t[relative+4]==0x89)
relative+=7;
p+=framelength+relative;
sprintf(tAction.type,"Order");
tAction.frame=cframe;
Player[cPlayer].pushaction(tAction); }
else if(t[framelength] % 16 == 0x0D)
{
if(t[framelength+1])
{
//单位编组
p+=5;
sprintf(tAction.type,"HK Assign %d", t[framelength] / 16);
tAction.frame=cframe;
Player[cPlayer].pushaction(tAction);
}
else
{
//选择编组
p+=5;
sprintf(tAction.type,"HK Select %d", t[framelength] / 16);
tAction.frame=cframe;
Player[cPlayer].pushaction(tAction);
}
}
else
{
p++;
continue;
} //check end
}
}
//分析玩家起始位置
if(mapexist)
{
double cx,cy,x,y,degree;
cx = map.width / 2.0;
cy = map.height / 2.0;
for(int i = 0; i < playercount; i++)
{
if(Player[i].countcamera)
{
x = Player[i].camera[0].x / 65536 - cx;//根据玩家第一个镜头(肯定是自己的主基地),计算初始位置(如5点钟位置)
y = Player[i].camera[0].y / 65536 - cy;
degree = atan(y / x) * 180 / 3.1415926;
if(degree < 0)
{
while(degree < 0)
degree += 360;
}
else if(degree >= 360)
degree -= 360;
if(degree >= 345 && degree <= 360 || degree >= 0 && degree < 15)
Player[i].startlocation = 3;
else if(degree >= 15 && degree < 45)
Player[i].startlocation = 2;
else if(degree >= 45 && degree < 75)
Player[i].startlocation = 1;
else if(degree >= 75 && degree < 105)
Player[i].startlocation = 12;
else if(degree >= 105 && degree < 135)
Player[i].startlocation = 11;
else if(degree >= 135 && degree < 165)
Player[i].startlocation = 10;
else if(degree >= 165 && degree < 195)
Player[i].startlocation = 9;
else if(degree >= 195 && degree < 225)
Player[i].startlocation = 8;
else if(degree >= 225 && degree < 255)
Player[i].startlocation = 7;
else if(degree >= 255 && degree < 285)
Player[i].startlocation = 6;
else if(degree >= 285 && degree < 315)
Player[i].startlocation = 5;
else if(degree >= 315 && degree < 345)
Player[i].startlocation = 4;
else
Player[i].startlocation = 0;
} } }
analysed=true;
}
};void main(int argc, char ** argv)
{
if(argc==2)
{
SC2_REP rep(argv[1]);
rep.printrep();
rep.printplayer();
rep.printmessage();
}
else
{
char str[300]="";
printf("Input replay file path:\n");
scanf("%s",str);
SC2_REP rep(str);
rep.printrep();
rep.printplayer();
rep.printmessage();
}
system("pause");
}
主要的分析代码在第三部分也就是SC2_REP的analyse方法。
重点是MPQ文档操作的库StormLib这个,网上可以找到,找不到也可以发邮件给我。
我做java的,本来想用java改一个,但是用不了这个MPQ库,而且类型长度差异和不能指针问题弄的我很烦,还是你自己用C#写吧。
后悔当初没选C++。