Beispiel #1
0
// send complete game info set!
void sendOptions()
{
	bool dummy = true;
	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);
	NETuint8_t(&game.maxPlayers);
	NETstring(game.name, 128);
	NETbool(&dummy);
	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();
}
Beispiel #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;
}
Beispiel #3
0
// send complete game info set!
void sendOptions()
{
	unsigned int i;

	NETbeginEncode(NETbroadcastQueue(), NET_OPTIONS);

	// First send information about the game
	NETuint8_t(&game.type);
	NETstring(game.map, 128);
	NETuint8_t(&game.maxPlayers);
	NETstring(game.name, 128);
	NETbool(&game.fog);
	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();
}
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// New research stuff, so you can see what others are up to!
// inform others that I'm researching this.
bool sendResearchStatus(STRUCTURE *psBuilding, uint32_t index, uint8_t player, bool bStart)
{
	if (!myResponsibility(player) || gameTime < 5)
	{
		return true;
	}

	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_RESEARCHSTATUS);
		NETuint8_t(&player);
		NETbool(&bStart);

		// If we know the building researching it then send its ID
		if (psBuilding)
		{
			NETuint32_t(&psBuilding->id);
		}
		else
		{
			uint32_t zero = 0;
			NETuint32_t(&zero);
		}

		// Finally the topic in question
		NETuint32_t(&index);
	NETend();

	// Tell UI to remove from the list of available research.
	MakeResearchStartedPending(&asPlayerResList[player][index]);

	return true;
}
Beispiel #5
0
void recvProcessDebugMappings(NETQUEUE queue)
{
	bool val = false;
	NETbeginDecode(queue, GAME_DEBUG_MODE);
		NETbool(&val);
	NETend();

	bool oldDebugMode = getDebugMappingStatus();
	processDebugMappings(queue.index, val);
	bool newDebugMode = getDebugMappingStatus();

	char const *cmsg;
	if (val)
	{
		sasprintf((char**)&cmsg, _("%s wants to enable debug mode. Enabled: %s, Disabled: %s."), getPlayerName(queue.index), getWantedDebugMappingStatuses(true).c_str(), getWantedDebugMappingStatuses(false).c_str());
	}
	else
	{
		sasprintf((char**)&cmsg, _("%s wants to disable debug mode. Enabled: %s, Disabled: %s."), getPlayerName(queue.index), getWantedDebugMappingStatuses(true).c_str(), getWantedDebugMappingStatuses(false).c_str());
	}
	addConsoleMessage(cmsg, DEFAULT_JUSTIFY,  SYSTEM_MESSAGE);

	if (!oldDebugMode && newDebugMode)
	{
		addConsoleMessage(_("Debug mode now enabled!"), DEFAULT_JUSTIFY,  SYSTEM_MESSAGE);
	}
	else if (oldDebugMode && !newDebugMode)
	{
		addConsoleMessage(_("Debug mode now disabled!"), DEFAULT_JUSTIFY,  SYSTEM_MESSAGE);
	}
}
Beispiel #6
0
static void NETcoder(PACKETDIR dir)
{
	static const char original[] = "THIS IS A TEST STRING";
	char str[sizeof(original)];
	BOOL b = true;
	uint32_t u32 = 32;
	uint16_t u16 = 16;
	uint8_t u8 = 8;
	int32_t i32 = -32;
	int16_t i16 = -16;
	int8_t i8 = -8;
	test_enum te = test_b;

	sstrcpy(str, original);

	if (dir == PACKET_ENCODE)
		NETbeginEncode(0, 0);
	else
		NETbeginDecode(0);
	NETbool(&b);			assert(b == true);
	NETuint32_t(&u32);  assert(u32 == 32);
	NETuint16_t(&u16);  assert(u16 == 16);
	NETuint8_t(&u8);    assert(u8 == 8);
	NETint32_t(&i32);   assert(i32 == -32);
	NETint16_t(&i16);   assert(i16 == -16);
	NETint8_t(&i8);     assert(i8 == -8);
	NETstring(str, sizeof(str)); assert(strncmp(str, original, sizeof(str) - 1) == 0);
	NETenum(&te);       assert(te == test_b);
}
Beispiel #7
0
/// Does not read/write info->droidId!
static void NETQueuedDroidInfo(QueuedDroidInfo *info)
{
	NETuint8_t(&info->player);
	NETenum(&info->order);
	NETbool(&info->subType);
	if (info->subType)
	{
		NETuint32_t(&info->destId);
		NETenum(&info->destType);
	}
	else
	{
		NETuint32_t(&info->x);
		NETuint32_t(&info->y);
	}
	if (info->order == DORDER_BUILD || info->order == DORDER_LINEBUILD)
	{
		NETuint32_t(&info->structRef);
		NETuint16_t(&info->direction);
	}
	if (info->order == DORDER_LINEBUILD)
	{
		NETuint32_t(&info->x2);
		NETuint32_t(&info->y2);
	}
}
Beispiel #8
0
// ////////////////////////////////////////////////////////////////////////////
// Send a new Droid to the other players
bool SendDroid(DROID_TEMPLATE *pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrdersP)
{
	if (!bMultiMessages)
	{
		return true;
	}

	ASSERT_OR_RETURN(false, x != 0 && y != 0, "SendDroid: Invalid droid coordinates");
	ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player);

	// Dont send other droids during campaign setup
	if (ingame.localJoiningInProgress)
	{
		return true;
	}

	// Only send the droid if we are responsible
	if (!myResponsibility(player))
	{
		// Don't build if we are not responsible
		return false;
	}

	debug(LOG_SYNC, "Droid sent with id of %u", id);
	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEBUG_ADD_DROID);
	{
		Position pos(x, y, 0);
		bool haveInitialOrders = initialOrdersP != NULL;
		int32_t droidType = pTemplate->droidType;

		NETuint8_t(&player);
		NETuint32_t(&id);
		NETPosition(&pos);
		NETqstring(pTemplate->name);
		NETint32_t(&droidType);
		NETuint8_t(&pTemplate->asParts[COMP_BODY]);
		NETuint8_t(&pTemplate->asParts[COMP_BRAIN]);
		NETuint8_t(&pTemplate->asParts[COMP_PROPULSION]);
		NETuint8_t(&pTemplate->asParts[COMP_REPAIRUNIT]);
		NETuint8_t(&pTemplate->asParts[COMP_ECM]);
		NETuint8_t(&pTemplate->asParts[COMP_SENSOR]);
		NETuint8_t(&pTemplate->asParts[COMP_CONSTRUCT]);
		NETint8_t(&pTemplate->numWeaps);
		for (int i = 0; i < pTemplate->numWeaps; i++)
		{
			NETuint8_t(&pTemplate->asWeaps[i]);
		}
		NETbool(&haveInitialOrders);
		if (haveInitialOrders)
		{
			INITIAL_DROID_ORDERS initialOrders = *initialOrdersP;
			NETuint32_t(&initialOrders.secondaryOrder);
			NETint32_t(&initialOrders.moveToX);
			NETint32_t(&initialOrders.moveToY);
			NETuint32_t(&initialOrders.factoryId);  // For making scripts happy.
		}
	}
	debug(LOG_LIFE, "===> sending Droid from %u id of %u ", player, id);
	return NETend();
}
Beispiel #9
0
// accept and process incoming ping messages.
BOOL recvPing(NETQUEUE queue)
{
	BOOL	isNew;
	uint8_t	sender, us = selectedPlayer;

	NETbeginDecode(queue, NET_PING);
		NETuint8_t(&sender);
		NETbool(&isNew);
	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)
	{
		NETbeginEncode(NETnetQueue(sender), NET_PING);
			// We are responding to a new ping
			isNew = false;

			NETuint8_t(&us);
			NETbool(&isNew);
		NETend();
	}
	// They are responding to one of our pings
	else
	{
		// Work out how long it took them to respond
		ingame.PingTimes[sender] = (gameTime2 - PingSend[sender]) / 2;

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

	return true;
}
Beispiel #10
0
// ////////////////////////////////////////////////////////////////////////////
// Tell the host we are leaving the game 'nicely', (we wanted to) and not
// because we have some kind of error. (dropped or disconnected)
bool sendLeavingMsg(void)
{
	debug(LOG_NET, "We are leaving 'nicely'");
	NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_PLAYER_LEAVING);
	{
		bool host = NetPlay.isHost;
		uint32_t id = selectedPlayer;

		NETuint32_t(&id);
		NETbool(&host);
	}
	NETend();

	return true;
}
Beispiel #11
0
// ////////////////////////////////////////////////////////////////////////////
// Send a new Droid to the other players
BOOL SendDroid(const DROID_TEMPLATE* pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrdersP)
{
	if (!bMultiMessages)
		return true;

	ASSERT(x != 0 && y != 0, "SendDroid: Invalid droid coordinates");
	ASSERT( player < MAX_PLAYERS, "invalid player %u", player);

	// Dont send other droids during campaign setup
	if (ingame.localJoiningInProgress)
	{
		return true;
	}

	// Only send the droid if we are responsible
	if (!myResponsibility(player))
	{
		// Don't build if we are not responsible
		return false;
	}

	debug(LOG_SYNC, "Droid sent with id of %u", id);
	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROID);
	{
		Position pos = { x, y, 0 };
		uint32_t templateID = pTemplate->multiPlayerID;
		BOOL haveInitialOrders = initialOrdersP != NULL;

		NETuint8_t(&player);
		NETuint32_t(&id);
		NETPosition(&pos);
		NETuint32_t(&templateID);
		NETbool(&haveInitialOrders);
		if (haveInitialOrders)
		{
			INITIAL_DROID_ORDERS initialOrders = *initialOrdersP;
			NETuint32_t(&initialOrders.secondaryOrder);
			NETint32_t(&initialOrders.moveToX);
			NETint32_t(&initialOrders.moveToY);
			NETuint32_t(&initialOrders.factoryId);  // For making scripts happy.
		}
	}
	debug(LOG_LIFE, "===> sending Droid from %u id of %u ",player,id);
	return NETend();
}
Beispiel #12
0
/// Does not read/write info->droidId!
static void NETQueuedDroidInfo(QueuedDroidInfo *info)
{
	NETuint8_t(&info->player);
	NETenum(&info->subType);
	switch (info->subType)
	{
		case ObjOrder:
		case LocOrder:
			NETenum(&info->order);
			if (info->subType == ObjOrder)
			{
				NETuint32_t(&info->destId);
				NETenum(&info->destType);
			}
			else
			{
				NETauto(&info->pos);
			}
			if (info->order == DORDER_BUILD || info->order == DORDER_LINEBUILD)
			{
				NETuint32_t(&info->structRef);
				NETuint16_t(&info->direction);
			}
			if (info->order == DORDER_LINEBUILD)
			{
				NETauto(&info->pos2);
			}
			if (info->order == DORDER_BUILDMODULE)
			{
				NETauto(&info->index);
			}
			NETbool(&info->add);
			break;
		case SecondaryOrder:
			NETenum(&info->secOrder);
			NETenum(&info->secState);
			break;
	}
}
static void NETtemplate(DROID_TEMPLATE *pTempl)
{
	NETstring(pTempl->aName, sizeof(pTempl->aName));

	for (unsigned i = 0; i < ARRAY_SIZE(pTempl->asParts); ++i)
	{
		// signed, but sent as a bunch of bits...
		NETint32_t(&pTempl->asParts[i]);
	}

	NETuint32_t(&pTempl->buildPoints);
	NETuint32_t(&pTempl->powerPoints);
	NETuint32_t(&pTempl->storeCount);
	NETuint32_t(&pTempl->numWeaps);
	NETbool(&pTempl->stored);	// other players don't need to know, but we need to keep the knowledge in the loop somehow...

	for (int i = 0; i < DROID_MAXWEAPS; ++i)
	{
		NETuint32_t(&pTempl->asWeaps[i]);
	}

	NETenum(&pTempl->droidType);
	NETuint32_t(&pTempl->multiPlayerID);
}
Beispiel #14
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);
	}
}
Beispiel #15
0
void sendProcessDebugMappings(bool val)
{
	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEBUG_MODE);
		NETbool(&val);
	NETend();
}
Beispiel #16
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);
    }
}
Beispiel #17
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;
}
bool recvResearchStatus(NETQUEUE queue)
{
	STRUCTURE			*psBuilding;
	PLAYER_RESEARCH		*pPlayerRes;
	RESEARCH_FACILITY	*psResFacilty;
	RESEARCH			*pResearch;
	uint8_t				player;
	bool				bStart;
	uint32_t			index, structRef;

	NETbeginDecode(queue, GAME_RESEARCHSTATUS);
		NETuint8_t(&player);
		NETbool(&bStart);
		NETuint32_t(&structRef);
		NETuint32_t(&index);
	NETend();

	syncDebug("player%d, bStart%d, structRef%u, index%u", player, bStart, structRef, index);

	if (player >= MAX_PLAYERS || index >= asResearch.size())
	{
		debug(LOG_ERROR, "Bad GAME_RESEARCHSTATUS received, player is %d, index is %u", (int)player, index);
		return false;
	}
	if (!canGiveOrdersFor(queue.index, player))
	{
		debug(LOG_WARNING, "Droid order for wrong player.");
		syncDebug("Wrong player.");
		return false;
	}

	int prevResearchState = 0;
	if (aiCheckAlliances(selectedPlayer, player))
	{
		prevResearchState = intGetResearchState();
	}

	pPlayerRes = &asPlayerResList[player][index];

	// psBuilding may be null if finishing
	if (bStart)							// Starting research
	{
		psBuilding = IdToStruct(structRef, player);

		// Set that facility to research
		if (psBuilding && psBuilding->pFunctionality)
		{
			psResFacilty = (RESEARCH_FACILITY *) psBuilding->pFunctionality;

			popStatusPending(*psResFacilty);  // Research is no longer pending, as it's actually starting now.

			if (psResFacilty->psSubject)
			{
				cancelResearch(psBuilding, ModeImmediate);
			}

			// Set the subject up
			pResearch				= &asResearch[index];
			psResFacilty->psSubject = pResearch;

			// Start the research
			MakeResearchStarted(pPlayerRes);
			psResFacilty->timeStartHold		= 0;
		}

	}
	// Finished/cancelled research
	else
	{
		// If they completed the research, we're done
		if (IsResearchCompleted(pPlayerRes))
		{
			return true;
		}

		// If they did not say what facility it was, look it up orselves
		if (!structRef)
		{
			// Go through the structs to find the one doing this topic
			for (psBuilding = apsStructLists[player]; psBuilding; psBuilding = psBuilding->psNext)
			{
				if (psBuilding->pStructureType->type == REF_RESEARCH
				 && psBuilding->status == SS_BUILT
				 && ((RESEARCH_FACILITY *) psBuilding->pFunctionality)->psSubject
				 && ((RESEARCH_FACILITY *) psBuilding->pFunctionality)->psSubject->ref - REF_RESEARCH_START == index)
				{
					break;
				}
			}
		}
		else
		{
			psBuilding = IdToStruct(structRef, player);
		}

		// Stop the facility doing any research
		if (psBuilding)
		{
			cancelResearch(psBuilding, ModeImmediate);
			popStatusPending(*(RESEARCH_FACILITY *)psBuilding->pFunctionality);  // Research cancellation is no longer pending, as it's actually cancelling now.
		}
	}

	if (aiCheckAlliances(selectedPlayer, player))
	{
		intAlliedResearchChanged();
		intNotifyResearchButton(prevResearchState);
	}

	return true;
}
Beispiel #19
0
// ////////////////////////////////////////////////////////////////////////////
// receive droid creation information from other players
BOOL recvDroid(NETQUEUE queue)
{
	DROID_TEMPLATE* pT;
	DROID* psDroid;
	uint8_t player;
	uint32_t id;
	Position pos;
	uint32_t templateID;
	BOOL haveInitialOrders;
	INITIAL_DROID_ORDERS initialOrders;

	NETbeginDecode(queue, GAME_DROID);
	{
		NETuint8_t(&player);
		NETuint32_t(&id);
		NETPosition(&pos);
		NETuint32_t(&templateID);
		NETbool(&haveInitialOrders);
		if (haveInitialOrders)
		{
			NETuint32_t(&initialOrders.secondaryOrder);
			NETint32_t(&initialOrders.moveToX);
			NETint32_t(&initialOrders.moveToY);
			NETuint32_t(&initialOrders.factoryId);  // For making scripts happy.
		}

		pT = IdToTemplate(templateID, player);
	}
	NETend();

	ASSERT( player < MAX_PLAYERS, "invalid player %u", player);

	debug(LOG_LIFE, "<=== getting Droid from %u id of %u ",player,id);
	if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight))
	{
		debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y,
				queue.index, player, isHumanPlayer(player) ? "Human" : "AI");
		return false;
	}

	// If we can not find the template ask for the entire droid instead
	if (!pT)
	{
		debug(LOG_ERROR, "Packet from %d refers to non-existent template %u, [%s : p%d]",
				queue.index, templateID, isHumanPlayer(player) ? "Human" : "AI", player);
		return false;
	}

	// Create that droid on this machine.
	psDroid = reallyBuildDroid(pT, pos.x, pos.y, player, false);

	// If we were able to build the droid set it up
	if (psDroid)
	{
		psDroid->id = id;
		addDroid(psDroid, apsDroidLists);

		if (haveInitialOrders)
		{
			psDroid->secondaryOrder = initialOrders.secondaryOrder;
			orderDroidLoc(psDroid, DORDER_MOVE, initialOrders.moveToX, initialOrders.moveToY, ModeImmediate);
			cbNewDroid(IdToStruct(initialOrders.factoryId, ANYPLAYER), psDroid);
		}
	}
	else
	{
		debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index,
			player, isHumanPlayer(player) ? "Human" : "AI");
#ifdef DEBUG
		CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync"));
#endif
		return false;
	}

	return true;
}
Beispiel #20
0
// ////////////////////////////////////////////////////////////////////////////
// receive droid creation information from other players
bool recvDroid(NETQUEUE queue)
{
	DROID_TEMPLATE t, *pT = &t;
	DROID *psDroid;
	uint8_t player;
	uint32_t id;
	Position pos;
	bool haveInitialOrders;
	INITIAL_DROID_ORDERS initialOrders;

	NETbeginDecode(queue, GAME_DEBUG_ADD_DROID);
	{
		int32_t droidType;

		NETuint8_t(&player);
		NETuint32_t(&id);
		NETPosition(&pos);
		NETqstring(pT->name);
		pT->id = pT->name;
		NETint32_t(&droidType);
		NETuint8_t(&pT->asParts[COMP_BODY]);
		NETuint8_t(&pT->asParts[COMP_BRAIN]);
		NETuint8_t(&pT->asParts[COMP_PROPULSION]);
		NETuint8_t(&pT->asParts[COMP_REPAIRUNIT]);
		NETuint8_t(&pT->asParts[COMP_ECM]);
		NETuint8_t(&pT->asParts[COMP_SENSOR]);
		NETuint8_t(&pT->asParts[COMP_CONSTRUCT]);
		NETint8_t(&pT->numWeaps);
		for (int i = 0; i < pT->numWeaps; i++)
		{
			NETuint8_t(&pT->asWeaps[i]);
		}
		NETbool(&haveInitialOrders);
		if (haveInitialOrders)
		{
			NETuint32_t(&initialOrders.secondaryOrder);
			NETint32_t(&initialOrders.moveToX);
			NETint32_t(&initialOrders.moveToY);
			NETuint32_t(&initialOrders.factoryId);  // For making scripts happy.
		}
		pT->droidType = (DROID_TYPE)droidType;
	}
	NETend();

	if (!getDebugMappingStatus() && bMultiPlayer)
	{
		debug(LOG_WARNING, "Failed to add droid for player %u.", NetPlay.players[queue.index].position);
		return false;
	}

	ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player);

	debug(LOG_LIFE, "<=== getting Droid from %u id of %u ", player, id);
	if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight))
	{
		debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y,
		      queue.index, player, isHumanPlayer(player) ? "Human" : "AI");
		return false;
	}

	// Create that droid on this machine.
	psDroid = reallyBuildDroid(pT, pos, player, false);

	// If we were able to build the droid set it up
	if (psDroid)
	{
		psDroid->id = id;
		addDroid(psDroid, apsDroidLists);

		if (haveInitialOrders)
		{
			psDroid->secondaryOrder = initialOrders.secondaryOrder;
			psDroid->secondaryOrderPending = psDroid->secondaryOrder;
			orderDroidLoc(psDroid, DORDER_MOVE, initialOrders.moveToX, initialOrders.moveToY, ModeImmediate);
			cbNewDroid(IdToStruct(initialOrders.factoryId, ANYPLAYER), psDroid);
		}

		syncDebugDroid(psDroid, '+');
	}
	else
	{
		debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index,
		      player, isHumanPlayer(player) ? "Human" : "AI");
#ifdef DEBUG
		CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync"));
#endif
		return false;
	}

	return true;
}