Пример #1
0
// ////////////////////////////////////////////////////////////////////////////
// receive droid information form other players.
bool recvDroidInfo(NETQUEUE queue)
{
	NETbeginDecode(queue, GAME_DROIDINFO);
	{
		QueuedDroidInfo info;
		memset(&info, 0x00, sizeof(info));
		NETQueuedDroidInfo(&info);

		STRUCTURE_STATS *psStats = NULL;
		if (info.subType == LocOrder && (info.order == DORDER_BUILD || info.order == DORDER_LINEBUILD))
		{
			// Find structure target
			for (unsigned typeIndex = 0; typeIndex < numStructureStats; typeIndex++)
			{
				if (asStructureStats[typeIndex].ref == info.structRef)
				{
					psStats = asStructureStats + typeIndex;
					break;
				}
			}
		}

		switch (info.subType)
		{
			case ObjOrder:       syncDebug("Order=%s,%d(%d)", getDroidOrderName(info.order), info.destId, info.destType); break;
			case LocOrder:       syncDebug("Order=%s,(%d,%d)", getDroidOrderName(info.order), info.pos.x, info.pos.y); break;
			case SecondaryOrder: syncDebug("SecondaryOrder=%d,%08X", (int)info.secOrder, (int)info.secState); break;
		}

		DROID_ORDER_DATA sOrder = infoToOrderData(info, psStats);

		uint32_t num = 0;
		NETuint32_t(&num);

		for (unsigned n = 0; n < num; ++n)
		{
			// Get the next droid ID which is being given this order.
			uint32_t deltaDroidId = 0;
			NETuint32_t(&deltaDroidId);
			info.droidId += deltaDroidId;

			DROID *psDroid = IdToDroid(info.droidId, info.player);
			if (!psDroid)
			{
				debug(LOG_NEVER, "Packet from %d refers to non-existent droid %u, [%s : p%d]",
				      queue.index, info.droidId, isHumanPlayer(info.player) ? "Human" : "AI", info.player);
				syncDebug("Droid %d missing", info.droidId);
				continue;  // Can't find the droid, so skip this droid.
			}

			CHECK_DROID(psDroid);

			syncDebugDroid(psDroid, '<');

			switch (info.subType)
			{
				case ObjOrder:
				case LocOrder:
					/*
					* If the current order not is a command order and we are not a
					* commander yet are in the commander group remove us from it.
					*/
					if (hasCommander(psDroid))
					{
						psDroid->psGroup->remove(psDroid);
					}

					if (sOrder.psObj != TargetMissing)  // Only do order if the target didn't die.
					{
						if (!info.add)
						{
							orderDroidListEraseRange(psDroid, 0, psDroid->listSize + 1);  // Clear all non-pending orders, plus the first pending order (which is probably the order we just received).
							orderDroidBase(psDroid, &sOrder);  // Execute the order immediately (even if in the middle of another order.
						}
						else
						{
							orderDroidAdd(psDroid, &sOrder);   // Add the order to the (non-pending) list. Will probably overwrite the corresponding pending order, assuming all pending orders were written to the list.
						}
					}
					break;
				case SecondaryOrder:
					// Set the droids secondary order
					turnOffMultiMsg(true);
					secondarySetState(psDroid, info.secOrder, info.secState);
					turnOffMultiMsg(false);
					break;
			}

			syncDebugDroid(psDroid, '>');

			CHECK_DROID(psDroid);
		}
	}
	NETend();

	return true;
}
Пример #2
0
// ////////////////////////////////////////////////////////////////////////////
// receive droid information form other players.
BOOL recvDroidInfo(NETQUEUE queue)
{
	NETbeginDecode(queue, GAME_DROIDINFO);
	{
		QueuedDroidInfo info;
		memset(&info, 0x00, sizeof(info));
		NETQueuedDroidInfo(&info);

		STRUCTURE_STATS *psStats = NULL;
		if (info.order == DORDER_BUILD || info.order == DORDER_LINEBUILD)
		{
			// Find structure target
			for (unsigned typeIndex = 0; typeIndex < numStructureStats; typeIndex++)
			{
				if (asStructureStats[typeIndex].ref == info.structRef)
				{
					psStats = asStructureStats + typeIndex;
					break;
				}
			}
		}

		if (info.subType)
		{
			syncDebug("Order=%s,%d(%d)", getDroidOrderName(info.order), info.destId, info.destType);
		}
		else
		{
			syncDebug("Order=%s,(%d,%d)", getDroidOrderName(info.order), info.x, info.y);
		}

		DROID_ORDER_DATA sOrder;
		memset(&sOrder, 0x00, sizeof(sOrder));
		sOrder.order = info.order;
		sOrder.x = info.x;
		sOrder.y = info.y;
		sOrder.x2 = info.x2;
		sOrder.y2 = info.y2;
		sOrder.direction = info.direction;
		sOrder.psObj = processDroidTarget(info.destType, info.destId);
		sOrder.psStats = (BASE_STATS *)psStats;

		uint32_t num = 0;
		NETuint32_t(&num);

		for (unsigned n = 0; n < num; ++n)
		{
			// Get the next droid ID which is being given this order.
			uint32_t deltaDroidId = 0;
			NETuint32_t(&deltaDroidId);
			info.droidId += deltaDroidId;

			DROID *psDroid = NULL;
			if (!IdToDroid(info.droidId, ANYPLAYER, &psDroid))
			{
				debug(LOG_NEVER, "Packet from %d refers to non-existent droid %u, [%s : p%d]",
				      queue.index, info.droidId, isHumanPlayer(info.player) ? "Human" : "AI", info.player);
				syncDebug("Droid %d missing", info.droidId);
				continue;  // Can't find the droid, so skip this droid.
			}

			CHECK_DROID(psDroid);

			syncDebugDroid(psDroid, '<');

			psDroid->waitingForOwnReceiveDroidInfoMessage = false;

			/*
			* If the current order not is a command order and we are not a
			* commander yet are in the commander group remove us from it.
			*/
			if (hasCommander(psDroid))
			{
				grpLeave(psDroid->psGroup, psDroid);
			}

			if (sOrder.psObj != TargetMissing)  // Only do order if the target didn't die.
			{
				orderDroidBase(psDroid, &sOrder);
			}

			syncDebugDroid(psDroid, '>');

			CHECK_DROID(psDroid);
		}
	}
	NETend();

	return true;
}
Пример #3
0
// ////////////////////////////////////////////////////////////////////////////
// receive a check and update the local world state accordingly
BOOL recvDroidCheck(NETQUEUE queue)
{
	uint8_t		count;
	int		i;
	uint32_t        synchTime;

	NETbeginDecode(queue, GAME_CHECK_DROID);

		// Get the number of droids to expect
		NETuint8_t(&count);
		NETuint32_t(&synchTime);  // Get game time.

		for (i = 0; i < count; i++)
		{
			DROID *         pD;
			PACKAGED_CHECK  pc, pc2;
			Position        precPos;

			NETPACKAGED_CHECK(&pc);

			// Find the droid in question
			if (!IdToDroid(pc.droidID, pc.player, &pD))
			{
				NETlogEntry("Recvd Unknown droid info. val=player", SYNC_FLAG, pc.player);
				debug(LOG_SYNC, "Received checking info for an unknown (as yet) droid. player:%d ref:%d", pc.player, pc.droidID);
				continue;
			}

			syncDebugDroid(pD, '<');

			if (pD->gameCheckDroid == NULL)
			{
				debug(LOG_SYNC, "We got a droid %u synch, but we couldn't find the droid!", pc.droidID);
				continue;  // Can't synch, since we didn't save data to be able to calculate a delta.
			}

			pc2 = *(PACKAGED_CHECK *)pD->gameCheckDroid;  // pc2 should be declared here, as const.

			if (pc2.gameTime != synchTime + MIN_DELAY_BETWEEN_DROID_SYNCHS)
			{
				debug(LOG_SYNC, "We got a droid %u synch, but we didn't choose the same droid to synch.", pc.droidID);
				((PACKAGED_CHECK *)pD->gameCheckDroid)->gameTime = synchTime + MIN_DELAY_BETWEEN_DROID_SYNCHS;  // Get droid synch time back in synch.
				continue;  // Can't synch, since we didn't save data to be able to calculate a delta.
			}

#define MERGECOPY(x, y, z)  if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z" to %"z".", pc.droidID, x, pc.y);             x = pc.y; }
#define MERGEDELTA(x, y, z) if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z" to %"z".", pc.droidID, x, x + pc.y - pc2.y); x += pc.y - pc2.y; }
			// player not synched here...
			precPos = droidGetPrecisePosition(pD);
			MERGEDELTA(precPos.x, pos.x, "d");
			MERGEDELTA(precPos.y, pos.y, "d");
			MERGEDELTA(precPos.z, pos.z, "d");
			droidSetPrecisePosition(pD, precPos);
			MERGEDELTA(pD->rot.direction, rot.direction, "d");
			MERGEDELTA(pD->rot.pitch, rot.pitch, "d");
			MERGEDELTA(pD->rot.roll, rot.roll, "d");
			MERGEDELTA(pD->body, body, "u");
			if (pD->body > pD->originalBody)
			{
				pD->body = pD->originalBody;
				debug(LOG_SYNC, "Droid %u body was too high after synch, reducing to %u.", pc.droidID, pD->body);
			}
			MERGEDELTA(pD->experience, experience, "u");

			if (pc.pos.x != pc2.pos.x || pc.pos.y != pc2.pos.y)
			{
				// snap droid(if on ground) to terrain level at x,y.
				if ((asPropulsionStats + pD->asBits[COMP_PROPULSION].nStat)->propulsionType != PROPULSION_TYPE_LIFT)  // if not airborne.
				{
					pD->pos.z = map_Height(pD->pos.x, pD->pos.y);
				}
			}

			// Doesn't cover all cases, but at least doesn't actively break stuff randomly.
			switch (pc.order)
			{
				case DORDER_MOVE:
					if (pc.order != pc2.order || pc.orderX != pc2.orderX || pc.orderY != pc2.orderY)
					{
						debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%d, %d).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.orderX, pc.orderY);
						// reroute the droid.
						orderDroidLoc(pD, pc.order, pc.orderX, pc.orderY, ModeImmediate);
					}
					break;
				case DORDER_ATTACK:
					if (pc.order != pc2.order || pc.targetID != pc2.targetID)
					{
						BASE_OBJECT *obj = IdToPointer(pc.targetID, ANYPLAYER);
						if (obj != NULL)
						{
							debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%u).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.targetID);
							// remote droid is attacking, not here tho!
							orderDroidObj(pD, pc.order, IdToPointer(pc.targetID, ANYPLAYER), ModeImmediate);
						}
						else
						{
							debug(LOG_SYNC, "Droid %u out of synch, would change order from %s to %s(%u), but can't find target.", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.targetID);
						}
					}
					break;
				case DORDER_NONE:
				case DORDER_GUARD:
					if (pc.order != pc2.order)
					{
						DROID_ORDER_DATA sOrder;
						memset(&sOrder, 0, sizeof(DROID_ORDER_DATA));
						sOrder.order = pc.order;

						debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s.", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order));
						turnOffMultiMsg(true);
						moveStopDroid(pD);
						orderDroidBase(pD, &sOrder);
						turnOffMultiMsg(false);
					}
					break;
				default:
					break;  // Don't know what to do, but at least won't be actively breaking anything.
			}

			MERGECOPY(pD->secondaryOrder, secondaryOrder, "u");  // The old code set this after changing orders, so doing that in case.
#undef MERGECOPY
#undef MERGEDELTA

			syncDebugDroid(pD, '>');

			// ...and repeat!
		}

	NETend();

	return true;
}