Remove legacy synch code.

Some of it would run in the case of desynchs, but didn't help with anything.
master
Cyp 2012-02-12 18:05:18 +01:00
parent a369971dbf
commit 24db01ae10
21 changed files with 0 additions and 990 deletions

View File

@ -452,8 +452,3 @@ void setPlayerGameTime(unsigned player, uint32_t time)
gameQueueTime[player] = time;
}
}
bool isInSync(void)
{
return !crcError;
}

View File

@ -201,6 +201,4 @@ void recvPlayerGameTime(NETQUEUE queue); ///< Processes a GAME_
bool checkPlayerGameTime(unsigned player); ///< Checks that we are not waiting for a GAME_GAME_TIME message from this player. (player can be NET_ALL_PLAYERS.)
void setPlayerGameTime(unsigned player, uint32_t time); ///< Sets the player's time.
bool isInSync(void); ///< Returns true unless there was a CRC mismatch between the last GAME_GAME_TIME messages.
#endif

View File

@ -118,16 +118,6 @@ bool NETstopLogging(void)
}
PHYSFS_write(pFileHandle, dash_line, strlen(dash_line), 1);
snprintf(buf, sizeof(buf), "sent/unsent DroidCheck %"PRIu64" / %"PRIu64"\n", sync_counter.sentDroidCheck, sync_counter.unsentDroidCheck);
PHYSFS_write(pFileHandle, buf, strlen(buf), 1);
snprintf(buf, sizeof(buf), "sent/unsent StructureCheck %"PRIu64" / %"PRIu64"\n", sync_counter.sentStructureCheck, sync_counter.unsentStructureCheck);
PHYSFS_write(pFileHandle, buf, strlen(buf), 1);
snprintf(buf, sizeof(buf), "sent/unsent PowerCheck %"PRIu64" / %"PRIu64"\n", sync_counter.sentPowerCheck, sync_counter.unsentPowerCheck);
PHYSFS_write(pFileHandle, buf, strlen(buf), 1);
snprintf(buf, sizeof(buf), "sent/unsent ScoreCheck %"PRIu64" / %"PRIu64"\n", sync_counter.sentScoreCheck, sync_counter.unsentScoreCheck);
PHYSFS_write(pFileHandle, buf, strlen(buf), 1);
snprintf(buf, sizeof(buf), "sent/unsent Ping %"PRIu64" / %"PRIu64"\n", sync_counter.sentPing, sync_counter.unsentPing);
PHYSFS_write(pFileHandle, buf, strlen(buf), 1);
PHYSFS_write(pFileHandle, dash_line, strlen(dash_line), 1);
if (!PHYSFS_close(pFileHandle))

View File

@ -3484,11 +3484,6 @@ const char *messageTypeToString(unsigned messageType_)
case GAME_STRUCTDEST: return "GAME_STRUCTDEST";
case GAME_FEATUREDEST: return "GAME_FEATUREDEST";
case GAME_RESEARCH: return "GAME_RESEARCH";
case GAME_CHECK_DROID: return "GAME_CHECK_DROID";
case GAME_CHECK_STRUCT: return "GAME_CHECK_STRUCT";
case GAME_CHECK_POWER: return "GAME_CHECK_POWER";
case GAME_DEMOLISH: return "GAME_DEMOLISH";
case GAME_DROIDEMBARK: return "GAME_DROIDEMBARK";
case GAME_DROIDDISEMBARK: return "GAME_DROIDDISEMBARK";
// End of redundant messages.
case GAME_MAX_TYPE: return "GAME_MAX_TYPE";

View File

@ -112,11 +112,6 @@ enum MESSAGE_TYPES
GAME_STRUCTDEST, ///< specify a strucutre to destroy, will be sent by all players at the same time, and have no effect, if synchronised.
GAME_FEATUREDEST, ///< destroy a game feature.
GAME_RESEARCH, ///< Research has been completed.
GAME_CHECK_DROID, ///< check & update bot position and damage.
GAME_CHECK_STRUCT, ///< check & update struct damage.
GAME_CHECK_POWER, ///< power levels for a player.
GAME_DEMOLISH, ///< a demolish is complete.
GAME_DROIDEMBARK, ///< droid embarked on a Transporter
GAME_DROIDDISEMBARK, ///< droid disembarked from a Transporter
// End of redundant messages.
GAME_MAX_TYPE ///< Maximum+1 valid GAME_ type, *MUST* be last.
@ -191,16 +186,6 @@ struct GAMESTRUCT
// the following structure is going to be used to track if we sync or not
struct SYNC_COUNTER
{
uint64_t sentDroidCheck;
uint64_t unsentDroidCheck;
uint64_t sentStructureCheck;
uint64_t unsentStructureCheck;
uint64_t sentPowerCheck;
uint64_t unsentPowerCheck;
uint64_t sentScoreCheck;
uint64_t unsentScoreCheck;
uint64_t sentPing;
uint64_t unsentPing;
uint16_t kicks;
uint16_t joins;
uint16_t left;

View File

@ -73,7 +73,6 @@ static CHEAT_ENTRY cheatCodes[] =
{"showlevelname", kf_ToggleLevelName}, // shows the current level name on screen
{"logical", kf_ToggleLogical}, //logical game updates separated from graphics updates.
{"pause", kf_TogglePauseMode}, // Pause the game.
{"sync me", kf_ForceSync},
{"power info", kf_PowerInfo},
{"reload me", kf_Reload}, // reload selected weapons immediately
{"desync me", kf_ForceDesync},

View File

@ -291,7 +291,6 @@ DROID::DROID(uint32_t id, unsigned player)
, action(DACTION_NONE)
, actionPos(0, 0)
, psCurAnim(NULL)
, gameCheckDroid(NULL)
{
order.type = DORDER_NONE;
order.pos = Vector2i(0, 0);
@ -345,8 +344,6 @@ DROID::~DROID()
clustRemoveObject((BASE_OBJECT *)psDroid);
free(sMove.asPath);
delete gameCheckDroid;
}
@ -413,15 +410,6 @@ void removeDroidBase(DROID *psDel)
syncDebugDroid(psDel, '#');
//ajl, inform others of destruction.
// Everyone else should be doing this at the same time, assuming it's in synch (so everyone sends a GAME_DROIDDEST message at once)...
if (!isInSync() && bMultiMessages
&& !(psDel->player != selectedPlayer && psDel->order.type == DORDER_RECYCLE))
{
ASSERT_OR_RETURN( , droidOnMap(psDel), "Asking other players to destroy droid driving off the map");
SendDestroyDroid(psDel);
}
/* remove animation if present */
if (psDel->psCurAnim != NULL)
{

View File

@ -122,7 +122,6 @@ struct DROID_TEMPLATE : public BASE_STATS
bool enabled; ///< Has been enabled
};
struct PACKAGED_CHECK;
class DROID_GROUP;
struct STRUCTURE;
@ -205,9 +204,6 @@ struct DROID : public BASE_OBJECT
/* anim data */
ANIM_OBJECT *psCurAnim;
SDWORD iAudioID;
// Synch checking
PACKAGED_CHECK *gameCheckDroid; ///< Last PACKAGED_CHECK, for synchronisation use only (see multisync.c). TODO Make synch perfect, so that this isn't needed at all.
};
#endif // __INCLUDED_DROIDDEF_H__

View File

@ -378,11 +378,6 @@ bool removeFeature(FEATURE *psDel)
ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer");
ASSERT_OR_RETURN(false, !psDel->died, "Feature already dead");
if (bMultiMessages && !ingame.localJoiningInProgress && !isInSync())
{
SendDestroyFeature(psDel); // inform other players of destruction
}
//remove from the map data
StructureBounds b = getStructureBounds(psDel);
for (int breadth = 0; breadth < b.size.y; ++breadth)

View File

@ -164,21 +164,6 @@ void kf_ToggleRadarJump( void )
// --------------------------------------------------------------------------
void kf_ForceSync( void )
{
DROID *psCDroid, *psNDroid;
for(psCDroid = apsDroidLists[selectedPlayer]; psCDroid; psCDroid = psNDroid)
{
psNDroid = psCDroid->psNext;
if (psCDroid->selected)
{
ForceDroidSync(psCDroid);
}
}
}
void kf_ForceDesync(void)
{
syncDebug("Oh no!!! I went out of sync!!!");

View File

@ -259,7 +259,6 @@ extern void kf_ToggleWatchWindow( void );
bool runningMultiplayer(void);
void kf_ForceSync( void );
void kf_ForceDesync(void);
void kf_PowerInfo( void );
void kf_BuildNextPage( void );

View File

@ -635,12 +635,6 @@ static void gameStateUpdate()
objmemUpdate();
// Do completely useless stuff.
if (!isInSync())
{
sendCheck(); // send some pointless checking info if we're doomed anyway
}
// Must end update, since we may or may not have ticked, and some message queue processing code may vary depending on whether it's in an update.
gameTimeUpdateEnd();
}

View File

@ -165,95 +165,6 @@ bool sendDroidSecondary(const DROID* psDroid, SECONDARY_ORDER sec, SECONDARY_STA
return true;
}
/** Broadcast droid and transporter loading information
*
* \sa recvDroidEmbark(),sendDroidDisEmbark(),recvDroidDisEmbark()
*/
bool sendDroidEmbark(const DROID* psDroid, const DROID* psTransporter)
{
if (!bMultiMessages)
return true;
NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROIDEMBARK);
{
uint8_t player = psDroid->player;
uint32_t droidID = psDroid->id;
uint32_t transporterID = psTransporter->id;
NETuint8_t(&player);
NETuint32_t(&droidID);
NETuint32_t(&transporterID);
}
return NETend();
}
/** Receive droid and transporter loading information
*
* \sa sendDroidEmbark(),sendDroidDisEmbark(),recvDroidDisEmbark()
*/
bool recvDroidEmbark(NETQUEUE queue)
{
DROID* psDroid;
DROID* psTransporterDroid;
bool bDroidRemoved;
NETbeginDecode(queue, GAME_DROIDEMBARK);
{
uint8_t player;
uint32_t droidID;
uint32_t transporterID;
NETuint8_t(&player);
NETuint32_t(&droidID);
NETuint32_t(&transporterID);
// we have to find the droid on our (local) list first.
psDroid = IdToDroid(droidID, player);
if (!psDroid)
{
NETend();
// Possible it already died? (sync error?)
debug(LOG_WARNING, "player's %d droid %d wasn't found?", player,droidID);
return false;
}
psTransporterDroid = IdToDroid(transporterID, player);
if (!psTransporterDroid)
{
NETend();
// Possible it already died? (sync error?)
debug(LOG_WARNING, "player's %d transport droid %d wasn't found?", player,transporterID);
return false;
}
if (psDroid == NULL)
{
// how can this happen?
return true;
}
// Take it out of the world without destroying it (just removes it from the droid list)
bDroidRemoved = droidRemove(psDroid, apsDroidLists);
// Init the order for when disembark
psDroid->order.type = DORDER_NONE;
setDroidTarget(psDroid, NULL);
psDroid->order.psStats = NULL;
if (bDroidRemoved)
{
// and now we need to add it to their transporter group!
psTransporterDroid->psGroup->add(psDroid);
}
else
{
// possible sync error?
debug(LOG_WARNING, "Eh? Where did unit %d go? Couldn't load droid onto transporter.", droidID);
}
}
NETend();
return true;
}
/** Broadcast that droid is being unloaded from a transporter
*
* \sa sendDroidEmbark(),recvDroidEmbark(),recvDroidDisEmbark()

View File

@ -582,15 +582,6 @@ bool recvMessage(void)
case GAME_DROIDDEST: // droid destroy
recvDestroyDroid(queue);
break;
case GAME_CHECK_DROID: // droid damage and position checks
recvDroidCheck(queue);
break;
case GAME_CHECK_STRUCT: // structure damage checks.
recvStructureCheck(queue);
break;
case GAME_CHECK_POWER: // Power level syncing.
recvPowerCheck(queue);
break;
case NET_TEXTMSG: // simple text message
recvTextMessage(queue);
break;
@ -609,9 +600,6 @@ bool recvMessage(void)
case GAME_STRUCTDEST: // structure destroy
recvDestroyStructure(queue);
break;
case GAME_DROIDEMBARK:
recvDroidEmbark(queue); //droid has embarked on a Transporter
break;
case GAME_DROIDDISEMBARK:
recvDroidDisEmbark(queue); //droid has disembarked from a Transporter
break;
@ -643,9 +631,6 @@ bool recvMessage(void)
case NET_PING: // diagnostic ping msg.
recvPing(queue);
break;
case GAME_DEMOLISH: // structure demolished.
recvDemolishFinished(queue);
break;
case GAME_RESEARCH: // some research has been done.
recvResearch(queue);
break;

View File

@ -82,22 +82,6 @@ enum STRUCTURE_INFO
STRUCTUREINFO_RELEASERESEARCH
};
struct PACKAGED_CHECK
{
uint32_t gameTime; ///< Game time that this synch check was made. Not touched by NETauto().
uint8_t player;
uint32_t droidID;
int32_t order;
uint32_t secondaryOrder;
uint32_t body;
uint32_t experience;
Position pos;
Rotation rot;
uint32_t targetID; ///< Defined iff order == DORDER_ATTACK.
uint16_t orderX; ///< Defined iff order == DORDER_MOVE.
uint16_t orderY; ///< Defined iff order == DORDER_MOVE.
};
// ////////////////////////////////////////////////////////////////////////////
// Game Options and stats.
extern MULTIPLAYERGAME game; // the game description.
@ -203,14 +187,12 @@ void sendStructureInfo (STRUCTURE *psStruct, STRUCTURE_INFO str
// droids . multibot
extern bool SendDroid (const DROID_TEMPLATE* pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrders);
extern bool SendDestroyDroid (const DROID* psDroid);
extern bool SendDemolishFinished(STRUCTURE *psS,DROID *psD);
void sendQueuedDroidInfo(void); ///< Actually sends the droid orders which were queued by SendDroidInfo.
void sendDroidInfo(DROID *psDroid, DroidOrder const &order, bool add);
extern bool SendCmdGroup (DROID_GROUP *psGroup, UWORD x, UWORD y, BASE_OBJECT *psObj);
extern bool sendDroidSecondary (const DROID* psDroid, SECONDARY_ORDER sec, SECONDARY_STATE state);
extern bool sendDroidEmbark (const DROID* psDroid, const DROID* psTransporter);
bool sendDroidDisembark(DROID const *psTransporter, DROID const *psDroid);
// Startup. mulitopt
@ -228,11 +210,9 @@ extern bool addTemplateToList(DROID_TEMPLATE *psNew, DROID_TEMPLATE **ppList);
void addTemplateBack(unsigned player, DROID_TEMPLATE *psNew);
// syncing.
void sendCheck(); //send/recv check info
extern bool sendScoreCheck (void); //score check only(frontend)
extern bool sendPing (void); // allow game to request pings.
extern bool ForceDroidSync(const DROID *droidToSend);
// multijoin
extern bool sendResearchStatus (STRUCTURE *psBuilding, UDWORD index, UBYTE player, bool bStart);

View File

@ -35,15 +35,10 @@ extern bool recvDestroyStructure (NETQUEUE queue);
extern bool recvBuildFinished (NETQUEUE queue);
extern bool recvTemplate (NETQUEUE queue);
extern bool recvDestroyFeature (NETQUEUE queue);
extern bool recvDemolishFinished (NETQUEUE queue);
extern bool recvPing (NETQUEUE queue);
extern bool recvRequestDroid (NETQUEUE queue);
extern bool recvTextMessage (NETQUEUE queue);
extern bool recvDroidEmbark (NETQUEUE queue);
extern bool recvDroidDisEmbark (NETQUEUE queue);
extern bool recvDroidCheck (NETQUEUE queue);
extern bool recvStructureCheck (NETQUEUE queue);
extern bool recvPowerCheck (NETQUEUE queue);
extern bool recvColourRequest (NETQUEUE queue);
extern bool recvPositionRequest (NETQUEUE queue);
extern void recvOptions (NETQUEUE queue);

View File

@ -151,53 +151,6 @@ bool recvBuildFinished(NETQUEUE queue)
}
// ////////////////////////////////////////////////////////////////////////////
// demolish message.
bool SendDemolishFinished(STRUCTURE *psStruct, DROID *psDroid)
{
NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEMOLISH);
// Send what is being demolish and who is doing it
NETuint32_t(&psStruct->id);
NETuint32_t(&psDroid->id);
return NETend();
}
bool recvDemolishFinished(NETQUEUE queue)
{
STRUCTURE *psStruct;
DROID *psDroid;
uint32_t structID, droidID;
NETbeginDecode(queue, GAME_DEMOLISH);
NETuint32_t(&structID);
NETuint32_t(&droidID);
NETend();
psStruct = IdToStruct(structID, ANYPLAYER);
psDroid = IdToDroid(droidID, ANYPLAYER);
if (!psDroid)
{
debug(LOG_ERROR, "recvDemolishFinished: Packet with bad droid ID received. Discarding!");
return false;
}
if (psStruct)
{
// Demolish it
// Should never get here, if in synch.
removeStruct(psStruct, true);
if (psDroid && psDroid->order.psStats)
{
// Update droid if reqd
psDroid->order.psStats = NULL;
}
}
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Inform others that a structure has been destroyed
bool SendDestroyStructure(STRUCTURE *s)

View File

@ -53,704 +53,16 @@
#include "multirecv.h"
#include "random.h"
static void NETauto(PACKAGED_CHECK *v)
{
NETauto(&v->player);
NETauto(&v->droidID);
NETauto(&v->order);
NETauto(&v->secondaryOrder);
NETauto(&v->body);
NETauto(&v->experience);
NETauto(&v->pos);
NETauto(&v->rot);
if (v->order == DORDER_ATTACK)
{
NETauto(&v->targetID);
}
else if (v->order == DORDER_MOVE)
{
NETauto(&v->orderX);
NETauto(&v->orderY);
}
}
// ////////////////////////////////////////////////////////////////////////////
// function definitions
static bool sendStructureCheck (void); //Structure
static PACKAGED_CHECK packageCheck(const DROID *pD);
static bool sendDroidCheck (void); //droids
static bool sendPowerCheck(void);
static UDWORD averagePing(void);
#define AV_PING_FREQUENCY 20000 // how often to update average pingtimes. in approx millisecs.
#define PING_FREQUENCY 4000 // how often to update pingtimes. in approx millisecs.
#define STRUCT_PERIOD 4000 // how often (ms) to send a structure check.
#define DROID_PERIOD 315 // how often (ms) to send droid checks
#define POWER_PERIOD 5000 // how often to send power levels
#define SCORE_FREQUENCY 108000 // how often to update global score.
static UDWORD PingSend[MAX_PLAYERS]; //stores the time the ping was called.
// ////////////////////////////////////////////////////////////////////////////
// test traffic level.
static bool okToSend(void)
{
// Update checks and go no further if any exceeded.
// removing the received check again ... add NETgetRecentBytesRecvd() to left hand side of equation if this works badly
if (NETgetRecentBytesSent() >= MAX_BYTESPERSEC)
{
return false;
}
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Droid checking info. keep position and damage in sync.
void sendCheck()
{
NETgetBytesSent(); // update stats.
NETgetBytesRecvd();
NETgetPacketsSent();
NETgetPacketsRecvd();
// dont send checks till all players are present.
for (unsigned i = 0; i < MAX_PLAYERS; ++i)
{
if(isHumanPlayer(i) && ingame.JoiningInProgress[i])
{
return;
}
}
// send Checks. note each send has it's own send criteria, so might not send anything.
// Priority is droids -> structures -> power -> score -> ping
sendDroidCheck();
sync_counter.sentDroidCheck++;
sendStructureCheck();
sync_counter.sentStructureCheck++;
sendPowerCheck();
sync_counter.sentPowerCheck++;
if(okToSend())
{
sendScoreCheck();
sync_counter.sentScoreCheck++;
}
else
{
sync_counter.unsentScoreCheck++;
}
if(okToSend())
{
sendPing();
sync_counter.sentPing++;
}
else
{
sync_counter.unsentPing++;
}
}
// ////////////////////////////////////////////////////////////////////////////
// pick a droid to send, NULL otherwise.
static DROID* pickADroid(void)
{
DROID *pD, *ret = NULL; // ret: dummy initialisation.
unsigned player = MAX_PLAYERS;
unsigned i;
// Pick a random player who has at least one droid.
for (i = 0; i < 200; ++i)
{
unsigned p = gameRand(MAX_PLAYERS);
if (apsDroidLists[p] != NULL)
{
player = p;
break;
}
}
if (player == MAX_PLAYERS)
{
return NULL; // No players have any droids, with high probability...
}
// O(n) where n is number of droids. Slow, but hard to beat on a linked list. (One call of a pick n droids function would be just as fast.)
i = 0;
for (pD = apsDroidLists[player]; pD != NULL; pD = pD->psNext)
{
if (gameRand(++i) == 0)
{
ret = pD;
}
}
return ret;
}
/** Force a droid to be synced
*
* Call this when you need to update the given droid right now.
*/
bool ForceDroidSync(const DROID* droidToSend)
{
uint8_t count = 1; // *always* one
PACKAGED_CHECK pc = packageCheck(droidToSend);
ASSERT(droidToSend != NULL, "NULL pointer passed");
debug(LOG_SYNC, "Force sync of droid %u from player %u", droidToSend->id, droidToSend->player);
NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_DROID);
NETuint8_t(&count);
NETuint32_t(&gameTime); // Send game time.
NETauto(&pc);
return NETend();
}
// ///////////////////////////////////////////////////////////////////////////
// send a droid info packet.
static bool sendDroidCheck(void)
{
DROID *pD, **ppD;
uint8_t i, count;
static UDWORD lastSent = 0; // Last time a struct was sent.
UDWORD toSend = 12;
if (lastSent > gameTime)
{
lastSent= 0;
}
// Only send a struct send if not done recently
if (gameTime - lastSent < DROID_PERIOD)
{
return true;
}
lastSent = gameTime;
if (!isInSync()) // Don't really send anything, unless out of synch.
{
NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_DROID);
}
// Allocate space for the list of droids to send
ppD = (DROID **)alloca(sizeof(DROID *) * toSend);
// Get the list of droids to sent
for (i = 0, count = 0; i < toSend; i++)
{
pD = pickADroid();
if (pD == NULL || (pD->gameCheckDroid != NULL && pD->gameCheckDroid->gameTime > gameTime))
{
continue; // Didn't find a droid, or droid was synched recently.
}
// If the droid is ours add it to the list
if (myResponsibility(pD->player))
{
ppD[count++] = pD;
}
delete pD->gameCheckDroid;
pD->gameCheckDroid = new PACKAGED_CHECK(packageCheck(pD));
}
if (!isInSync()) // Don't really send anything, unless out of synch.
{
// Send the number of droids to expect
NETuint8_t(&count);
NETuint32_t(&gameTime); // Send game time.
// Add the droids to the packet
for (i = 0; i < count; i++)
{
NETauto(ppD[i]->gameCheckDroid);
}
}
if (!isInSync()) // Don't really send anything, unless out of synch.
{
return NETend();
}
return true;
}
#define MIN_DELAY_BETWEEN_DROID_SYNCHS 5000 // Must be longer than maximum possible latency.
// ////////////////////////////////////////////////////////////////////////////
// Send a Single Droid Check message
static PACKAGED_CHECK packageCheck(const DROID *pD)
{
PACKAGED_CHECK pc;
memset(&pc, 0xFF, sizeof(pc)); // Dummy initialisation.
pc.gameTime = gameTime + MIN_DELAY_BETWEEN_DROID_SYNCHS;
pc.player = pD->player;
pc.droidID = pD->id;
pc.order = pD->order.type;
pc.secondaryOrder = pD->secondaryOrder;
pc.body = pD->body;
if (pD->body > pD->originalBody)
{
ASSERT(false, "Droid %u body is too high before synch, is %u, which is more than %u.", pc.droidID, pD->body, pD->originalBody);
}
pc.experience = pD->experience;
pc.pos = pD->pos;
pc.rot = pD->rot;
if (pD->order.type == DORDER_ATTACK)
{
pc.targetID = pD->order.psObj->id;
}
else if (pD->order.type == DORDER_MOVE)
{
pc.orderX = pD->order.pos.x;
pc.orderY = pD->order.pos.y;
}
return pc;
}
// ////////////////////////////////////////////////////////////////////////////
// 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;
NETauto(&pc);
// Find the droid in question
pD = IdToDroid(pc.droidID, pc.player);
if (!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.
}
PACKAGED_CHECK const pc2 = *pD->gameCheckDroid;
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);
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 MERGECOPYSYNC(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...
MERGEDELTA(pD->pos.x, pos.x, "d");
MERGEDELTA(pD->pos.y, pos.y, "d");
MERGEDELTA(pD->pos.z, pos.z, "d");
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((DROID_ORDER)pc2.order), getDroidOrderName((DROID_ORDER)pc.order), pc.orderX, pc.orderY);
// reroute the droid.
orderDroidLoc(pD, (DROID_ORDER)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((DROID_ORDER)pc2.order), getDroidOrderName((DROID_ORDER)pc.order), pc.targetID);
// remote droid is attacking, not here tho!
orderDroidObj(pD, (DROID_ORDER)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((DROID_ORDER)pc2.order), getDroidOrderName((DROID_ORDER)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.type = (DROID_ORDER)pc.order;
debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s.", pc.droidID, getDroidOrderName((DROID_ORDER)pc2.order), getDroidOrderName((DROID_ORDER)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.
}
MERGECOPYSYNC(pD->secondaryOrder, secondaryOrder, "u"); // The old code set this after changing orders, so doing that in case.
#undef MERGECOPYSYNC
#undef MERGEDELTA
pD->secondaryOrderPending = pD->secondaryOrder; // These droid checks are useless. TODO Completely remove recvDroidCheck and related code, since it's useless for synch, anyway?
syncDebugDroid(pD, '>');
// ...and repeat!
}
NETend();
return true;
}
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Structure Checking, to ensure smoke and stuff is consistent across machines.
// this func is recursive!
static STRUCTURE *pickAStructure(unsigned player)
{
STRUCTURE *pS, *ret = NULL;
unsigned i;
// O(n) where n is number of structures. Slow, but hard to beat on a linked list.
i = 0;
for (pS = apsStructLists[player]; pS != NULL; pS = pS->psNext)
{
if (gameRand(++i) == 0)
{
ret = pS;
}
}
return ret;
}
static uint32_t structureCheckLastSent = 0; // Last time a struct was sent
static uint32_t structureCheckLastId[MAX_PLAYERS];
static uint32_t structureCheckLastBody[MAX_PLAYERS];
static Rotation structureCheckLastDirection[MAX_PLAYERS];
static uint32_t structureCheckLastType[MAX_PLAYERS];
// ////////////////////////////////////////////////////////////////////////
// Send structure information.
static bool sendStructureCheck(void)
{
uint8_t player;
if (structureCheckLastSent > gameTime)
{
structureCheckLastSent = 0;
}
// Only send a struct send if not done recently
if (gameTime - structureCheckLastSent < STRUCT_PERIOD)
{
return true;
}
structureCheckLastSent = gameTime;
for (player = 0; player < MAX_PLAYERS; ++player)
{
STRUCTURE *pS = pickAStructure(player);
bool hasCapacity = true;
uint8_t capacity;
// Only send info about complete buildings
if (pS == NULL || pS->status != SS_BUILT)
{
structureCheckLastId[player] = 0;
continue;
}
switch (pS->pStructureType->type)
{
case REF_RESEARCH:
capacity = pS->pFunctionality->researchFacility.capacity;
break;
case REF_FACTORY:
case REF_VTOL_FACTORY:
capacity = pS->pFunctionality->factory.capacity;
break;
case REF_POWER_GEN:
capacity = pS->pFunctionality->powerGenerator.capacity;
default:
hasCapacity = false;
break;
}
structureCheckLastId[player] = pS->id;
structureCheckLastBody[player] = pS->body;
structureCheckLastDirection[player] = pS->rot;
structureCheckLastType[player] = pS->pStructureType->type;
if (myResponsibility(player))
{
if (!isInSync()) // Don't really send anything, unless out of synch.
{
NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_STRUCT);
NETuint8_t(&player);
NETuint32_t(&gameTime);
NETuint32_t(&pS->id);
NETuint32_t(&pS->body);
NETenum(&pS->pStructureType->type);
NETRotation(&pS->rot);
if (hasCapacity)
{
NETuint8_t(&capacity);
}
NETend();
}
}
}
return true;
}
// receive checking info about a structure and update local world state
bool recvStructureCheck(NETQUEUE queue)
{
uint32_t synchTime;
STRUCTURE *pS;
bool hasCapacity = true;
int j;
Rotation rot;
uint8_t player, ourCapacity;
uint32_t body;
uint32_t ref;
STRUCTURE_TYPE type = REF_HQ; // Dummy initialisation.
NETbeginDecode(queue, GAME_CHECK_STRUCT);
NETuint8_t(&player);
NETuint32_t(&synchTime);
NETuint32_t(&ref);
NETuint32_t(&body);
NETenum(&type);
NETRotation(&rot);
if (player >= MAX_PLAYERS)
{
debug(LOG_ERROR, "Bad GAME_CHECK_STRUCT received!");
NETend();
return false;
}
if (structureCheckLastSent != synchTime)
{
debug(LOG_ERROR, "We got a structure synch at the wrong time.");
}
if (ref != structureCheckLastId[player])
{
debug(LOG_ERROR, "We got a structure %u synch, but had chosen %u instead.", ref, structureCheckLastId[player]);
NETend();
return false;
}
// If the structure exists our job is easy
pS = IdToStruct(ref, player);
if (pS)
{
syncDebugStructure(pS, '<');
if (pS->pStructureType->type != structureCheckLastType[player] || type != structureCheckLastType[player])
{
debug(LOG_ERROR, "GAME_CHECK_STRUCT received, wrong structure type!");
NETend();
return false;
}
// Check its finished
if (pS->status != SS_BUILT)
{
pS->rot = rot;
pS->id = ref;
pS->status = SS_BUILT;
buildingComplete(pS);
}
// If the structure has a capacity
switch (pS->pStructureType->type)
{
case REF_RESEARCH:
ourCapacity = ((RESEARCH_FACILITY *) pS->pFunctionality)->capacity;
j = researchModuleStat;
break;
case REF_FACTORY:
case REF_VTOL_FACTORY:
ourCapacity = ((FACTORY *) pS->pFunctionality)->capacity;
j = factoryModuleStat;
break;
case REF_POWER_GEN:
ourCapacity = ((POWER_GEN *) pS->pFunctionality)->capacity;
j = powerModuleStat;
break;
default:
hasCapacity = false;
break;
}
// So long as the struct has a capacity fetch it from the packet
if (hasCapacity)
{
uint8_t actualCapacity = 0;
NETuint8_t(&actualCapacity);
// If our capacity is different upgrade ourself
for (; ourCapacity < actualCapacity; ourCapacity++)
{
debug(LOG_SYNC, "Structure %u out of synch, adding module.", ref);
buildStructure(&asStructureStats[j], pS->pos.x, pS->pos.y, pS->player, false);
// Check it is finished
if (pS->status != SS_BUILT)
{
pS->id = ref;
pS->status = SS_BUILT;
buildingComplete(pS);
}
}
}
#define MERGEDELTA(x, y, ya, z) if (y != ya) { debug(LOG_SYNC, "Structure %u out of synch, changing "#x" from %"z" to %"z".", ref, x, x + y - ya); x += y - ya; }
MERGEDELTA(pS->body, body, structureCheckLastBody[player], "u");
MERGEDELTA(pS->rot.direction, rot.direction, structureCheckLastDirection[player].direction, "d");
MERGEDELTA(pS->rot.pitch, rot.pitch, structureCheckLastDirection[player].pitch, "d");
MERGEDELTA(pS->rot.roll, rot.roll, structureCheckLastDirection[player].roll, "d");
#undef MERGEDELTA
syncDebugStructure(pS, '>');
}
else
{
debug(LOG_ERROR, "We got a structure %u synch, but can't find the structure.", ref);
}
NETend();
return true;
}
static uint32_t powerCheckLastSent = 0;
static int64_t powerCheckLastPower[MAX_PLAYERS];
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Power Checking. Send a power level check every now and again.
static bool sendPowerCheck()
{
uint8_t player;
if (powerCheckLastSent > gameTime)
{
powerCheckLastSent = 0;
}
// Only send if not done recently
if (gameTime - powerCheckLastSent < POWER_PERIOD)
{
return true;
}
powerCheckLastSent = gameTime;
for (player = 0; player < MAX_PLAYERS; ++player)
{
powerCheckLastPower[player] = getPrecisePower(player);
if (myResponsibility(player))
{
if (!isInSync()) // Don't really send anything, unless out of synch.
{
NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_POWER);
NETuint8_t(&player);
NETuint32_t(&gameTime);
NETint64_t(&powerCheckLastPower[player]);
NETend();
}
}
}
return true;
}
bool recvPowerCheck(NETQUEUE queue)
{
uint8_t player;
uint32_t synchTime;
int64_t power;
NETbeginDecode(queue, GAME_CHECK_POWER);
NETuint8_t(&player);
NETuint32_t(&synchTime);
NETint64_t(&power);
NETend();
if (powerCheckLastSent != synchTime)
{
debug(LOG_ERROR, "Power synch check out of synch!");
return false;
}
if (player >= MAX_PLAYERS)
{
debug(LOG_ERROR, "Bad GAME_CHECK_POWER packet: player is %d : %s",
(int)player, isHumanPlayer(player) ? "Human" : "AI");
return false;
}
if (power != powerCheckLastPower[player])
{
int64_t powerFrom = getPrecisePower(player);
int64_t powerTo = powerFrom + power - powerCheckLastPower[player];
debug(LOG_SYNC, "GAME_CHECK_POWER: Adjusting power for player %d (%s) from %lf to %lf",
(int)player, isHumanPlayer(player) ? "Human" : "AI", powerFrom/4294967296., powerTo/4294967296.);
syncDebug("Adjusting power for player %d (%s) from %"PRId64" to %"PRId64"", (int)player, isHumanPlayer(player) ? "Human" : "AI", powerFrom, powerTo);
setPrecisePower(player, powerTo);
}
return true;
}
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
@ -758,20 +70,6 @@ bool recvPowerCheck(NETQUEUE queue)
// We use setMultiStats() to broadcast the score when needed.
bool sendScoreCheck(void)
{
static UDWORD lastsent = 0;
if (lastsent > gameTime)
{
lastsent= 0;
}
if (gameTime - lastsent < SCORE_FREQUENCY)
{
return true;
}
lastsent = gameTime;
// Broadcast any changes in other players, but not in FRONTEND!!!
if (titleMode != MULTIOPTION && titleMode != MULTILIMIT)
{

View File

@ -723,11 +723,6 @@ void researchResult(UDWORD researchIndex, UBYTE player, bool bDisplay, STRUCTURE
ASSERT_OR_RETURN( , researchIndex < asResearch.size(), "Invalid research index %u", researchIndex);
if (!isInSync())
{
sendResearchStatus(NULL, researchIndex, player, false);
}
MakeResearchCompleted(&asPlayerResList[player][researchIndex]);
//check for structures to be made available

View File

@ -824,11 +824,6 @@ void structureBuild(STRUCTURE *psStruct, DROID *psDroid, int buildPoints, int bu
intBuildFinished(psDroid);
}
if (!isInSync() && bMultiMessages && myResponsibility(psStruct->player))
{
SendBuildFinished(psStruct);
}
//only play the sound if selected player
if (psDroid &&
psStruct->player == selectedPlayer
@ -3138,15 +3133,6 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
{
int prevState = intGetResearchState();
if(bMultiMessages)
{
if (myResponsibility(psStructure->player) && !isInSync())
{
// This message should have no effect if in synch.
SendResearch(psStructure->player, researchIndex, true);
}
}
//store the last topic researched - if its the best
if (psResFacility->psBestTopic == NULL)
{
@ -4636,12 +4622,6 @@ bool destroyStruct(STRUCTURE *psDel, unsigned impactTime)
CHECK_STRUCTURE(psDel);
if (bMultiMessages && !isInSync())
{
// Every player should be sending this message at once, and ignoring it later.
SendDestroyStructure(psDel);
}
/* Firstly, are we dealing with a wall section */
bMinor = psDel->pStructureType->type == REF_WALL || psDel->pStructureType->type == REF_WALLCORNER;

View File

@ -1425,12 +1425,6 @@ void transporterAddDroid(DROID *psTransporter, DROID *psDroidToAdd)
// adding to transporter unit's group list
psTransporter->psGroup->add(psDroidToAdd);
psDroidToAdd->selected = false; // Display in transporter interface.
if (bMultiMessages && !isInSync())
{
//inform all other players to update their local lists
sendDroidEmbark(psDroidToAdd,psTransporter);
}
}
else
{