⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.cpp

📁 2002年
💻 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, &param);
	param.sched_priority = sched_get_priority_max(SCHED_RR) - 1;; 
	pthread_setschedparam(siginf, SCHED_RR, &param);
	param.sched_priority --;
	pthread_setschedparam(sigctrl, SCHED_RR, &param);	
#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 + -