从一开始学编程接触的是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]

解决方案 »

  1.   

    完整源码下载地址:http://51.dc.ftn.qq.com/ftn_handler/6b596216ce4cf740f9df167331d14dc6a9659fcce8db33f158d9975ac86f5a102da348ac9631554b01e53703cf7d25233502a0902ef1cbd72ec1d17acbbfc704/Main.cpp?k=083666376286cdc7780f62374538001704065653560f07011953020f5615060f05554b0f535e511555030302075d0459570e075563303275555f081900484238&&txf_fid=4c2a1ff369285db9a8b5ec1afd08edca1b4cf218
      

  2.   

    第一部分:
    #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);//关闭地图文件 }};
      

  3.   

    第二部分:
    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;
    }
      

  4.   

    第三部分:
    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");
    }
      

  5.   

    我根据理解和查看录像文件的内容加的一些注释,希望对你有帮助!
    主要的分析代码在第三部分也就是SC2_REP的analyse方法。
    重点是MPQ文档操作的库StormLib这个,网上可以找到,找不到也可以发邮件给我。
    我做java的,本来想用java改一个,但是用不了这个MPQ库,而且类型长度差异和不能指针问题弄的我很烦,还是你自己用C#写吧。
      

  6.   

    做C++的赶紧给做个星际2的录像分析管理器,建议参考W3G Master样子,肯定好多人抢。
    后悔当初没选C++。
      

  7.   

    都是类c语言改起来很方便地,只不过访问特定的类库函数你要找到对应的,访问win32 API 的话声明一下就可以了
      

  8.   

    没有考虑过编写成dll然后用dllimport导入进来么?