Remove legacy synch code.
Some of it would run in the case of desynchs, but didn't help with anything.master
parent
a369971dbf
commit
24db01ae10
|
@ -452,8 +452,3 @@ void setPlayerGameTime(unsigned player, uint32_t time)
|
|||
gameQueueTime[player] = time;
|
||||
}
|
||||
}
|
||||
|
||||
bool isInSync(void)
|
||||
{
|
||||
return !crcError;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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!!!");
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue