/*********************************************************
函数名称:AddFriend
功能描述:添加好友
参数说明:msg-消息结构体 pSocket-接收到消息的pSocket
返 回 值:
备    注:
*********************************************************/
int CSocketServerDlg::AddFriend(struct MSG_TRANSPOND * msg_addfrd, CChatSocket * pSocket) 
{
	struct MSG_SYS *msg_sys = new struct MSG_SYS;
	msg_sys->nType = IDS_SYSTEM_MESSAGE;

	if(msg_addfrd->nReturn == ADD_FRIEND_AGREE)
	{// 同意好友申请
		int nRes;
		nRes = m_data.MakeFriend(msg_addfrd->FromID, msg_addfrd->ToID);
		if(nRes == TRUE)
		{// 添加成功		
			msg_sys->nIDPrompt = IDS_ADD_FRIEND_SUCCESS;
		}
		else if(nRes == IDS_ERR_FRIEND_ADD_SELF)
		{// 不能添加自己为好友
			msg_sys->nIDPrompt = IDS_ERR_FRIEND_ADD_SELF;			
		}
		else if(nRes == IDS_ERR_FRIEND_HAD_EXIST)
		{// 好友已经存在
			msg_sys->nIDPrompt = IDS_ERR_FRIEND_HAD_EXIST;
		}

		// 分别向双方发送消息
		strcpy_s(msg_sys->nID, pSocket->m_userID);
		pSocket->Send(msg_sys, sizeof(*msg_sys));

		strcpy_s(msg_sys->nID, msg_addfrd->FromID);
		SendSystemMsg(msg_sys); // 在这个函数里面会将msg_sys释放
	}
	else
	{		
		msg_sys->nIDPrompt = IDS_ADD_FRIEND_REFUSE;
		strcpy_s(msg_sys->nID, msg_addfrd->FromID);
		SendSystemMsg(msg_sys); // 在这个函数里面会将msg_sys释放
	}
	return TRUE;
}
BOOL CLibInfoCharSvr::UseSkill(CInfoCharSvr *pInfoChar, DWORD dwSkillID)
{
	BOOL bRet, bResult;
	PCInfoSkillBase pInfoSkill;
	CPacketCHAR_STATUS PacketCHAR_STATUS;

	bRet = FALSE;
	if (pInfoChar == NULL) {
		goto Exit;
	}
	bResult = pInfoChar->HaveSkill (dwSkillID);
	if (bResult == FALSE) {
		goto Exit;
	}
	pInfoSkill = (PCInfoSkillBase)m_pLibInfoSkill->GetPtr (dwSkillID);
	if (pInfoSkill == NULL) {
		goto Exit;
	}
	if (pInfoChar->m_dwSP < pInfoSkill->m_dwSP) {
		SendSystemMsg (pInfoChar->m_dwSessionID, "SPが足りません", SYSTEMMSGTYPE_NOLOG);
		goto Exit;
	}

	switch (pInfoSkill->m_nTypeMain) {
	case SKILLTYPEMAIN_NONE:		/* 能力 */
		break;
	case SKILLTYPEMAIN_BATTLE:		/* 戦闘 */
		switch (pInfoSkill->m_nTypeSub) {
		case SKILLTYPESUB_BATTLE_MOVEATACK:	/* 移動して攻撃 */	bRet = UseSkillBATTLE_MOVEATACK (pInfoChar, pInfoSkill);	break;
		case SKILLTYPESUB_BATTLE_HEAL:		/* 回復 */			bRet = UseSkillNONE_HEAL (pInfoChar, pInfoSkill);			break;
		}
		break;
	case SKILLTYPEMAIN_LIFE:		/* 生活 */
		switch (pInfoSkill->m_nTypeSub) {
		case SKILLTYPESUB_LIFE_FISHING:	/* 釣り */	bRet = UseSkillFISHING (pInfoChar, pInfoSkill);	break;
		}
		break;
	}
	if (bRet) {
		pInfoChar->m_dwSP -= pInfoSkill->m_dwSP;

		PacketCHAR_STATUS.Make (pInfoChar);
		m_pMainFrame->SendToClient (pInfoChar->m_dwSessionID, &PacketCHAR_STATUS);
	}

Exit:
	return bRet;
}
bool CGameServer::Update()
{
	if(lastSyncRequest<gu->gameTime-2){
		lastSyncRequest=gu->gameTime;

		if (game && game->playing) {
			//check if last times sync responses is correct
			if (outstandingSyncFrame > 0) {
				// I've disabled majority voting for now.
				// Should be tested in a few big multiplayer games first.
#if 0
				std::map<CChecksum, int> freq; // maps checksums to their frequency
				for(int a = 0; a < gs->activePlayers; ++a)
					if(gs->players[a]->active) {
						//if the checksum really happens to be 0 we will get lots of falls positives here
						if(!syncResponses[a]) {
							if (!serverNet->playbackDemo)
								logOutput.Print("No response from %s", gs->players[a]->playerName.c_str());
						} else
							++freq[syncResponses[a]];
					}
				if (freq.size() != 1) {
					CChecksum correctSync;
					int highestFreq = 0;
					for (std::map<CChecksum, int>::const_iterator it = freq.begin(); it != freq.end(); ++it)
						if (it->second > highestFreq) {
							correctSync = it->first;
							highestFreq = it->second;
						}
					if (correctSync)
						for (int a = 0; a < gs->activePlayers; ++a)
							if (gs->players[a]->active && syncResponses[a] && correctSync != syncResponses[a]) {
								char buf[10];
								SendSystemMsg("Sync error for %s %i %s",
									gs->players[a]->playerName.c_str(), outstandingSyncFrame, correctSync.diff(buf, syncResponses[a]));
							}
				}
#else
				CChecksum correctSync;
				bool err = false;
				for(int a = 0; a < gs->activePlayers; ++a)
					if(gs->players[a]->active) {
						//if the checksum really happens to be 0 we will get lots of falls positives here
						if(!syncResponses[a] && !serverNet->playbackDemo) {
							logOutput.Print("No response from %s", gs->players[a]->playerName.c_str());
							continue;
						}
						if (correctSync && correctSync != syncResponses[a]) {
							char buf[10];
							SendSystemMsg("Sync error for %s %i %s",
										  gs->players[a]->playerName.c_str(), outstandingSyncFrame, correctSync.diff(buf, syncResponses[a]));
							err = true;
							continue;
						}
						//this assumes the lowest num player is the correct one, should maybe some sort of majority voting instead
						correctSync = syncResponses[a];
					}
#endif
#ifdef SYNCDEBUG
				if (err || fakeDesync) {
					CSyncDebugger::GetInstance()->ServerTriggerSyncErrorHandling(serverframenum);
					fakeDesync = false;
				}
#else // SYNCDEBUG
				if (err && gu->autoQuit)
					serverNet->SendData(NETMSG_QUIT);
#endif // !SYNCDEBUG
			}
			for(int a=0;a<gs->activePlayers;++a)
				syncResponses[a]=0;
			
			if(!serverNet->playbackDemo){
				//send sync request
				serverNet->SendData<int>(NETMSG_SYNCREQUEST, serverframenum);
				outstandingSyncFrame=serverframenum;
			}

			int firstReal=0;
			if(gameSetup)
				firstReal=gameSetup->numDemoPlayers;
			//send info about the players
			for(int a=firstReal;a<gs->activePlayers;++a){
				if(gs->players[a]->active){
					serverNet->SendData<unsigned char, float, int>(
							NETMSG_PLAYERINFO, a, gs->players[a]->cpuUsage, gs->players[a]->ping);
				}
			}

			//decide new internal speed
			float maxCpu=0;
			for(int a=0;a<gs->activePlayers;++a){
				if(gs->players[a]->cpuUsage>maxCpu && gs->players[a]->active){
					maxCpu=gs->players[a]->cpuUsage;
				}
			}

			if (maxCpu != 0) {
				float wantedCpu=0.35f+(1-gs->speedFactor/gs->userSpeedFactor)*0.5f;
				//float speedMod=1+wantedCpu-maxCpu;
				float newSpeed=gs->speedFactor*wantedCpu/maxCpu;
				//logOutput.Print("Speed %f %f %f %f",maxCpu,wantedCpu,speedMod,newSpeed);
				newSpeed=(newSpeed+gs->speedFactor)*0.5f;
				if(newSpeed>gs->userSpeedFactor)
					newSpeed=gs->userSpeedFactor;
				if(newSpeed<0.1f)
					newSpeed=0.1f;
				if(newSpeed!=gs->speedFactor)
					serverNet->SendData<float>(NETMSG_INTERNAL_SPEED, newSpeed);
			}
		}
	}

	if(!ServerReadNet()){
		logOutput.Print("Server read net wanted quit");
		return false;
	}
	if (game && game->playing && !serverNet->playbackDemo){
		Uint64 currentFrame;
		currentFrame = SDL_GetTicks();
		float timeElapsed=((float)(currentFrame - lastframe))/1000.f;
		if(gameEndDetected)
			gameEndTime+=timeElapsed;
//		logOutput.Print("float value is %f",timeElapsed);

		if(gameClientUpdated){
			gameClientUpdated=false;
			maxTimeLeft=2;
		}
		if(timeElapsed>maxTimeLeft)
			timeElapsed=maxTimeLeft;
		maxTimeLeft-=timeElapsed;

		timeLeft+=GAME_SPEED*gs->speedFactor*timeElapsed;
		lastframe=currentFrame;

		while((timeLeft>0) && (!gs->paused || game->bOneStep)){
			if(!game->creatingVideo){
				game->bOneStep=false;
				CreateNewFrame(true);
			}
			timeLeft--;
		}
	}
	serverNet->Update();

	CheckForGameEnd();
	return true;
}
bool CGameServer::ServerReadNet()
{
	static int lastMsg[MAX_PLAYERS],thisMsg=0;

	for(int a=0;a<gs->activePlayers;a++){
		int inbufpos=0;
		int inbuflength=0;
		if(gs->players[a]->active && (!gameSetup || a>=gameSetup->numDemoPlayers)){
			if((inbuflength=serverNet->GetData(inbuf,NETWORK_BUFFER_SIZE,a))==-1){
				PUSH_CODE_MODE;		//this could lead to some nasty errors if the other thread switches code mode...
				ENTER_MIXED;
				gs->players[a]->active=false;
				POP_CODE_MODE;
				inbuflength=0;
				serverNet->SendData<unsigned char, unsigned char>(NETMSG_PLAYERLEFT, a, 0);
			}
		}
		//		logOutput << serverNet->numConnected << "\n";

		while(inbufpos<inbuflength){
			thisMsg=inbuf[inbufpos];
			int lastLength=0;
			switch (inbuf[inbufpos]){

			case NETMSG_ATTEMPTCONNECT: //handled directly in CNet
				lastLength=3;
				break;

			case NETMSG_HELLO: 
				lastLength=1;
				break;

			case NETMSG_RANDSEED: 
				lastLength=5;
				serverNet->SendData(&inbuf[inbufpos],5); //forward data
				break;

			case NETMSG_NEWFRAME: 
				gs->players[a]->ping=serverframenum-*(int*)&inbuf[inbufpos+1];
				lastLength=5;
				break;

			case NETMSG_PAUSE:
				if(inbuf[inbufpos+2]!=a){
					logOutput.Print("Server: Warning got pause msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					assert(game);
					if(game->gamePausable || a==0){
						timeLeft=0;
						serverNet->SendData(&inbuf[inbufpos],3);
					}
				}
				lastLength=3;
				break;

			case NETMSG_INTERNAL_SPEED: 
				logOutput.Print("Server shouldnt get internal speed msgs?");
				lastLength=5;
				break;

			case NETMSG_USER_SPEED: {
				float speed=*((float*)&inbuf[inbufpos+1]);
				assert(game);
				if(speed>game->maxUserSpeed)
					speed=game->maxUserSpeed;
				if(speed<game->minUserSpeed)
					speed=game->minUserSpeed;
				if(gs->userSpeedFactor!=speed){
					if(gs->speedFactor==gs->userSpeedFactor || gs->speedFactor>speed)
						serverNet->SendData<float>(NETMSG_INTERNAL_SPEED, speed);
					serverNet->SendData(&inbuf[inbufpos],5); //forward data
				}
				lastLength=5;
				break;}

			case NETMSG_CPU_USAGE: 
				ENTER_MIXED;
				gs->players[a]->cpuUsage=*((float*)&inbuf[inbufpos+1]);
				ENTER_UNSYNCED;
				lastLength=5;
				break;

			case NETMSG_EXECHECKSUM: 
				if(exeChecksum!=*((unsigned int*)&inbuf[inbufpos+1])){
					SendSystemMsg("Wrong exe checksum from %i got %X instead of %X",a,*((unsigned int*)&inbuf[inbufpos+1]),exeChecksum);
				}
				lastLength=5;
				break;

			case NETMSG_QUIT:
				ENTER_MIXED;
				gs->players[a]->active=false;
				ENTER_UNSYNCED;
				serverNet->connections[a].active=false;
				serverNet->SendData<unsigned char, unsigned char>(NETMSG_PLAYERLEFT, a, 1);
				lastLength=1;
				break;

			case NETMSG_PLAYERNAME:
				if(inbuf[inbufpos+2]!=a && a!=0){
					SendSystemMsg("Server: Warning got playername msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					ENTER_MIXED;
					gs->players[inbuf[inbufpos+2]]->playerName=(char*)(&inbuf[inbufpos+3]);
					gs->players[inbuf[inbufpos+2]]->readyToStart=true;
					gs->players[inbuf[inbufpos+2]]->active=true;
					ENTER_UNSYNCED;

					SendSystemMsg("Player %s joined as %i",&inbuf[inbufpos+3],inbuf[inbufpos+2]);
					serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				}
				lastLength=inbuf[inbufpos+1];
				break;

			case NETMSG_CHAT:
				if(inbuf[inbufpos+2]!=a){
					SendSystemMsg("Server: Warning got chat msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				}
				lastLength=inbuf[inbufpos+1];
				break;

			case NETMSG_SYSTEMMSG:
				if(inbuf[inbufpos+2]!=a){
					logOutput.Print("Server: Warning got system msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				}
				lastLength=inbuf[inbufpos+1];	
				break;

			case NETMSG_STARTPOS:
				if(inbuf[inbufpos+1]!=gs->players[a]->team && a!=0){
					SendSystemMsg("Server: Warning got select msg from %i claiming to be from team %i",a,inbuf[inbufpos+1]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],15); //forward data
				}
				lastLength=15;
				break;

			case NETMSG_COMMAND:
				if(inbuf[inbufpos+3]!=a){
					SendSystemMsg("Server: Warning got command msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
				}
				lastLength=*((short int*)&inbuf[inbufpos+1]);
				break;

			case NETMSG_SELECT:
				if(inbuf[inbufpos+3]!=a){
					SendSystemMsg("Server: Warning got select msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
				}
				lastLength=*((short int*)&inbuf[inbufpos+1]);
				break;

			case NETMSG_AICOMMAND:
				if(inbuf[inbufpos+3]!=a){
					SendSystemMsg("Server: Warning got aicommand msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
				}
				lastLength=*((short int*)&inbuf[inbufpos+1]);
				break;

			case NETMSG_SYNCRESPONSE:{
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got syncresponse msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo){
						int frame = *(int*)&inbuf[inbufpos+2];
						if(outstandingSyncFrame == frame)
							syncResponses[inbuf[inbufpos+1]] = *(CChecksum*)&inbuf[inbufpos+6];
						else
							logOutput.Print("Delayed respone from %s (%i instead of %i)",
										  gs->players[inbuf[inbufpos+1]]->playerName.c_str(), frame, outstandingSyncFrame);
					}
				}
				lastLength=6+sizeof(CChecksum);}
				break;

			case NETMSG_SHARE:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got share msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],12); //forward data
				}
				lastLength=12;
				break;

			case NETMSG_SETSHARE:
				if(inbuf[inbufpos+1]!=gs->players[a]->team){
					SendSystemMsg("Server: Warning got setshare msg from player %i claiming to be from team %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],10); //forward data
				}
				lastLength=10;
				break;

			case NETMSG_PLAYERSTAT:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got stat msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],sizeof(CPlayer::Statistics)+2); //forward data
				}
				lastLength=sizeof(CPlayer::Statistics)+2;
				break;

			case NETMSG_MAPDRAW:
				serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				lastLength=inbuf[inbufpos+1];
				break;

#ifdef DIRECT_CONTROL_ALLOWED
			case NETMSG_DIRECT_CONTROL:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got direct control msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],2); //forward data
				}
				lastLength=2;
				break;

			case NETMSG_DC_UPDATE:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got dc update msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],7); //forward data
				}
				lastLength=7;
				break;
#endif
			default:
#ifdef SYNCDEBUG
				// maybe something for the sync debugger?
				lastLength = CSyncDebugger::GetInstance()->ServerReceived(&inbuf[inbufpos]);
				if (!lastLength)
#endif
				{
					logOutput.Print("Unknown net msg in server %d from %d pos %d last %d", (int)inbuf[inbufpos], a, inbufpos, lastMsg[a]);
					lastLength=1;
				}
				break;
			}
			if(lastLength<=0){
				logOutput.Print("Server readnet got packet type %i length %i pos %i from %i??",thisMsg,lastLength,inbufpos,a);
				lastLength=1;
			}
			inbufpos+=lastLength;
			lastMsg[a]=thisMsg;
		}
		if(inbufpos!=inbuflength){
			char txt[200];
			sprintf(txt,"Wrong packet length got %d from %d instead of %d",inbufpos,a,inbuflength);
			logOutput.Print(txt);
			handleerror(0,txt,"Server network error",0);
		}
	}
#ifdef SYNCDEBUG
	CSyncDebugger::GetInstance()->ServerHandlePendingBlockRequests();
#endif
	return true;
}
bool CGameServer::HandleSyncResponses()
{
	//check if last times sync responses is correct
	if (outstandingSyncFrame > 0 && !serverNet->playbackDemo) {
		CChecksum correctSync;
		for(int a = 0; a < gs->activePlayers; ++a) {
			if(gs->players[a]->active) {
				switch (syncResponseState[a]) {
					case SRS_WAITING:
						break;
					case SRS_TBH: // To Be Handled
						if (correctSync) {
							if (correctSync != syncResponses[a]) {
								char buf[10];
								SendSystemMsg("Sync error for %s %i %s",
										gs->players[a]->playerName.c_str(), outstandingSyncFrame, correctSync.diff(buf, syncResponses[a]));
								if (outstandingChecksumFrame <= 0 && (correctSync.x != syncResponses[a].x || correctSync.y != syncResponses[a].y || correctSync.z != syncResponses[a].z)) {
									// try to resync by sending out a CHECKSUMREQUEST (only on XYZ sync errors)
									serverNet->SendData<int>(NETMSG_CHECKSUMREQUEST, serverframenum);
									outstandingChecksumFrame = serverframenum;
									lastChecksumRequest = gu->gameTime;
									for (int b = 0; b < gs->activePlayers; ++b)
										checksumResponses[b].resize(1, 0xFFFF);
								}
								syncResponseState[a] = SRS_WRONG;
							} else
								syncResponseState[a] = SRS_RIGHT;
						} else {
							//this assumes the lowest num player is the correct one, should maybe some sort of majority voting instead
							correctSync = syncResponses[a];
							syncResponseState[a] = SRS_RIGHT;
						}
						break;
					case SRS_WRONG:
						break;
					case SRS_RIGHT:
						correctSync = syncResponses[a];
						break;
				}
			}
		}
	}

	// Every 2 seconds, reset the sync repsonses and push a new SYCNREQUEST out.
	if(lastSyncRequest < gu->gameTime - 2){
		lastSyncRequest = gu->gameTime;

		if (outstandingSyncFrame > 0) {
			for (int a = 0; a < gs->activePlayers; ++a) {
				if (gs->players[a]->active) {
					if (syncResponseState[a] == SRS_WAITING)
						info->AddLine("No sync response from %s", gs->players[a]->playerName.c_str());
				}
			}
			outstandingSyncFrame = -1;
		}
		// wait with pushing a new syncrequest until all resync is finished.
		if (!serverNet->playbackDemo && outstandingChecksumFrame <= 0) {
			// reset
			for (int a = 0; a < gs->activePlayers; ++a) {
				syncResponses[a] = 0;
				syncResponseState[a] = SRS_WAITING;
			}
			//send sync request
			serverNet->SendData<int>(NETMSG_SYNCREQUEST, serverframenum);
			outstandingSyncFrame = serverframenum;
		}
		return true;
	}
	return false;
}
bool CGameServer::ServerReadNet()
{
	static int lastMsg[MAX_PLAYERS],thisMsg=0;

	for(int a=0;a<gs->activePlayers;a++){
		int inbufpos=0;
		int inbuflength=0;
		if(gs->players[a]->active && (!gameSetup || a>=gameSetup->numDemoPlayers)){
			if((inbuflength=serverNet->GetData(inbuf,NETWORK_BUFFER_SIZE,a))==-1){
				PUSH_CODE_MODE;		//this could lead to some nasty errors if the other thread switches code mode...
				ENTER_MIXED;
				gs->players[a]->active=false;
				POP_CODE_MODE;
				inbuflength=0;
				serverNet->SendData<unsigned char, unsigned char>(NETMSG_PLAYERLEFT, a, 0);
			}
		}
		//		(*info) << serverNet->numConnected << "\n";

		while(inbufpos<inbuflength){
			thisMsg=inbuf[inbufpos];
			int lastLength=0;
			switch (inbuf[inbufpos]){

			case NETMSG_ATTEMPTCONNECT: //handled directly in CNet
				lastLength=3;
				break;

			case NETMSG_HELLO: 
				lastLength=1;
				break;

			case NETMSG_RANDSEED: 
				lastLength=5;
				serverNet->SendData(&inbuf[inbufpos],5); //forward data
				break;

			case NETMSG_NEWFRAME: 
				gs->players[a]->ping=serverframenum-*(int*)&inbuf[inbufpos+1];
				lastLength=5;
				break;

			case NETMSG_PAUSE:
				if(inbuf[inbufpos+2]!=a){
					info->AddLine("Server: Warning got pause msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					if(game->gamePausable || a==0){
						timeLeft=0;
						serverNet->SendData(&inbuf[inbufpos],3);
					}
				}
				lastLength=3;
				break;

			case NETMSG_INTERNAL_SPEED: 
				info->AddLine("Server shouldnt get internal speed msgs?");
				lastLength=5;
				break;

			case NETMSG_USER_SPEED: {
				float speed=*((float*)&inbuf[inbufpos+1]);
				if(speed>game->maxUserSpeed)
					speed=game->maxUserSpeed;
				if(speed<game->minUserSpeed)
					speed=game->minUserSpeed;
				if(gs->userSpeedFactor!=speed){
					if(gs->speedFactor==gs->userSpeedFactor || gs->speedFactor>speed)
						serverNet->SendData<float>(NETMSG_INTERNAL_SPEED, speed);
					serverNet->SendData(&inbuf[inbufpos],5); //forward data
				}
				lastLength=5;
				break;}

			case NETMSG_CPU_USAGE: 
				ENTER_MIXED;
				gs->players[a]->cpuUsage=*((float*)&inbuf[inbufpos+1]);
				ENTER_UNSYNCED;
				lastLength=5;
				break;

			case NETMSG_EXECHECKSUM: 
				if(exeChecksum!=*((unsigned int*)&inbuf[inbufpos+1])){
					SendSystemMsg("Wrong exe checksum from %i got %X instead of %X",a,*((unsigned int*)&inbuf[inbufpos+1]),exeChecksum);
				}
				lastLength=5;
				break;

			case NETMSG_MAPNAME:
				if(inbuf[inbufpos+1])
					lastLength=inbuf[inbufpos+1];
				break;

			case NETMSG_QUIT:
				ENTER_MIXED;
				gs->players[a]->active=false;
				ENTER_UNSYNCED;
				serverNet->connections[a].active=false;
				serverNet->SendData<unsigned char, unsigned char>(NETMSG_PLAYERLEFT, a, 1);
				lastLength=1;
				break;

			case NETMSG_PLAYERNAME:
				if(inbuf[inbufpos+2]!=a && a!=0){
					SendSystemMsg("Server: Warning got playername msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					ENTER_MIXED;
					gs->players[inbuf[inbufpos+2]]->playerName=(char*)(&inbuf[inbufpos+3]);
					gs->players[inbuf[inbufpos+2]]->readyToStart=true;
					gs->players[inbuf[inbufpos+2]]->active=true;
					ENTER_UNSYNCED;

					SendSystemMsg("Player %s joined as %i",&inbuf[inbufpos+3],inbuf[inbufpos+2]);
					serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				}
				lastLength=inbuf[inbufpos+1];
				break;

			case NETMSG_CHAT:
				if(inbuf[inbufpos+2]!=a){
					SendSystemMsg("Server: Warning got chat msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				}
				lastLength=inbuf[inbufpos+1];
				break;

			case NETMSG_SYSTEMMSG:
				if(inbuf[inbufpos+2]!=a){
					info->AddLine("Server: Warning got system msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				}
				lastLength=inbuf[inbufpos+1];	
				break;

			case NETMSG_STARTPOS:
				if(inbuf[inbufpos+1]!=gs->players[a]->team && a!=0){
					SendSystemMsg("Server: Warning got select msg from %i claiming to be from team %i",a,inbuf[inbufpos+1]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],15); //forward data
				}
				lastLength=15;
				break;

			case NETMSG_COMMAND:
				if(inbuf[inbufpos+3]!=a){
					SendSystemMsg("Server: Warning got command msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
				}
				lastLength=*((short int*)&inbuf[inbufpos+1]);
				break;

			case NETMSG_SELECT:
				if(inbuf[inbufpos+3]!=a){
					SendSystemMsg("Server: Warning got select msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
				}
				lastLength=*((short int*)&inbuf[inbufpos+1]);
				break;

			case NETMSG_AICOMMAND:
				if(inbuf[inbufpos+3]!=a){
					SendSystemMsg("Server: Warning got aicommand msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
				}
				lastLength=*((short int*)&inbuf[inbufpos+1]);
				break;

			case NETMSG_SYNCRESPONSE:{
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got syncresponse msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo){
						int frame = *(int*)&inbuf[inbufpos+2];
						if(outstandingSyncFrame == frame) {
							syncResponses[inbuf[inbufpos+1]] = *(CChecksum*)&inbuf[inbufpos+6];
							syncResponseState[inbuf[inbufpos+1]] = SRS_TBH;
						} else
							info->AddLine("Delayed sync respone from %s (%i instead of %i)",
										  gs->players[inbuf[inbufpos+1]]->playerName.c_str(), frame, outstandingSyncFrame);
					}
				}
				lastLength=6+sizeof(CChecksum);}
				break;

			case NETMSG_SHARE:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got share msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],12); //forward data
				}
				lastLength=12;
				break;

			case NETMSG_SETSHARE:
				if(inbuf[inbufpos+1]!=gs->players[a]->team){
					SendSystemMsg("Server: Warning got setshare msg from player %i claiming to be from team %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],10); //forward data
				}
				lastLength=10;
				break;

			case NETMSG_PLAYERSTAT:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got stat msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					serverNet->SendData(&inbuf[inbufpos],sizeof(CPlayer::Statistics)+2); //forward data
				}
				lastLength=sizeof(CPlayer::Statistics)+2;
				break;

			case NETMSG_MAPDRAW:
				serverNet->SendData(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
				lastLength=inbuf[inbufpos+1];
				break;

#ifdef DIRECT_CONTROL_ALLOWED
			case NETMSG_DIRECT_CONTROL:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got direct control msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],2); //forward data
				}
				lastLength=2;
				break;

			case NETMSG_DC_UPDATE:
				if(inbuf[inbufpos+1]!=a){
					SendSystemMsg("Server: Warning got dc update msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo)
						serverNet->SendData(&inbuf[inbufpos],7); //forward data
				}
				lastLength=7;
				break;
#endif
			case NETMSG_CHECKSUMRESPONSE:
				/*
					unsigned char NETMSG_CHECKSUMRESPONSE @0
					short int     size                    @1
					unsigned char myPlayerNum             @3
					int           frameNum                @4
					std::vector<unsigned short>           @8
				*/
				if(inbuf[inbufpos+3]!=a){
					SendSystemMsg("Server: Warning got checksum response msg from %i claiming to be from %i", a, inbuf[inbufpos+1]);
				} else {
					if(!serverNet->playbackDemo){
						int player = inbuf[inbufpos+3];
						int frame = *(int*)&inbuf[inbufpos+4];
						if(outstandingChecksumFrame == frame) {
							int numelem = (*((short int*)&inbuf[inbufpos+1]) - 8) / sizeof(short);
							const unsigned short* begin = (unsigned short*)&inbuf[inbufpos+8];
							const unsigned short* end = begin + numelem;
							checksumResponses[player].resize(numelem);
							std::copy(begin, end, checksumResponses[player].begin());
						} else
							info->AddLine("Delayed checksum respone from %s (%i instead of %i)",
										  gs->players[player]->playerName.c_str(), frame, outstandingChecksumFrame);
					}
				}
				lastLength=*((short int*)&inbuf[inbufpos+1]);
				assert(lastLength > 0);
				break;

			case NETMSG_RESYNCRESPONSE: {
				/*
					unsigned char NETMSG_RESYNCRESPONSE   @0
					int           frameNum                @1
					CResyncUnit   unit data               @5
				*/
				int* frame = (int*)&inbuf[inbufpos+1];
				// Adjust frame to the right value.
				*frame = serverframenum;
				lastLength=5+sizeof(CResyncUnit);}
				if(!serverNet->playbackDemo)
					serverNet->SendData(&inbuf[inbufpos],lastLength); //forward data to everyone
				break;

			default:
				char txt[200];
				sprintf(txt,"Unknown net msg in server %d from %d pos %d last %d",(int)inbuf[inbufpos],a,inbufpos,lastMsg[a]);
				info->AddLine(txt);
				//handleerror(0,txt,"Network error",0);
				lastLength=1;
				break;
			}
			if(lastLength<=0){
				info->AddLine("Server readnet got packet type %i length %i pos %i from %i??",thisMsg,lastLength,inbufpos,a);
				lastLength=1;
			}
			inbufpos+=lastLength;
			lastMsg[a]=thisMsg;
		}
		if(inbufpos!=inbuflength){
			char txt[200];
			sprintf(txt,"Wrong packet length got %d from %d instead of %d",inbufpos,a,inbuflength);
			info->AddLine(txt);
			handleerror(0,txt,"Server network error",0);
		}
	}
	return true;
}
void CGameServer::CheckSync()
{
#ifdef SYNCCHECK
	// Check sync
	std::deque<int>::iterator f = outstandingSyncFrames.begin();
	while (f != outstandingSyncFrames.end()) {
		//maps incorrect checksum to players with that checksum
		std::map<unsigned, std::vector<int> > desyncGroups;
		bool bComplete = true;
		bool bGotCorrectChecksum = false;
		unsigned correctChecksum = 0;
		for (int a = 0; a < MAX_PLAYERS; ++a) {
			if (!gs->players[a]->active)
				continue;
			std::map<int, unsigned>::iterator it = syncResponse[a].find(*f);
			if (it == syncResponse[a].end()) {
				if (*f >= serverframenum - SYNCCHECK_TIMEOUT)
					bComplete = false;
				else
					logOutput.Print("No sync response from %s for frame %d", gs->players[a]->playerName.c_str(), *f);
			} else {
				if (!bGotCorrectChecksum) {
					bGotCorrectChecksum = true;
					correctChecksum = it->second;
				} else if (it->second != correctChecksum) {
					desyncGroups[it->second].push_back(a);
				}
			}
		}

		// If anything's in it, we have a desync.
		// TODO take care of !bComplete case?
		// Should we start resync then immediately or wait for the missing packets (while paused)?
		if (bComplete && !desyncGroups.empty()) {
			if (!syncErrorFrame || (*f - syncErrorFrame > SYNCCHECK_MSG_TIMEOUT)) {
				syncErrorFrame = *f;

				// TODO enable this when we have resync
				//serverNet->SendData<unsigned char, unsigned char>(NETMSG_PAUSE, gu->myPlayerNum, true);

				//For each group, output a message with list of playernames in it.
				// TODO this should be linked to the resync system so it can roundrobin
				// the resync checksum request packets to multiple clients in the same group.
				std::map<unsigned, std::vector<int> >::const_iterator g = desyncGroups.begin();
				for (; g != desyncGroups.end(); ++g) {
					std::string players;
					std::vector<int>::const_iterator p = g->second.begin();
					for (; p != g->second.end(); ++p) {
						if (!players.empty())
							players += ", ";
						players += gs->players[*p]->playerName;
					}
					SendSystemMsg("Sync error for %s in frame %d (0x%X)", players.c_str(), *f, g->first ^ correctChecksum);
				}
			}
		}

		// Remove complete sets (for which all player's checksums have been received).
		if (bComplete) {
// 			if (*f >= serverframenum - SYNCCHECK_TIMEOUT)
// 				logOutput.Print("Succesfully purged outstanding sync frame %d from the deque", *f);
			for (int a = 0; a < MAX_PLAYERS; ++a) {
				if (gs->players[a]->active)
					syncResponse[a].erase(*f);
			}
			f = outstandingSyncFrames.erase(f);
		} else
			++f;
	}
#else
	// Make it clear this build isn't suitable for release.
	if (!syncErrorFrame || (serverframenum - syncErrorFrame > SYNCCHECK_MSG_TIMEOUT)) {
		syncErrorFrame = serverframenum;
		SendSystemMsg("Warning: Sync checking disabled!");
	}
#endif
}
bool CGameServer::Update(void)
{
	if(lastSyncRequest<gu->gameTime-2){
		lastSyncRequest=gu->gameTime;

		if(game->playing){
			//check if last times sync responses is correct
			if(outstandingSyncFrame>0){
				int correctSync=0;
				for(int a=0;a<MAX_PLAYERS;++a){
					if(gs->players[a]->active){
						if(!syncResponses[a] && !serverNet->playbackDemo){		//if the checksum really happens to be 0 we will get lots of falls positives here
							info->AddLine("No sync response from %s",gs->players[a]->playerName.c_str());
							continue;
						}
						if(correctSync && correctSync!=syncResponses[a]){
							SendSystemMsg("Sync error for %s %i %X %X",gs->players[a]->playerName.c_str(),outstandingSyncFrame,correctSync,syncResponses[a]);
							continue;
						}
						correctSync=syncResponses[a];		//this assumes the lowest num player is the correct one, should maybe use some sort of majority voting instead
					}
				}
			}
			for(int a=0;a<MAX_PLAYERS;++a)
				syncResponses[a]=0;
			
			if(!serverNet->playbackDemo){
				//send sync request
				outbuf[0]=NETMSG_SYNCREQUEST;
				(*((int*)&outbuf[1]))=serverframenum;
				serverNet->SendData(outbuf,5);
				outstandingSyncFrame=serverframenum;
			}

			int firstReal=0;
			if(gameSetup)
				firstReal=gameSetup->numDemoPlayers;
			//send info about the players
			for(int a=firstReal;a<MAX_PLAYERS;++a){
				if(gs->players[a]->active){
					outbuf[0]=NETMSG_PLAYERINFO;
					outbuf[1]=a;
					*(float*)&outbuf[2]=gs->players[a]->cpuUsage;
					*(int*)&outbuf[6]=gs->players[a]->ping;
					serverNet->SendData(outbuf,10);
				}
			}

			//decide new internal speed
			float maxCpu=0;
			for(int a=0;a<MAX_PLAYERS;++a){
				if(gs->players[a]->cpuUsage>maxCpu && gs->players[a]->active){
					maxCpu=gs->players[a]->cpuUsage;
				}
			}

			float wantedCpu=0.35+(1-gs->speedFactor/gs->userSpeedFactor)*0.5;
			//float speedMod=1+wantedCpu-maxCpu;
			float newSpeed=gs->speedFactor*wantedCpu/maxCpu;
			//info->AddLine("Speed %f %f %f %f",maxCpu,wantedCpu,speedMod,newSpeed);
			newSpeed=(newSpeed+gs->speedFactor)*0.5;
			if(newSpeed>gs->userSpeedFactor)
				newSpeed=gs->userSpeedFactor;
			if(newSpeed<0.1)
				newSpeed=0.1;
			if(newSpeed!=gs->speedFactor){
				outbuf[0]=NETMSG_INTERNAL_SPEED;
				*((float*)&outbuf[1])=newSpeed;
				serverNet->SendData(outbuf,5);
			}
		}
	}

	if(!ServerReadNet()){
		info->AddLine("Server read net wanted quit");
		return false;
	}
	if (game->playing && !serverNet->playbackDemo){
		LARGE_INTEGER currentFrame;
		QueryPerformanceCounter(&currentFrame);
		
		double timeElapsed=((double)(currentFrame.QuadPart - lastframe.QuadPart))/timeSpeed.QuadPart;
		if(gameEndDetected)
			gameEndTime+=timeElapsed;
//		info->AddLine("float value is %f",timeElapsed);

		if(gameClientUpdated){
			gameClientUpdated=false;
			maxTimeLeft=2;
		}
		if(timeElapsed>maxTimeLeft)
			timeElapsed=maxTimeLeft;
		maxTimeLeft-=timeElapsed;

		timeLeft+=GAME_SPEED*gs->speedFactor*timeElapsed;
		lastframe=currentFrame;
		
		while((timeLeft>0) && (!gs->paused || game->bOneStep)){
			if(!game->creatingVideo){
				game->bOneStep=false;
				CreateNewFrame(true);
			}
			timeLeft--;
		}
	}
	serverNet->Update();

	CheckForGameEnd();
	return true;
}
bool CGameServer::ServerReadNet()
{
    static int lastMsg[MAX_PLAYERS],thisMsg=0;

    for(int a=0; a<gs->activePlayers; a++) {
        int inbufpos=0;
        int inbuflength=0;
        if (gs->players[a]->active &&
                ((!net->localDemoPlayback && (!gameSetup || a>=gameSetup->numDemoPlayers)) ||
                 (net->localDemoPlayback && a == (gameSetup ? gameSetup->myPlayer : 0) ))) {
            if((inbuflength=serverNet->GetData(inbuf,netcode::NETWORK_BUFFER_SIZE,a))==-1) {
                PUSH_CODE_MODE;		//this could lead to some nasty errors if the other thread switches code mode...
                ENTER_MIXED;
                gs->players[a]->active=false;
                POP_CODE_MODE;
                inbuflength=0;
                serverNet->SendPlayerLeft(a, 0);
            }
        }

        // dont bother handling anything if we are just sending a demo to
        // localhost, this would result in double chat messages and server warnings..
        if (net->localDemoPlayback)
            continue;

        //		logOutput << serverNet->numConnected << "\n";

        while(inbufpos<inbuflength) {
            thisMsg=inbuf[inbufpos];
            int lastLength=0;
            // TODO rearrange this in order of importance (most used to the front)
            switch (inbuf[inbufpos]) {

            case NETMSG_HELLO:
                lastLength=1;
                break;

            case NETMSG_ATTEMPTCONNECT: //handled directly in CNet
                lastLength=3;
                break;

            case NETMSG_RANDSEED:
                lastLength=5;
                serverNet->SendRandSeed(inbuf[inbufpos+1]); //forward data
                break;

            case NETMSG_NEWFRAME:
                gs->players[a]->ping=serverframenum-*(int*)&inbuf[inbufpos+1];
                lastLength=5;
                break;

            case NETMSG_PAUSE:
                if(inbuf[inbufpos+1]!=a) {
                    logOutput.Print("Server: Warning got pause msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
                } else {
                    if (!inbuf[inbufpos+2])  // reset sync checker
                        syncErrorFrame = 0;
                    assert(game);
                    if(game->gamePausable || a==0) {
                        timeLeft=0;
                        serverNet->SendPause(inbuf[inbufpos+1],inbuf[inbufpos+2]);
                    }
                }
                lastLength=3;
                break;

            case NETMSG_INTERNAL_SPEED:
                logOutput.Print("Server shouldnt get internal speed msgs?");
                lastLength=5;
                break;

            case NETMSG_USER_SPEED: {
                float speed=*((float*)&inbuf[inbufpos+1]);
                assert(game);
                if(speed>game->maxUserSpeed)
                    speed=game->maxUserSpeed;
                if(speed<game->minUserSpeed)
                    speed=game->minUserSpeed;
                if(gs->userSpeedFactor!=speed) {
                    if(gs->speedFactor==gs->userSpeedFactor || gs->speedFactor>speed)
                        serverNet->SendInternalSpeed(speed);
                    serverNet->SendUserSpeed(speed); //forward data
                }
                lastLength=5;
                break;
            }

            case NETMSG_CPU_USAGE:
                ENTER_MIXED;
                gs->players[a]->cpuUsage=*((float*)&inbuf[inbufpos+1]);
                ENTER_UNSYNCED;
                lastLength=5;
                break;

            case NETMSG_QUIT:
                ENTER_MIXED;
                gs->players[a]->active=false;
                ENTER_UNSYNCED;
                serverNet->connections[a]->active=false;
                serverNet->SendPlayerLeft(a, 1);
                lastLength=1;
                break;

            case NETMSG_PLAYERNAME: {
                unsigned char playerNum = inbuf[inbufpos+2];
                if(playerNum!=a && a!=0) {
                    SendSystemMsg("Server: Warning got playername msg from %i claiming to be from %i",a,playerNum);
                } else {
                    ENTER_MIXED;
                    gs->players[playerNum]->playerName=(char*)(&inbuf[inbufpos+3]);
                    gs->players[playerNum]->readyToStart=true;
                    gs->players[playerNum]->active=true;
                    ENTER_UNSYNCED;

                    SendSystemMsg("Player %s joined as %i",&inbuf[inbufpos+3],playerNum);
                    serverNet->SendPlayerName(playerNum,gs->players[playerNum]->playerName);
                }
                lastLength=inbuf[inbufpos+1];
                break;
            }

            case NETMSG_CHAT:
                if(inbuf[inbufpos+2]!=a) {
                    SendSystemMsg("Server: Warning got chat msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
                } else {
                    serverNet->SendChat(inbuf[inbufpos+2], (char*)(&inbuf[inbufpos+3]));
                }
                lastLength=inbuf[inbufpos+1];
                break;

            case NETMSG_SYSTEMMSG:
                if(inbuf[inbufpos+2]!=a) {
                    logOutput.Print("Server: Warning got system msg from %i claiming to be from %i",a,inbuf[inbufpos+2]);
                } else {
                    serverNet->SendSystemMessage(inbuf[inbufpos+2], (char*)(&inbuf[inbufpos+3]));
                }
                lastLength=inbuf[inbufpos+1];
                break;

            case NETMSG_STARTPOS:
                if(inbuf[inbufpos+1]!=gs->players[a]->team && a!=0) {
                    SendSystemMsg("Server: Warning got startpos msg from %i claiming to be from team %i",a,inbuf[inbufpos+1]);
                } else {
                    serverNet->SendStartPos(inbuf[inbufpos+1],inbuf[inbufpos+2], *((float*)&inbuf[inbufpos+3]), *((float*)&inbuf[inbufpos+7]), *((float*)&inbuf[inbufpos+11])); //forward data
                }
                lastLength=15;
                break;

            case NETMSG_COMMAND:
                if(inbuf[inbufpos+3]!=a) {
                    SendSystemMsg("Server: Warning got command msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
                } else {
                    if(!serverNet->IsDemoServer())
                        serverNet->RawSend(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
                }
                lastLength=*((short int*)&inbuf[inbufpos+1]);
                break;

            case NETMSG_SELECT:
                if(inbuf[inbufpos+3]!=a) {
                    SendSystemMsg("Server: Warning got select msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
                } else {
                    if(!serverNet->IsDemoServer())
                        serverNet->RawSend(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
                }
                lastLength=*((short int*)&inbuf[inbufpos+1]);
                break;

            case NETMSG_AICOMMAND:
                if(inbuf[inbufpos+3]!=a) {
                    SendSystemMsg("Server: Warning got aicommand msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
                }
                else if (gs->noHelperAIs) {
                    SendSystemMsg("Server: Player %i is using a helper AI illegally", a);
                }
                else if(!serverNet->IsDemoServer()) {
                    serverNet->RawSend(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
                }
                lastLength=*((short int*)&inbuf[inbufpos+1]);
                break;

            case NETMSG_AICOMMANDS:
                if(inbuf[inbufpos+3]!=a) {
                    SendSystemMsg("Server: Warning got aicommands msg from %i claiming to be from %i",a,inbuf[inbufpos+3]);
                }
                else if (gs->noHelperAIs) {
                    SendSystemMsg("Server: Player %i is using a helper AI illegally", a);
                }
                else if(!serverNet->IsDemoServer()) {
                    serverNet->RawSend(&inbuf[inbufpos],*((short int*)&inbuf[inbufpos+1])); //forward data
                }
                lastLength=*((short int*)&inbuf[inbufpos+1]);
                break;

            case NETMSG_SYNCRESPONSE:
#ifdef SYNCCHECK
                if(inbuf[inbufpos+1]!=a) {
                    SendSystemMsg("Server: Warning got syncresponse msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
                } else {
                    if(!serverNet->IsDemoServer()) {
                        int frameNum = *(int*)&inbuf[inbufpos+2];
                        if (outstandingSyncFrames.empty() || frameNum >= outstandingSyncFrames.front())
                            syncResponse[a][frameNum] = *(unsigned*)&inbuf[inbufpos+6];
                        else if (serverframenum - delayedSyncResponseFrame > SYNCCHECK_MSG_TIMEOUT) {
                            delayedSyncResponseFrame = serverframenum;
                            logOutput.Print("Delayed respone from %s for frame %d (current %d)",
                                            gs->players[a]->playerName.c_str(), frameNum, serverframenum);
                        }
                    }
                }
#endif
                lastLength=10;
                break;

            case NETMSG_SHARE:
                if(inbuf[inbufpos+1]!=a) {
                    SendSystemMsg("Server: Warning got share msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
                } else {
                    if(!serverNet->IsDemoServer())
                        serverNet->SendShare(inbuf[inbufpos+1], inbuf[inbufpos+2], inbuf[inbufpos+3], *((float*)&inbuf[inbufpos+4]), *((float*)&inbuf[inbufpos+8]));
                }
                lastLength=12;
                break;

            case NETMSG_SETSHARE:
                if(inbuf[inbufpos+1]!=gs->players[a]->team) {
                    SendSystemMsg("Server: Warning got setshare msg from player %i claiming to be from team %i",a,inbuf[inbufpos+1]);
                } else {
                    if(!serverNet->IsDemoServer())
                        serverNet->SendSetShare(inbuf[inbufpos+1], *((float*)&inbuf[inbufpos+2]), *((float*)&inbuf[inbufpos+6]));
                }
                lastLength=10;
                break;

            case NETMSG_PLAYERSTAT:
                if(inbuf[inbufpos+1]!=a) {
                    SendSystemMsg("Server: Warning got stat msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
                } else {
                    serverNet->RawSend(&inbuf[inbufpos],sizeof(CPlayer::Statistics)+2); //forward data
                }
                lastLength=sizeof(CPlayer::Statistics)+2;
                break;

            case NETMSG_MAPDRAW:
                serverNet->RawSend(&inbuf[inbufpos],inbuf[inbufpos+1]); //forward data
                lastLength=inbuf[inbufpos+1];
                break;

#ifdef DIRECT_CONTROL_ALLOWED
            case NETMSG_DIRECT_CONTROL:
                if(inbuf[inbufpos+1]!=a) {
                    SendSystemMsg("Server: Warning got direct control msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
                } else {
                    if(!serverNet->IsDemoServer())
                        serverNet->SendDirectControl(inbuf[inbufpos+1]);
                }
                lastLength=2;
                break;

            case NETMSG_DC_UPDATE:
                if(inbuf[inbufpos+1]!=a) {
                    SendSystemMsg("Server: Warning got dc update msg from %i claiming to be from %i",a,inbuf[inbufpos+1]);
                } else {
                    if(!serverNet->IsDemoServer())
                        serverNet->SendDirectControlUpdate(inbuf[inbufpos+1], inbuf[inbufpos+2], *((short*)&inbuf[inbufpos+3]), *((short*)&inbuf[inbufpos+5]));
                }
                lastLength=7;
                break;
#endif
            default:
#ifdef SYNCDEBUG
                // maybe something for the sync debugger?
                lastLength = CSyncDebugger::GetInstance()->ServerReceived(&inbuf[inbufpos]);
                if (!lastLength)
#endif
                {
                    logOutput.Print("Unknown net msg in server %d from %d pos %d last %d", (int)inbuf[inbufpos], a, inbufpos, lastMsg[a]);
                    lastLength=1;
                }
                break;
            }
            if(lastLength<=0) {
                logOutput.Print("Server readnet got packet type %i length %i pos %i from %i??",thisMsg,lastLength,inbufpos,a);
                lastLength=1;
            }
            inbufpos+=lastLength;
            lastMsg[a]=thisMsg;
        }
        if(inbufpos!=inbuflength) {
            char txt[200];
            sprintf(txt,"Wrong packet length got %d from %d instead of %d",inbufpos,a,inbuflength);
            logOutput.Print("%s", txt);
            handleerror(0,txt,"Server network error",0);
        }
    }
#ifdef SYNCDEBUG
    CSyncDebugger::GetInstance()->ServerHandlePendingBlockRequests();
#endif
    return true;
}