最近想要基于fsd来开发一套飞控系统,那么对FSD源码的研究是十分重要的。这篇文章将记录FSD与外界进行明文数据沟通的最重要的一环——Whazzup.txt
源码
fsd是基于c++构建的,我在这里将whazzup的生成代码贴在这里,其位置位于fsd.cpp中
// WhazzUp Start
if ((now-prevwhazzup)>=WHAZZUPCHECK)
{
configentry *entry;
configgroup *sysgroup=configman->getgroup("system");
if (sysgroup)
if ((entry=sysgroup->getentry("whazzup"))!=NULL)
{
if (whazzupfile)
free(whazzupfile);
whazzupfile=strdup(entry->getdata());
char whazzuptemp[100];
sprintf(whazzuptemp,"%s%s", whazzupfile, ".tmp");
prevwhazzup=now;
if (fileopen==0)
{
FILE *wzfile=fopen(whazzuptemp, "w");
if (wzfile)
{
//Ready to write data
fileopen = 1;
char s[32];
fprintf(wzfile,"%s%s\n","![DateStamp]",sprintgmtdate(now,s));
fprintf(wzfile,"%s\n","!GENERAL");
fprintf(wzfile,"%s = %d\n", "VERSION", 4);
fprintf(wzfile,"%s = %d\n", "RELOAD", 5);
fprintf(wzfile,"%s = %s\n", "UPDATE", sprintgmt(now, s));
client *tempclient;
flightplan *tempflightplan;
server *tempserver;
int clients=0;
for (tempclient=rootclient; tempclient; tempclient=tempclient->next)
clients++;
fprintf(wzfile,"%s = %d\n", "CONNECTED CLIENTS", clients);
int servers=0;
for (tempserver=rootserver; tempserver; tempserver=tempserver->next)
servers++;
fprintf(wzfile,"%s = %d\n", "CONNECTED SERVERS", servers);
fprintf(wzfile,"%s\n","!CLIENTS");
char dataseg1[150];
char dataseg2[150];
char dataseg3[150];
char dataseg4[150];
char dataseg5[150];
char dataseg6[2000];
char dataseg7[50];
for (tempclient=rootclient; tempclient; tempclient=tempclient->next)
{
sprintf(dataseg1,"%s:%s:%s:%s", tempclient->callsign, tempclient->cid, tempclient->realname, tempclient->type==CLIENT_ATC?"ATC":"PILOT");
if (tempclient->frequency!=0 && tempclient->frequency<100000 && tempclient)
sprintf(dataseg2,"1%02d.%03d", tempclient->frequency/1000, tempclient->frequency%1000);
else
sprintf(dataseg2,"%s","");
tempflightplan=tempclient->plan;
if (tempclient->lat!=0 && tempclient->altitude < 100000 && tempclient->lon != 0)
sprintf(dataseg3,"%f:%f:%d:%d", tempclient->lat, tempclient->lon, tempclient->altitude, tempclient->groundspeed);
else
sprintf(dataseg3,"%s",":::");
if (tempflightplan)
sprintf(dataseg4,"%s:%d:%s:%s:%s", tempflightplan->aircraft, tempflightplan->tascruise, tempflightplan->depairport, tempflightplan->alt, tempflightplan->destairport);
else
sprintf(dataseg4,"%s","::::");
sprintf(dataseg5,"%s:%s:%d:%d:%d:%d", tempclient->location->ident, tempclient->protocol, tempclient->rating, tempclient->transponder, tempclient->facilitytype, tempclient->visualrange);
if (tempflightplan)
sprintf(dataseg6,"%d:%c:%d:%d:%d:%d:%d:%d:%s:%s:%s", tempflightplan->revision, tempflightplan->type, tempflightplan->deptime, tempflightplan->actdeptime, tempflightplan->hrsenroute, tempflightplan->minenroute, tempflightplan->hrsfuel, tempflightplan->minfuel, tempflightplan->altairport, tempflightplan->remarks, tempflightplan->route);
else
sprintf(dataseg6,"%s","::::::::::");
sprintf(dataseg7,"::::::%s:%d", sprintgmt(tempclient->starttime,s), tempclient->pbh);
fprintf(wzfile,"%s:%s:%s:%s:%s:%s:%s\n", dataseg1, dataseg2, dataseg3, dataseg4, dataseg5, dataseg6, dataseg7);
}
char dataline[150];
fprintf(wzfile,"%s\n","!SERVERS");
for (tempserver=rootserver; tempserver; tempserver=tempserver->next)
if (strcmp(tempserver->hostname,"n/a") != 0)
{
sprintf(dataline,"%s:%s:%s:%s:%d", tempserver->ident, tempserver->hostname, tempserver->location, tempserver->name, tempserver->flags&SERVER_SILENT?0:1);
fprintf(wzfile,"%s\n",dataline);
};
fclose(wzfile);
remove(whazzupfile);
rename(whazzuptemp, whazzupfile);
fileopen=0;
}
else
fileopen=0;
}
}
}
// WhazzUp End
分析
整个whazzup分为三个部分 我将其称为基础信息、用户信息、服务器信息
基础信息
基础信息我们其实仅需要关注UPDATE , CONNECTED CLIENTS ,CONNECTED SERVERS 这几个标签即可。UPDATE显然记录的是更新的时间戳 ,CONNECTED CLIENTS记录的是连接到几个用户,CONNECTED SERVERS记录着连接到几台服务器(fsd原生支持多服务器联动)
用户信息
个人认为用户信息是最值得探究也是最为复杂的。在其源码中,我们可以看到使用了多次判断来决定是否要显示哪些信息,每个属性都是用“:”来分隔的。
首先前四个属性分别为 呼号:cid:真实姓名:类型 这些是所有用户都有的基础信息,在ECHO,Euroscpe中也是必填项,我们可以通过cid来追踪用户。类型则表示是飞行员还是管制。
接下来是 频率 这个是ATC专属的,它可以在euroscope中设置
后面两个是经纬度信息,飞行员即表示着其所在位置,ATC则是表示管制圈的中心点(存疑),这个是写死在扇区文件之中的,可以根据后面的半径来确定管制圈,这在连飞地图上非常有用。
接下来是高度:地速 这两个是在飞行员中有的 而在ATC上则是被填写了0
接下来是机型:巡航真空速:出发机场:巡航高度:目的地机场 这些是由飞行员填写的飞行计划中包含的
之后是标识:协议:等级:应答机 标识即在fsd.conf中定义的服务器标识,协议暂不清楚,等级则就是连接到服务器的用户等级1-12,可在adminhelp中查询到,应答机则就是飞行员的应答机号,ATC则标为0
然后是设施类型:视距:修订版本 这个应该是与metar有关
接下来是飞行类型:出发时间:实际出发时间:巡航飞行小时:巡航飞行分钟:燃油续航小时:燃油续航分钟。这些都是可选项,在ECHO等飞行连接器中可以填写 飞行类型则是I表示IFR,V表示VFR。
接下来是备降机场:备注:航路:起始时间。这些都是在ECHO中发送的飞行计划中的内容,起始时间之登录时间。
接下来我认为最为重要的就是PBH,"Pitch, Bank, Heading",即俯仰角、滚转角和航向角。这个数值可以通过位运算来表示飞机的姿态。根据源码中的说明:俯仰角=(pbh&4290772992)>>22,滚转角=(pbh&4190208)>>12,航向角=(pbh&4092)>>2,这样我们就可以获取飞机的姿态信息了。而在ATC中,他则表示的是在p3d,fsx中的塔台视角。
服务器信息
服务器信息比较简单 标识:服务器网络位置:服务器地区:服务器名称:服务器序号
这些都是在fsd.conf中定义的
总结
通过对whazzup的研究,我们可以通过这个文件来捕获基本所有的通信信息,对开发帮助非常之大。
呼号:CID:真实姓名:类型:频率:纬度:经度:海拔高度:地速:机型:巡航真空速:出发机场:巡航高度:目的地机场:标识:协议:等级:应答机:设施类型:视距:修订版本:飞行类型:预计起飞时间:实际起飞时间:巡航飞行小时:巡航飞行分钟:燃油续航小时:燃油续航分钟:备降机场:备注:航路:::::::登陆时间戳:偏航角