📄 client.cpp
字号:
#include <stdlib.h>
#include <stdio.h>
#ifdef WIN32
#include <process.h>
#endif
#ifndef WIN32
#include "linux_syn.h"
#include <unistd.h>
#endif
#include "stopwatch.h"
#include "utils.h"
#include "client.h"
#include "worldmodel.h"
#include "perceptron.h"
#include "log.h"
#include "skill.h"
#include "agent.h"
#include "netif.h"
using namespace World;
float CP_est_max_AIcost = 23.0f; //estimation of max time length costed in AI update and decision-making
const float CP_min_waitvisualtime = 5.0f;
/*Note: Generally, sound info comes at 28 millisecond in the latest case.
But for sysfun "waitsingleobject", event notification is pretty accurate while waiting time is poor controlled.
CP_waitsoundtime is set as a high value because generally it can receive hear msg. -yjy
*/
const float CP_waitsoundtime = 50.0f;
/* Whether sever is available */
int ServerAlive = 0;
int NoResponseFromServer = 0;
void* InfProc(void*);
void* CtrlProc(void *);
bool ctrlthread_exit = true;
bool infthread_exit = true;
#ifdef WIN32
/* timer handle of information process and ai process */
HANDLE siginf = NULL, sigctrl = NULL;
CRITICAL_SECTION parse_update_mutex;
HANDLE newsenseinfo_event = NULL, newfullinfo_event =NULL, newsightinfo_event = NULL, newsoundinfo_event = NULL;
UINT WaitServerTimer = NULL;
//DWORD WINAPI InfProcWindows(LPVOID lpParameter);
unsigned int WINAPI InfProcWindows(void *);
unsigned int WINAPI CtrlProcWindows(LPVOID lpParameter);
void CALLBACK CheckServer(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);
#endif
#ifndef WIN32
pthread_mutex_t parse_update_mutex;
pthread_t siginf, sigctrl;
Event newsenseinfo_event, newfullinfo_event, newsightinfo_event, newsoundinfo_event;
bool CheckServer();
#endif
int InitInstance()
{
Log::InitLog();
Network::sock = Network::init_connection(ServerParam::host, ServerParam::port);
if(Network::sock == NULL){
my_error("Wrong Host %s!", ServerParam::host);
return false;
}
Skill::action.send_init_message();//sent init message
if (!Network::wait_message(StringBuffer::recvbuf,Network::sock)){// wait for server's reply
my_error("No response form server!");
return false;
}
if(!sensory.Parse_initialize_message(StringBuffer::recvbuf)){
my_error("Didn't get an init message: '%s')",StringBuffer::recvbuf);
ServerAlive = 0;
return 0;
}else{
ServerAlive = 1;
}
LogMat(LM_Init, "%s", MyTeamName);
LogMat(LM_Init, "%s", StringBuffer::recvbuf);
//receive server/player param and seven kinds of heterogenous players
for(int i=0; i<9; i++){
if(!Network::wait_message(StringBuffer::recvbuf,Network::sock))
return false;
sensory.Parse(StringBuffer::recvbuf);
LogMat(LM_Init, "%s", StringBuffer::recvbuf);
}
Skill::action.init_clang();
/********** Initialize Objects ***************/
Agent::Initialize();
/* set the socket back to blocking */
//Network::settoblock(Network::sock->socketfd);
#ifdef WIN32
newsenseinfo_event = CreateEvent(NULL, TRUE, FALSE, NULL);
newfullinfo_event = CreateEvent(NULL, TRUE, FALSE, NULL);
newsightinfo_event = CreateEvent(NULL, TRUE, FALSE, NULL);
newsoundinfo_event = CreateEvent(NULL, TRUE, FALSE, NULL);
#else // _LINUX
newsenseinfo_event.init();
newfullinfo_event.init();
newsightinfo_event.init();
newsoundinfo_event.init();
#endif
/* When receive no msg from server since more than 2000 milliseconds before,
we think that server has quitted*/
#ifdef WIN32
WaitServerTimer = SetTimer(hWND, 1, 10*ServerParam::simulator_step, CheckServer);
#endif
#ifdef WIN32
InitializeCriticalSection(&parse_update_mutex); //initialize mutex
#else // _LINUX
pthread_mutex_init(&parse_update_mutex,NULL);
#endif
/******************** start inf and control process ******************/
#ifdef WIN32
siginf = (HANDLE)_beginthreadex(NULL, 0, InfProcWindows, NULL, 0, NULL);
if(siginf == NULL){
return false;
}
sigctrl = (HANDLE)_beginthreadex(NULL, 0, CtrlProcWindows, NULL, 0, NULL);
if(sigctrl == NULL){
return false;
}
#else // _LINUX
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);
if (pthread_create(&siginf, &attr, InfProc, NULL) != 0){
my_error("create thread error");
return false;
}
if (pthread_create(&sigctrl, &attr, CtrlProc, NULL) != 0){
my_error("create thread error");
return false;
}
#endif
#ifdef WIN32
//enhance the priority of the thread
SetThreadPriority(siginf,THREAD_PRIORITY_TIME_CRITICAL);
SetThreadPriority(sigctrl,THREAD_PRIORITY_HIGHEST);
#else // _LINUX
struct sched_param param;
int policy;
pthread_getschedparam(siginf, &policy, ¶m);
param.sched_priority = sched_get_priority_max(SCHED_RR) - 1;;
pthread_setschedparam(siginf, SCHED_RR, ¶m);
param.sched_priority --;
pthread_setschedparam(sigctrl, SCHED_RR, ¶m);
#endif
stopwatch.TimeEvent(SW_Event_ChangeView);
return true;
}
/* Information process */
void* InfProc(void* ignore){
infthread_exit = false;
while(Network::receive_message(StringBuffer::recvbuf, Network::sock) == 1){
if (!ServerAlive) break;
stopwatch.Setcachetime();//when receive new msg
NoResponseFromServer = 0; // There is response frome server
#ifdef WIN32
EnterCriticalSection(&parse_update_mutex);
#else // _LINUX
pthread_mutex_lock(&parse_update_mutex);
#endif
sensory.Parse(StringBuffer::recvbuf);
#ifdef _LOGMAT
TIME_T t = stopwatch.GetRawData_Cache();
#ifdef WIN32
LogMat(LM_Watch,"%I64d", stopwatch.FormatTime(t));
#else // _LINUX
LogMat(LM_Watch,"%lld", stopwatch.FormatTime(t));
#endif
LogMat(LM_Info, "%s", StringBuffer::recvbuf);
#endif
// Notify the CtrlProc about some events
if(sensory.LastMsgIsSight()){
SetEvent(newsightinfo_event);
if(!situation.ClockStopped){
DoRecord(LOG_STOPWATCH,"%d See Time %.2f sight gap %.2f(%d %d) chview gap %.2f", \
sensory.LatestTime,
stopwatch.MsCheckBetween(SW_CycleStart, SW_Recv_Visualinfo, sensory.LatestTime), \
stopwatch.MsSpanCycle(SW_Recv_Visualinfo, sensory.PrevSightTime, sensory.LastSightTime), \
sensory.PrevSightTime, sensory.LastSightTime, \
stopwatch.MsFromEvent(SW_Event_ChangeView, SW_Recv_Visualinfo, sensory.LastSightTime));
}
}else if(sensory.LastMsgIsSense()){
SetEvent(newsenseinfo_event);//It is a new Cycle
}else if(sensory.LastMsgIsNonemptySound()){
DoRecord(LOG_STOPWATCH, "hear Time %.2f", \
stopwatch.MsCheckBetween(SW_CycleStart, SW_Recv_Soundinfo, sensory.LatestTime));
SetEvent(newsoundinfo_event);
}
#ifdef _Up_FState
else if(sensory.LastMsgIsFull()){
SetEvent(newfullinfo_event);
}
#endif
if (sensory.LatestTime > sensory.PrevInterruptTime ||
(situation.ClockStopped && sensory.LastMsgIsSense())){
ResetEvent(newfullinfo_event);
if (!sensory.LastMsgIsSight()){
ResetEvent(newsightinfo_event);
}
stopwatch.TimeNow(SW_Info_Send_Notify, sensory.LatestTime); // when notify the control process
DoRecord(LOG_STOPWATCH,"Previous Cycle last%f",
stopwatch.MsSpanCycle(SW_CycleStart, sensory.LatestTime));
}
#ifdef WIN32
LeaveCriticalSection(&parse_update_mutex);
#else // _LINUX
pthread_mutex_unlock(&parse_update_mutex);
#endif
}
ServerAlive = 0;
SetEvent(newsenseinfo_event); //inform ctrlproc to exit
infthread_exit = true;
return 0;
}
void* CtrlProc(void* ignore){
ctrlthread_exit = false;
CP_est_max_AIcost *= ServerParam::slow_down_factor;
int logwaitcounts = 0;
int logwaitfails = 0;
bool logwait;
float predictsightime;
int tmp_waittime;
#ifdef WIN32
DWORD waittime;
#else //_LINUX
struct timespec WaitingTime;
#endif
while(1){
#ifdef WIN32
WaitForSingleObject(newsenseinfo_event, INFINITE);// wait for the new cycle
#else // _LINUX
newsenseinfo_event.WaitEvent();
#endif
if (!ServerAlive) break;
#ifdef _Up_FState
if(sensory.HasFullState()){
#ifdef WIN32
WaitForSingleObject(newfullinfo_event, INFINITE);
#else // _LINUX
newfullinfo_event.WaitEvent();
#endif
}
#endif
stopwatch.UpdateCycle(sensory.LatestTime);
stopwatch.TimeNow(SW_Ctrl_Recv_Notify);
stopwatch.Estimate_correction_factor();
if (!situation.ClockStopped && sensory.LatestTime - 1 > situation.LastInterruptTime){
my_error("Miss %d cycles?", sensory.LatestTime - 1 - situation.LastInterruptTime);
DoLog(LOG_MISS, "%d cycles", sensory.LatestTime - 1 - situation.LastInterruptTime);
}
situation.LastInterruptTime = sensory.LatestTime;
//Time control to maximize the possibility of receiving the last visual info.
logwait = false;
if(sensory.LastSightTime < sensory.LatestTime){
//calculate the time length from the start of this cycle to next visual info with result stored in predictsightime
float timelapsed;
if(stopwatch.IsPrior_E(SW_Event_ChangeView, SW_Recv_Visualinfo, sensory.LastSightTime)){
timelapsed = stopwatch.MsBetween(SW_Recv_Visualinfo, sensory.LastSightTime, SW_CycleStart, sensory.LatestTime);
}else{
timelapsed = stopwatch.MsFromEvent(SW_Event_ChangeView, SW_CycleStart, sensory.LatestTime);
}
float sightgap = (float)sensory.MySightInterval();
predictsightime = sightgap - timelapsed;
DoLog(LOG_STOPWATCH, "time elapsed until this cycle%.2f, sight gap%.2f, predict sight time%.2f",
timelapsed, sightgap, predictsightime);
if(predictsightime < (float)ServerParam::simulator_step - CP_est_max_AIcost){
logwaitcounts ++;
tmp_waittime = int((float)ServerParam::simulator_step - CP_est_max_AIcost -
stopwatch.TimeElapsed(SW_CycleStart, sensory.LatestTime));
if(tmp_waittime > CP_min_waitvisualtime){
#ifdef WIN32
waittime = (DWORD)tmp_waittime;
WaitForSingleObject(newsightinfo_event, waittime);
#else // _LINUX
TIME_T t = stopwatch.GetRawData_Channel(SW_CycleStart, sensory.LatestTime);
WaitingTime.tv_sec = t.tv_sec;
WaitingTime.tv_nsec = (t.tv_usec + tmp_waittime * 1000)*1000;
newsightinfo_event.WaitEvent(&WaitingTime);
#endif
logwait = true;
}
}
}else
predictsightime = 0;
if(!logwait && !situation.ClockStopped && ServerParam::version >= 8.0f){
DoRecord("%d wait sound %.0f", sensory.LatestTime, CP_waitsoundtime);
#ifdef WIN32
WaitForSingleObject(newsoundinfo_event, (DWORD)CP_waitsoundtime);
#else // _LINUX
TIME_T t = stopwatch.GetRawData_Channel(SW_CycleStart, sensory.LatestTime);
WaitingTime.tv_sec = t.tv_sec;
WaitingTime.tv_nsec = (t.tv_usec + CP_waitsoundtime * 1000)*1000;
newsoundinfo_event.WaitEvent(&WaitingTime);
#endif
}
stopwatch.TimeNow(SW_Ctrl_Wake);
// Update the inner World
#ifdef WIN32
EnterCriticalSection(&parse_update_mutex);
#else // _LINUX
pthread_mutex_lock(&parse_update_mutex);
#endif
if(logwait){
if(sensory.LastSightTime != sensory.LatestTime){
logwaitfails ++;
DoLog(LOG_STOPWATCH, "wait fail (%d %d)",sensory.LastSightTime, sensory.LatestTime);
}else{
DoLog(LOG_STOPWATCH, "wait successfully",sensory.LastSightTime, sensory.LatestTime);
}
}
ResetEvent(newsenseinfo_event);
ResetEvent(newsoundinfo_event);
stopwatch.TimeNow(SW_Ctrl_UpdateStart);
DoLog(LOG_NONE, "******** Cycle %d **********", sensory.LatestTime);
LogMat(LM_Upd, "Update...");
sensory.Update();
LogMat(LM_Exec, "Exec...");
#ifdef WIN32
LeaveCriticalSection(&parse_update_mutex);
#else // _LINUX
pthread_mutex_unlock(&parse_update_mutex);
#endif
stopwatch.TimeNow(SW_Ctrl_AIStart);
int IsFinished = Agent::behave();
stopwatch.TimeNow(SW_Ctrl_AIExit);
if(!IsFinished)
DoLog(LOG_STOPWATCH, "AI exit at %.2f",stopwatch.MsBetween(SW_CycleStart, SW_Ctrl_AIExit));
else{
}
#ifdef _LOG
//DoLog(LOG_STOPWATCH, "Time elapsed on notification %f", stopwatch.MsBetween(SW_Info_Send_Notify, SW_Ctrl_Recv_Notify));
//DoLog(LOG_STOPWATCH, "Time between notification and wake %f", stopwatch.MsBetween(SW_Info_Send_Notify, SW_Ctrl_Wake));
if(logwait){
DoLog(LOG_STOPWATCH, "Sight Wake Time %.2f (%d)", stopwatch.MsBetween(SW_Ctrl_Recv_Notify, SW_Ctrl_Wake), tmp_waittime);
}
DoLog(LOG_STOPWATCH, "Correction Factor %f", stopwatch.Get_correction_factor());
DoLog(LOG_STOPWATCH, "Predict sight time %.2f(total visual wait fails%d, wait counts%d)", predictsightime, logwaitfails, logwaitcounts);
DoLog(LOG_STOPWATCH, "Update start %.2f", stopwatch.MsCheckBetween(SW_CycleStart, SW_Ctrl_UpdateStart));
//DoLog(LOG_STOPWATCH, "AI start %.2f", stopwatch.MsCheckBetween(SW_CycleStart, SW_Ctrl_AIStart));
DoLog(LOG_STOPWATCH, "AI use %.2f", stopwatch.MsCheckBetween(SW_Ctrl_AIStart, SW_Ctrl_AIExit));
//DoLog(LOG_STOPWATCH, "AI finished at%.2f", stopwatch.MsCheckBetween(SW_CycleStart, SW_Ctrl_AIExit));
#endif
}
ctrlthread_exit = true;
return 0;
}
#ifdef WIN32
unsigned int WINAPI InfProcWindows(void* lpParameter){
//DWORD WINAPI InfProcWindows(LPVOID lpParameter){
InfProc(NULL);
_endthreadex(0);
return 0;
}
/* Control Process */
unsigned int WINAPI CtrlProcWindows(void* plParameter){
CtrlProc(NULL);
_endthreadex(0);
return 0;
}
void CALLBACK CheckServer(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime){
if (NoResponseFromServer){
ServerAlive = 0;
PostMessage(hwnd, WM_DESTROY, 0, 0);
}
NoResponseFromServer = 1;
}
#endif
#ifndef WIN32
bool CheckServer(){
if (NoResponseFromServer){
ServerAlive = 0;
return false;
}
NoResponseFromServer = 1;
return true;
}
#endif
void destruction(){
ServerAlive = 0;
Network::close_connection(Network::sock);
int count = 0;
//wait until both thread exit automatically
while(!ctrlthread_exit || !infthread_exit){
#ifdef WIN32
Sleep(1000); //time for the other two thread to exit.
#else //_LINUX
sleep(1);
#endif
if(count ++ > 3) break;
}
if(Network::sock != NULL) delete Network::sock;
#ifdef WIN32
if (siginf != NULL){
CloseHandle(siginf);
}
if (sigctrl != NULL){
CloseHandle(sigctrl);
}
DeleteCriticalSection(&parse_update_mutex);
if(newsenseinfo_event != NULL) CloseHandle(newsenseinfo_event);
if(newsoundinfo_event != NULL) CloseHandle(newsoundinfo_event);
if(newfullinfo_event != NULL) CloseHandle(newfullinfo_event);
if(newsightinfo_event != NULL) CloseHandle(newsightinfo_event);
if(WaitServerTimer != NULL) KillTimer(hWND, WaitServerTimer);
#else // _LINUX
pthread_mutex_destroy(&parse_update_mutex);
newsenseinfo_event.destroy();
newsoundinfo_event.destroy();
newfullinfo_event.destroy();
newsightinfo_event.destroy();
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -