//
// At this time, we do NOT support messages for beacons
//
bool sendBeacon(int32_t locX, int32_t locY, int32_t forPlayer, int32_t sender, const char* pStr)
{
	int sendPlayer;
	//debug(LOG_WZ, "sendBeacon: '%s'",pStr);

	//find machine that is hosting this human or AI
	sendPlayer = whosResponsible(forPlayer);

	if(sendPlayer >= MAX_PLAYERS)
	{
		debug(LOG_ERROR, "sendAIMessage() - whosResponsible() failed.");
		return false;
	}

	// I assume this is correct, looks like it sends it to ONLY that person, and the routine
	// kf_AddHelpBlip() iterates for each player it needs.
	NETbeginEncode(NETnetQueue(sendPlayer), NET_BEACONMSG);    // send to the player who is hosting 'to' player (might be himself if human and not AI)
		NETint32_t(&sender);                                // save the actual sender

		// save the actual player that is to get this msg on the source machine (source can host many AIs)
		NETint32_t(&forPlayer);                             // save the actual receiver (might not be the same as the one we are actually sending to, in case of AIs)
		NETint32_t(&locX);                                  // save location
		NETint32_t(&locY);

		// const_cast: need to cast away constness because of the const-incorrectness of NETstring (const-incorrect when sending/encoding a packet)
		NETstring((char*)pStr, MAX_CONSOLE_STRING_LENGTH);  // copy message in.
	NETend();

	return true;
}
Exemple #2
0
static void sendPlayerLeft(uint32_t playerIndex)
{
	ASSERT(NetPlay.isHost, "Only host should call this.");

	uint32_t forcedPlayerIndex = whosResponsible(playerIndex);
	NETQUEUE(*netQueueType)(unsigned) = forcedPlayerIndex != selectedPlayer ? NETgameQueueForced : NETgameQueue;
	NETbeginEncode(netQueueType(forcedPlayerIndex), GAME_PLAYER_LEFT);
	NETuint32_t(&playerIndex);
	NETend();
}
// Write a message to the console.
bool recvTextMessage(NETQUEUE queue)
{
	UDWORD	playerIndex;
	char	msg[MAX_CONSOLE_STRING_LENGTH];
	char newmsg[MAX_CONSOLE_STRING_LENGTH];

	memset(msg, 0x0, sizeof(msg));
	memset(newmsg, 0x0, sizeof(newmsg));

	NETbeginDecode(queue, NET_TEXTMSG);
		// Who this msg is from
		NETuint32_t(&playerIndex);
		// The message to send
		NETstring(newmsg, MAX_CONSOLE_STRING_LENGTH);
	NETend();

	if (whosResponsible(playerIndex) != queue.index)
	{
		playerIndex = queue.index;  // Fix corrupted playerIndex.
	}

	if (playerIndex >= MAX_PLAYERS || (!NetPlay.players[playerIndex].allocated && NetPlay.players[playerIndex].ai == AI_OPEN))
	{
		return false;
	}

	sstrcpy(msg, NetPlay.players[playerIndex].name);
	// Seperator
	sstrcat(msg, ": ");
	// Add message
	sstrcat(msg, newmsg);

	addConsoleMessage(msg, DEFAULT_JUSTIFY, playerIndex);

	// Multiplayer message callback
	// Received a console message from a player, save
	MultiMsgPlayerFrom = playerIndex;
	MultiMsgPlayerTo = selectedPlayer;

	sstrcpy(MultiplayMsg, newmsg);
	eventFireCallbackTrigger((TRIGGER_TYPE)CALL_AI_MSG);

	// make some noise!
	if (titleMode == MULTIOPTION || titleMode == MULTILIMIT)
	{
		audio_PlayTrack(FE_AUDIO_MESSAGEEND);
	}
	else if (!ingame.localJoiningInProgress)
	{
		audio_PlayTrack(ID_SOUND_MESSAGEEND);
	}

	return true;
}
//AI multiplayer message, send from a certain player index to another player index
bool sendAIMessage(char *pStr, UDWORD player, UDWORD to)
{
	UDWORD	sendPlayer;

	//check if this is one of the local players, don't need net send then
	if (to == selectedPlayer || myResponsibility(to))	//(the only) human on this machine or AI on this machine
	{
		triggerEventChat(player, to, pStr);

		//Just show "him" the message
		displayAIMessage(pStr, player, to);

		//Received a console message from a player callback
		//store and call later
		//-------------------------------------------------
		if (!msgStackPush(CALL_AI_MSG,player,to,pStr,-1,-1,NULL))
		{
			debug(LOG_ERROR, "sendAIMessage() - msgStackPush - stack failed");
			return false;
		}
	}
	else		//not a local player (use multiplayer mode)
	{
		if (!ingame.localOptionsReceived)
		{
			return true;
		}

		//find machine that is hosting this human or AI
		sendPlayer = whosResponsible(to);

		if (sendPlayer >= MAX_PLAYERS)
		{
			debug(LOG_ERROR, "sendAIMessage() - sendPlayer >= MAX_PLAYERS");
			return false;
		}

		if (!isHumanPlayer(sendPlayer))		//NETsend can't send to non-humans
		{
			debug(LOG_ERROR, "sendAIMessage() - player is not human.");
			return false;
		}

		//send to the player who is hosting 'to' player (might be himself if human and not AI)
		NETbeginEncode(NETnetQueue(sendPlayer), NET_AITEXTMSG);
			NETuint32_t(&player);			//save the actual sender
			//save the actual player that is to get this msg on the source machine (source can host many AIs)
			NETuint32_t(&to);				//save the actual receiver (might not be the same as the one we are actually sending to, in case of AIs)
			NETstring(pStr, MAX_CONSOLE_STRING_LENGTH);		// copy message in.
		NETend();
	}

	return true;
}
Exemple #5
0
void sendPlayerGameTime()
{
	unsigned player;
	uint32_t latencyTicks = discreteChosenLatency / GAME_TICKS_PER_UPDATE;
	uint32_t checkTime = gameTime;
	uint32_t checkCrc = nextDebugSync();

	for (player = 0; player < game.maxPlayers; ++player)
	{
		if (!myResponsibility(player) && whosResponsible(player) != realSelectedPlayer)
		{
			continue;
		}

		NETbeginEncode(NETgameQueue(player), GAME_GAME_TIME);
			NETuint32_t(&latencyTicks);
			NETuint32_t(&checkTime);
			NETuint32_tLarge(&checkCrc);
			NETuint16_t(&wantedLatency);
		NETend();
	}
}
Exemple #6
0
void recvPlayerLeft(NETQUEUE queue)
{
	uint32_t playerIndex = 0;
	NETbeginDecode(queue, GAME_PLAYER_LEFT);
	NETuint32_t(&playerIndex);
	NETend();

	addConsolePlayerLeftMessage(playerIndex);

	if (whosResponsible(playerIndex) != queue.index)
	{
		return;
	}

	turnOffMultiMsg(true);
	clearPlayer(playerIndex, false);  // don't do it quietly
	turnOffMultiMsg(false);
	NetPlay.players[playerIndex].allocated = false;

	NETsetPlayerConnectionStatus(CONNECTIONSTATUS_PLAYER_DROPPED, playerIndex);

	debug(LOG_INFO, "** player %u has dropped, in-game!", playerIndex);
}
Exemple #7
0
void recvPlayerLeft(NETQUEUE queue)
{
	uint32_t playerIndex = 0;
	NETbeginDecode(queue, GAME_PLAYER_LEFT);
		NETuint32_t(&playerIndex);
	NETend();
	if (whosResponsible(playerIndex) != queue.index)
	{
		return;
	}

	turnOffMultiMsg(true);
	clearPlayer(playerIndex, false);  // don't do it quietly
	turnOffMultiMsg(false);
	NetPlay.players[playerIndex].allocated = false;

	char buf[256];
	ssprintf(buf, _("%s has Left the Game"), getPlayerName(playerIndex));
	addConsoleMessage(buf, DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
	NETsetPlayerConnectionStatus(CONNECTIONSTATUS_PLAYER_DROPPED, playerIndex);

	debug(LOG_INFO, "** player %u has dropped, in-game!", playerIndex);
}
//AI multiplayer message - received message from AI (from scripts)
bool recvTextMessageAI(NETQUEUE queue)
{
	UDWORD	sender, receiver;
	char	msg[MAX_CONSOLE_STRING_LENGTH];
	char	newmsg[MAX_CONSOLE_STRING_LENGTH];

	NETbeginDecode(queue, NET_AITEXTMSG);
		NETuint32_t(&sender);			//in-game player index ('normal' one)
		NETuint32_t(&receiver);			//in-game player index
		NETstring(newmsg,MAX_CONSOLE_STRING_LENGTH);
	NETend();

	if (whosResponsible(sender) != queue.index)
	{
		sender = queue.index;  // Fix corrupted sender.
	}

	//sstrcpy(msg, getPlayerName(sender));  // name
	//sstrcat(msg, " : ");                  // seperator
	sstrcpy(msg, newmsg);
	triggerEventChat(sender, receiver, newmsg);

	//Display the message and make the script callback
	displayAIMessage(msg, sender, receiver);

	//Received a console message from a player callback
	//store and call later
	//-------------------------------------------------
	if(!msgStackPush(CALL_AI_MSG,sender,receiver,msg,-1,-1,NULL))
	{
		debug(LOG_ERROR, "recvTextMessageAI() - msgStackPush - stack failed");
		return false;
	}

	return true;
}
Exemple #9
0
bool recvDataCheck(NETQUEUE queue)
{
	int i = 0;
	uint32_t player = queue.index;
	uint32_t tempBuffer[DATA_MAXDATA] = {0};

	if(!NetPlay.isHost)				// only host should act
	{
		ASSERT(false, "Host only routine detected for client!");
		return false;
	}

	NETbeginDecode(queue, NET_DATA_CHECK);
	for(i = 0; i < DATA_MAXDATA; i++)
	{
		NETuint32_t(&tempBuffer[i]);
	}
	NETend();

	if (player >= MAX_PLAYERS) // invalid player number.
	{
		debug(LOG_ERROR, "invalid player number (%u) detected.", player);
		return false;
	}

	if (whosResponsible(player) != queue.index)
	{
		HandleBadParam("NET_DATA_CHECK given incorrect params.", player, queue.index);
		return false;
	}

	debug(LOG_NET, "** Received NET_DATA_CHECK from player %u", player);

	if (NetPlay.isHost)
	{
		if (memcmp(DataHash, tempBuffer, sizeof(DataHash)))
		{
			char msg[256] = {'\0'};

			for (i=0; i<DATA_MAXDATA; i++)
			{
				if (DataHash[i] != tempBuffer[i]) break;
			}

			sprintf(msg, _("%s (%u) has an incompatible mod, and has been kicked."), getPlayerName(player), player);
			sendTextMessage(msg, true);
			addConsoleMessage(msg, LEFT_JUSTIFY, NOTIFY_MESSAGE);

			kickPlayer(player, "your data doesn't match the host's!", ERROR_WRONGDATA);
			debug(LOG_WARNING, "%s (%u) has an incompatible mod. ([%d] got %x, expected %x)", getPlayerName(player), player, i, tempBuffer[i], DataHash[i]);
			debug(LOG_POPUP, "%s (%u), has an incompatible mod. ([%d] got %x, expected %x)", getPlayerName(player), player, i, tempBuffer[i], DataHash[i]);

			return false;
		}
		else
		{
			debug(LOG_NET, "DataCheck message received and verified for player %s (slot=%u)", getPlayerName(player), player);
			ingame.DataIntegrity[player] = true;
		}
	}
	return true;
}
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// Recv Messages. Get a message and dispatch to relevant function.
bool recvMessage(void)
{
	NETQUEUE queue;
	uint8_t type;

	while (NETrecvNet(&queue, &type) || NETrecvGame(&queue, &type))          // for all incoming messages.
	{
		bool processedMessage1 = false;
		bool processedMessage2 = false;

		if (queue.queueType == QUEUE_GAME)
		{
			syncDebug("Processing player %d, message %s", queue.index, messageTypeToString(type));
		}

		// messages only in game.
		if(!ingame.localJoiningInProgress)
		{
			processedMessage1 = true;
			switch(type)
			{
			case GAME_DROIDINFO:					//droid update info
				recvDroidInfo(queue);
				break;
			case NET_TEXTMSG:					// simple text message
				recvTextMessage(queue);
				break;
			case NET_DATA_CHECK:
				recvDataCheck(queue);
				break;
			case NET_AITEXTMSG:					//multiplayer AI text message
				recvTextMessageAI(queue);
				break;
			case NET_BEACONMSG:					//beacon (blip) message
				recvBeacon(queue);
				break;
			case GAME_DROIDDISEMBARK:
				recvDroidDisEmbark(queue);           //droid has disembarked from a Transporter
				break;
			case GAME_GIFT:						// an alliance gift from one player to another.
				recvGift(queue);
				break;
			case GAME_LASSAT:
				recvLasSat(queue);
				break;
			case GAME_DEBUG_MODE:
				recvProcessDebugMappings(queue);
				break;
			case GAME_DEBUG_ADD_DROID:
				recvDroid(queue);
				break;
			case GAME_DEBUG_ADD_STRUCTURE:
				recvBuildFinished(queue);
				break;
			case GAME_DEBUG_ADD_FEATURE:
				recvMultiPlayerFeature(queue);
				break;
			case GAME_DEBUG_REMOVE_DROID:
				recvDestroyDroid(queue);
				break;
			case GAME_DEBUG_REMOVE_STRUCTURE:
				recvDestroyStructure(queue);
				break;
			case GAME_DEBUG_REMOVE_FEATURE:
				recvDestroyFeature(queue);
				break;
			case GAME_DEBUG_FINISH_RESEARCH:
				recvResearch(queue);
				break;
			default:
				processedMessage1 = false;
				break;
			}
		}

		// messages usable all the time
		processedMessage2 = true;
		switch(type)
		{
		case GAME_TEMPLATE:					// new template
			recvTemplate(queue);
			break;
		case GAME_TEMPLATEDEST:				// template destroy
			recvDestroyTemplate(queue);
			break;
		case NET_PING:						// diagnostic ping msg.
			recvPing(queue);
			break;
		case NET_OPTIONS:
			recvOptions(queue);
			break;
		case NET_PLAYER_DROPPED:				// remote player got disconnected
		{
			uint32_t player_id;

			NETbeginDecode(queue, NET_PLAYER_DROPPED);
			{
				NETuint32_t(&player_id);
			}
			NETend();

			if (whosResponsible(player_id) != queue.index && queue.index != NET_HOST_ONLY)
			{
				HandleBadParam("NET_PLAYER_DROPPED given incorrect params.", player_id, queue.index);
				break;
			}

			debug(LOG_INFO,"** player %u has dropped!", player_id);

			if (NetPlay.players[player_id].allocated)
			{
				MultiPlayerLeave(player_id);		// get rid of their stuff
				NET_InitPlayer(player_id, false);
			}
			NETsetPlayerConnectionStatus(CONNECTIONSTATUS_PLAYER_DROPPED, player_id);
			break;
		}
		case NET_PLAYERRESPONDING:			// remote player is now playing
		{
			uint32_t player_id;

			resetReadyStatus(false);

			NETbeginDecode(queue, NET_PLAYERRESPONDING);
				// the player that has just responded
				NETuint32_t(&player_id);
			NETend();
			if (player_id >= MAX_PLAYERS)
			{
				debug(LOG_ERROR, "Bad NET_PLAYERRESPONDING received, ID is %d", (int)player_id);
				break;
			}
			// This player is now with us!
			ingame.JoiningInProgress[player_id] = false;
			break;
		}
		// FIXME: the next 4 cases might not belong here --check (we got two loops for this)
		case NET_COLOURREQUEST:
			recvColourRequest(queue);
			break;
		case NET_POSITIONREQUEST:
			recvPositionRequest(queue);
			break;
		case NET_TEAMREQUEST:
			recvTeamRequest(queue);
			break;
		case NET_READY_REQUEST:
			recvReadyRequest(queue);

			// if hosting try to start the game if everyone is ready
			if(NetPlay.isHost && multiplayPlayersReady(false))
			{
				startMultiplayerGame();
			}
			break;
		case GAME_ALLIANCE:
			recvAlliance(queue, true);
			break;
		case NET_KICK:	// in-game kick message
		{
			uint32_t player_id;
			char reason[MAX_KICK_REASON];
			LOBBY_ERROR_TYPES KICK_TYPE = ERROR_NOERROR;

			NETbeginDecode(queue, NET_KICK);
				NETuint32_t(&player_id);
				NETstring(reason, MAX_KICK_REASON);
				NETenum(&KICK_TYPE);
			NETend();

			if (player_id == NET_HOST_ONLY)
			{
				char buf[250]= {'\0'};

				ssprintf(buf, "Player %d (%s : %s) tried to kick %u", (int) queue.index, NetPlay.players[queue.index].name, NetPlay.players[queue.index].IPtextAddress, player_id);
				NETlogEntry(buf, SYNC_FLAG, 0);
				debug(LOG_ERROR, "%s", buf);
				if (NetPlay.isHost)
				{
					NETplayerKicked((unsigned int) queue.index);
				}
				break;
			}
			else if (selectedPlayer == player_id)  // we've been told to leave.
			{
				debug(LOG_ERROR, "You were kicked because %s", reason);
				setPlayerHasLost(true);
			}
			else
			{
				debug(LOG_NET, "Player %d was kicked: %s", player_id, reason);
				NETplayerKicked(player_id);
			}
			break;
		}
		case GAME_RESEARCHSTATUS:
			recvResearchStatus(queue);
			break;
		case GAME_STRUCTUREINFO:
			recvStructureInfo(queue);
			break;
		case NET_PLAYER_STATS:
			recvMultiStats(queue);
			break;
		case GAME_PLAYER_LEFT:
			recvPlayerLeft(queue);
			break;
		default:
			processedMessage2 = false;
			break;
		}

		if (processedMessage1 && processedMessage2)
		{
			debug(LOG_ERROR, "Processed %s message twice!", messageTypeToString(type));
		}
		if (!processedMessage1 && !processedMessage2)
		{
			debug(LOG_ERROR, "Didn't handle %s message!", messageTypeToString(type));
		}

		NETpop(queue);
	}

	return true;
}
//returns true if 'player' is responsible for 'playerinquestion'
bool responsibleFor(int player, int playerinquestion)
{
	return whosResponsible(playerinquestion) == player;
}
//returns true if selected player is responsible for 'player'
bool myResponsibility(int player)
{
	return (whosResponsible(player) == selectedPlayer || whosResponsible(player) == realSelectedPlayer);
}