Exemplo n.º 1
0
// send complete game info set!
void sendOptions()
{
    unsigned int i;

    if (!NetPlay.isHost || !bHosted)  // Only host should act, and only if the game hasn't started yet.
    {
        ASSERT(false, "Host only routine detected for client or not hosting yet!");
        return;
    }

    NETbeginEncode(NETbroadcastQueue(), NET_OPTIONS);

    // First send information about the game
    NETuint8_t(&game.type);
    NETstring(game.map, 128);
    NETbin(game.hash.bytes, game.hash.Bytes);
    NETuint8_t(&game.maxPlayers);
    NETstring(game.name, 128);
    NETuint32_t(&game.power);
    NETuint8_t(&game.base);
    NETuint8_t(&game.alliance);
    NETbool(&game.scavengers);

    for (i = 0; i < MAX_PLAYERS; i++)
    {
        NETuint8_t(&game.skDiff[i]);
    }

    // Send the list of who is still joining
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        NETbool(&ingame.JoiningInProgress[i]);
    }

    // Same goes for the alliances
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        unsigned int j;

        for (j = 0; j < MAX_PLAYERS; j++)
        {
            NETuint8_t(&alliances[i][j]);
        }
    }

    // Send the number of structure limits to expect
    NETuint32_t(&ingame.numStructureLimits);
    debug(LOG_NET, "(Host) Structure limits to process on client is %u", ingame.numStructureLimits);
    // Send the structures changed
    for (i = 0; i < ingame.numStructureLimits; i++)
    {
        NETuint32_t(&ingame.pStructureLimits[i].id);
        NETuint32_t(&ingame.pStructureLimits[i].limit);
    }
    updateLimitFlags();
    NETuint8_t(&ingame.flags);

    NETend();
}
Exemplo n.º 2
0
// accept and process incoming ping messages.
bool recvPing(NETQUEUE queue)
{
	bool	isNew = false;
	uint8_t	sender, us = selectedPlayer;
	uint8_t challenge[sizeof(pingChallenge)];
	EcKey::Sig challengeResponse;

	NETbeginDecode(queue, NET_PING);
	NETuint8_t(&sender);
	NETbool(&isNew);
	if (isNew)
	{
		NETbin(challenge, sizeof(pingChallenge));
	}
	else
	{
		NETbytes(&challengeResponse);
	}
	NETend();

	if (sender >= MAX_PLAYERS)
	{
		debug(LOG_ERROR, "Bad NET_PING packet, sender is %d", (int)sender);
		return false;
	}

	// If this is a new ping, respond to it
	if (isNew)
	{
		challengeResponse = getMultiStats(us).identity.sign(&challenge, sizeof(pingChallenge));

		NETbeginEncode(NETnetQueue(sender), NET_PING);
		// We are responding to a new ping
		isNew = false;

		NETuint8_t(&us);
		NETbool(&isNew);
		NETbytes(&challengeResponse);
		NETend();
	}
	// They are responding to one of our pings
	else
	{
		if (!getMultiStats(sender).identity.empty() && !getMultiStats(sender).identity.verify(challengeResponse, pingChallenge, sizeof(pingChallenge)))
		{
			// Either bad signature, or we sent more than one ping packet and this response is to an older one than the latest.
			debug(LOG_NEVER, "Bad and/or old NET_PING packet, alleged sender is %d", (int)sender);
			return false;
		}

		// Work out how long it took them to respond
		ingame.PingTimes[sender] = (realTime - PingSend[sender]) / 2;

		// Note that we have received it
		PingSend[sender] = 0;
	}

	return true;
}
Exemplo n.º 3
0
// ////////////////////////////////////////////////////////////////////////////
// options for a game. (usually recvd in frontend)
void recvOptions(NETQUEUE queue)
{
	unsigned int i;

	debug(LOG_NET, "Receiving options from host");
	NETbeginDecode(queue, NET_OPTIONS);

	// Get general information about the game
	NETuint8_t(&game.type);
	NETstring(game.map, 128);
	NETbin(game.hash.bytes, game.hash.Bytes);
	uint32_t modHashesSize;
	NETuint32_t(&modHashesSize);
	ASSERT_OR_RETURN(, modHashesSize < 1000000, "Way too many mods %u", modHashesSize);
	game.modHashes.resize(modHashesSize);
	for (auto &hash : game.modHashes)
	{
		NETbin(hash.bytes, hash.Bytes);
	}
	NETuint8_t(&game.maxPlayers);
	NETstring(game.name, 128);
	NETuint32_t(&game.power);
	NETuint8_t(&game.base);
	NETuint8_t(&game.alliance);
	NETbool(&game.scavengers);
	NETbool(&game.isMapMod);

	for (i = 0; i < MAX_PLAYERS; i++)
	{
		NETuint8_t(&game.skDiff[i]);
	}

	// Send the list of who is still joining
	for (i = 0; i < MAX_PLAYERS; i++)
	{
		NETbool(&ingame.JoiningInProgress[i]);
	}

	// Alliances
	for (i = 0; i < MAX_PLAYERS; i++)
	{
		unsigned int j;

		for (j = 0; j < MAX_PLAYERS; j++)
		{
			NETuint8_t(&alliances[i][j]);
		}
	}
	netPlayersUpdated = true;

	// Free any structure limits we may have in-place
	if (ingame.numStructureLimits)
	{
		ingame.numStructureLimits = 0;
		free(ingame.pStructureLimits);
		ingame.pStructureLimits = NULL;
	}

	// Get the number of structure limits to expect
	NETuint32_t(&ingame.numStructureLimits);
	debug(LOG_NET, "Host is sending us %u structure limits", ingame.numStructureLimits);
	// If there were any changes allocate memory for them
	if (ingame.numStructureLimits)
	{
		ingame.pStructureLimits = (MULTISTRUCTLIMITS *)malloc(ingame.numStructureLimits * sizeof(MULTISTRUCTLIMITS));
	}

	for (i = 0; i < ingame.numStructureLimits; i++)
	{
		NETuint32_t(&ingame.pStructureLimits[i].id);
		NETuint32_t(&ingame.pStructureLimits[i].limit);
	}
	NETuint8_t(&ingame.flags);

	NETend();

	// Do the skirmish slider settings if they are up
	for (i = 0; i < MAX_PLAYERS; i++)
	{
		if (widgGetFromID(psWScreen, MULTIOP_SKSLIDE + i))
		{
			widgSetSliderPos(psWScreen, MULTIOP_SKSLIDE + i, game.skDiff[i]);
		}
	}
	debug(LOG_INFO, "Rebuilding map list");
	// clear out the old level list.
	levShutDown();
	levInitialise();
	rebuildSearchPath(mod_multiplay, true);	// MUST rebuild search path for the new maps we just got!
	buildMapList();

	bool haveData = true;
	auto requestFile = [&haveData](Sha256 &hash, char const *filename) {
		if (std::any_of(NetPlay.wzFiles.begin(), NetPlay.wzFiles.end(), [&hash](WZFile const &file) { return file.hash == hash; }))
		{
			debug(LOG_INFO, "Already requested file, continue waiting.");
			haveData = false;
			return false;  // Downloading the file already
		}

		if (!PHYSFS_exists(filename))
		{
			debug(LOG_INFO, "Creating new file %s", filename);
		}
		else if (findHashOfFile(filename) != hash)
		{
			debug(LOG_INFO, "Overwriting old incomplete or corrupt file %s", filename);
		}
		else
		{
			return false;  // Have the file already.
		}

		NetPlay.wzFiles.emplace_back(PHYSFS_openWrite(filename), hash);

		// Request the map/mod from the host
		NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_FILE_REQUESTED);
		NETbin(hash.bytes, hash.Bytes);
		NETend();

		haveData = false;
		return true;  // Starting download now.
	};

	LEVEL_DATASET *mapData = levFindDataSet(game.map, &game.hash);
	// See if we have the map or not
	if (mapData == nullptr)
	{
		char mapName[256];
		sstrcpy(mapName, game.map);
		removeWildcards(mapName);

		if (strlen(mapName) >= 3 && mapName[strlen(mapName) - 3] == '-' && mapName[strlen(mapName) - 2] == 'T' && unsigned(mapName[strlen(mapName) - 1] - '1') < 3)
		{
			mapName[strlen(mapName) - 3] = '\0';  // Cut off "-T1", "-T2" or "-T3".
		}
		char filename[256];
		ssprintf(filename, "maps/%dc-%s-%s.wz", game.maxPlayers, mapName, game.hash.toString().c_str());  // Wonder whether game.maxPlayers is initialised already?

		if (requestFile(game.hash, filename))
		{
			debug(LOG_INFO, "Map was not found, requesting map %s from host, type %d", game.map, game.isMapMod);
			addConsoleMessage("MAP REQUESTED!", DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
		}
		else
		{
			debug(LOG_FATAL, "Can't load map %s, even though we downloaded %s", game.map, filename);
			abort();
		}
	}

	for (Sha256 &hash : game.modHashes)
	{
		char filename[256];
		ssprintf(filename, "mods/downloads/%s", hash.toString().c_str());

		if (requestFile(hash, filename))
		{
			debug(LOG_INFO, "Mod was not found, requesting mod %s from host", hash.toString().c_str());
			addConsoleMessage("MOD REQUESTED!", DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
		}
	}

	if (mapData && CheckForMod(mapData->realFileName))
	{
		char const *str = game.isMapMod ?
			_("Warning, this is a map-mod, it could alter normal gameplay.") :
			_("Warning, HOST has altered the game code, and can't be trusted!");
		addConsoleMessage(str, DEFAULT_JUSTIFY, NOTIFY_MESSAGE);
		game.isMapMod = true;
	}

	if (mapData)
	{
		loadMapPreview(false);
	}
}
Exemplo n.º 4
0
// ////////////////////////////////////////////////////////////////////////////
// options for a game. (usually recvd in frontend)
void recvOptions(NETQUEUE queue)
{
    unsigned int i;

    debug(LOG_NET, "Receiving options from host");
    NETbeginDecode(queue, NET_OPTIONS);

    // Get general information about the game
    NETuint8_t(&game.type);
    NETstring(game.map, 128);
    NETbin(game.hash.bytes, game.hash.Bytes);
    NETuint8_t(&game.maxPlayers);
    NETstring(game.name, 128);
    NETuint32_t(&game.power);
    NETuint8_t(&game.base);
    NETuint8_t(&game.alliance);
    NETbool(&game.scavengers);

    for (i = 0; i < MAX_PLAYERS; i++)
    {
        NETuint8_t(&game.skDiff[i]);
    }

    // Send the list of who is still joining
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        NETbool(&ingame.JoiningInProgress[i]);
    }

    // Alliances
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        unsigned int j;

        for (j = 0; j < MAX_PLAYERS; j++)
        {
            NETuint8_t(&alliances[i][j]);
        }
    }
    netPlayersUpdated = true;

    // Free any structure limits we may have in-place
    if (ingame.numStructureLimits)
    {
        ingame.numStructureLimits = 0;
        free(ingame.pStructureLimits);
        ingame.pStructureLimits = NULL;
    }

    // Get the number of structure limits to expect
    NETuint32_t(&ingame.numStructureLimits);
    debug(LOG_NET, "Host is sending us %u structure limits", ingame.numStructureLimits);
    // If there were any changes allocate memory for them
    if (ingame.numStructureLimits)
    {
        ingame.pStructureLimits = (MULTISTRUCTLIMITS *)malloc(ingame.numStructureLimits * sizeof(MULTISTRUCTLIMITS));
    }

    for (i = 0; i < ingame.numStructureLimits; i++)
    {
        NETuint32_t(&ingame.pStructureLimits[i].id);
        NETuint32_t(&ingame.pStructureLimits[i].limit);
    }
    NETuint8_t(&ingame.flags);

    NETend();

    // Do the skirmish slider settings if they are up
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        if (widgGetFromID(psWScreen, MULTIOP_SKSLIDE + i))
        {
            widgSetSliderPos(psWScreen, MULTIOP_SKSLIDE + i, game.skDiff[i]);
        }
    }
    debug(LOG_INFO, "Rebuilding map list");
    // clear out the old level list.
    levShutDown();
    levInitialise();
    setCurrentMap(NULL, 42);
    rebuildSearchPath(mod_multiplay, true);	// MUST rebuild search path for the new maps we just got!
    buildMapList();
    // See if we have the map or not
    if (levFindDataSet(game.map, &game.hash) == NULL)
    {
        uint32_t player = selectedPlayer;

        debug(LOG_INFO, "Map was not found, requesting map %s from host.", game.map);
        // Request the map from the host
        NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_FILE_REQUESTED);
        NETuint32_t(&player);
        NETend();

        addConsoleMessage("MAP REQUESTED!", DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
    }
    else
    {
        loadMapPreview(false);
    }
}
Exemplo n.º 5
0
bool sendPing(void)
{
	bool			isNew = true;
	uint8_t			player = selectedPlayer;
	int				i;
	static UDWORD	lastPing = 0;	// Last time we sent a ping
	static UDWORD	lastav = 0;		// Last time we updated average

	// Only ping every so often
	if (lastPing > realTime)
	{
		lastPing = 0;
	}

	if (realTime - lastPing < PING_FREQUENCY)
	{
		return true;
	}

	lastPing = realTime;

	// If host, also update the average ping stat for joiners
	if (NetPlay.isHost)
	{
		if (lastav > realTime)
		{
			lastav = 0;
		}

		if (realTime - lastav > AV_PING_FREQUENCY)
		{
			NETsetGameFlags(2, averagePing());
			lastav = realTime;
		}
	}

	/*
	 * Before we send the ping, if any player failed to respond to the last one
	 * we should re-enumerate the players.
	 */

	for (i = 0; i < MAX_PLAYERS; i++)
	{
		if (isHumanPlayer(i)
		    && PingSend[i]
		    && ingame.PingTimes[i]
		    && i != selectedPlayer)
		{
			ingame.PingTimes[i] = PING_LIMIT;
		}
		else if (!isHumanPlayer(i)
		         && PingSend[i]
		         && ingame.PingTimes[i]
		         && i != selectedPlayer)
		{
			ingame.PingTimes[i] = 0;
		}
	}

	uint64_t pingChallengei = (uint64_t)rand() << 32 | rand();
	memcpy(pingChallenge, &pingChallengei, sizeof(pingChallenge));

	NETbeginEncode(NETbroadcastQueue(), NET_PING);
	NETuint8_t(&player);
	NETbool(&isNew);
	NETbin(pingChallenge, sizeof(pingChallenge));
	NETend();

	// Note when we sent the ping
	for (i = 0; i < MAX_PLAYERS; i++)
	{
		PingSend[i] = realTime;
	}

	return true;
}