Better Netplay reset and abort handling. Some small other fixes.

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2571 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
meep-eep
2006-12-06 03:39:12 +00:00
parent 66a9b84837
commit 7958a9e87f
32 changed files with 815 additions and 160 deletions
+1
View File
@@ -1,4 +1,5 @@
Changes towards version 0.6:
- Better abort and disconnect handling for Netplay - SvdB
- Menu sounds in Setup track rest of game (#922), from Nic - Michael
- Shifted the Mouse Error to a Popup Window, moved the message to
starcon.txt for translators - Michael
+34 -2
View File
@@ -2261,8 +2261,8 @@ Awaiting incoming connection
#(Attempting outgoing connection...)
Attempting outgoing connection
#(Connected. Press RIGHT to disconnect.)
Connected. Change setting to disconnect.
#(Connected. Change the control method to disconnect.)
Connected. Change the control method to disconnect.
#(Confirmation cancelled. Press FIRE to reconfirm.)
@@ -2324,20 +2324,52 @@ Top player changed something -- need to reconfirm.
#(Press SPACE to cancel)
Press SPACE to cancel
#(Connect to remote host)
Connect to remote host
#(Wait for incoming connection)
Wait for incoming connection
#(Cancel)
Cancel
#(Host)
Host
#(Port)
Port
#(Net Delay)
Net Delay
#(Disconnect for an unspecified reason.)
Disconnect for an unspecified reason.
#(Connection aborted due to version mismatch.)
Connection aborted due to version mismatch.
#(Connection aborted due to an internal protocol error.)
Connection aborted due to an internal protocol error.
#(Game aborted for an unspecified reason.)
Game aborted for an unspecified reason.
#(Game aborted due to loss of synchronisation.)
Game aborted due to loss of synchronisation.
#(Game aborted by the remote player.)
Game aborted by the remote player.
+10 -2
View File
@@ -1,4 +1,4 @@
There are three types of negotiations used to synchronised the parties
There are several types of negotiations used to synchronised the parties
of a network connection.
- Continue when we know the other is ready ("Ready")
@@ -11,7 +11,8 @@ of a network connection.
This is used to end a state where both parties are modifying
common data. Both parties have to agree with the data for either
party to continue.
- Reset a connection. This is used to abort a game in progress and return
to the fleet setup menu.
============================================================================
@@ -199,6 +200,13 @@ I also check whether it is possible for packets to arrive that
aren't expected.
============================================================================
"Reset" negotiation.
See src/sc2code/netplay/proto.c
============================================================================
Battle ending negotiation.
-3
View File
@@ -117,9 +117,6 @@ To put in the announcement of Netplay:
Bugs and todos unrelated to netplay.
- When you insert a new ship, the cursor moves to the next square,
but the picture at the right doesn't change.
- The "Battle!" icon is not positioned correctly.
- other player being able to choose the next ship after 3 seconds
of inactivity
- DoRunAway() shouldn't be handled in ProcessInput()
+8
View File
@@ -2604,6 +2604,14 @@ SOURCE=..\sc2code\netplay\proto\ready.c
SOURCE=..\sc2code\netplay\proto\ready.h
# End Source File
# Begin Source File
SOURCE=..\sc2code\netplay\proto\reset.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\netplay\proto\reset.h
# End Source File
# End Group
# End Group
+42 -10
View File
@@ -47,6 +47,12 @@ size_t battleInputOrder[NUM_SIDES];
#ifdef NETPLAY
BattleFrameCounter battleFrameCount;
// Used for synchronisation purposes during netplay.
COUNT currentDeadSide;
// When a ship has been destroyed, each side of a network
// connection waits until the other side is ready.
// When two ships die at the same time, this is handled for one
// ship after the other. This variable indicate for which player
// we're currently doing this.
#endif
static BOOLEAN
@@ -158,7 +164,7 @@ ProcessInput (void)
JournalInput (InputState);
#endif /* CREATE_JOURNAL */
#ifdef NETPLAY
if (PlayerControl[cur_player] & HUMAN_CONTROL)
if (!(PlayerControl[cur_player] & NETWORK_CONTROL))
{
BattleInputBuffer *bib = getBattleInputBuffer(cur_player);
sendBattleInputConnections (InputState);
@@ -278,8 +284,11 @@ DoBattle (BATTLE_STATE *bs)
if (battleFrameCount >= delay
&& (battleFrameCount - delay) % NETPLAY_CHECKSUM_INTERVAL == 0)
{
if (!verifyChecksums (battleFrameCount - delay))
if (!(GLOBAL (CurrentActivity) & CHECK_ABORT))
if (!verifyChecksums (battleFrameCount - delay)) {
GLOBAL(CurrentActivity) |= CHECK_ABORT;
resetConnections(ResetReason_syncLoss);
}
}
}
#endif
@@ -440,24 +449,32 @@ Battle (void)
CountLinks (&race_q[1])
);
if (!selectAllShips (num_ships))
goto AbortBattle;
BattleSong (TRUE);
bs.NextTime = 0;
setupBattleInputOrder ();
#ifdef NETPLAY
initBattleInputBuffers ();
#ifdef NETPLAY_CHECKSUM
initChecksumBuffers ();
#endif
#endif /* NETPLAY_CHECKSUM */
battleFrameCount = 0;
currentDeadSide = (COUNT)~0;
#endif /* NETPLAY */
if (!selectAllShips (num_ships)) {
GLOBAL (CurrentActivity) |= CHECK_ABORT;
goto AbortBattle;
}
BattleSong (TRUE);
bs.NextTime = 0;
#ifdef NETPLAY
initBattleStateDataConnections ();
{
bool allOk = negotiateReadyConnections (true, NetState_inBattle);
if (!allOk)
if (!allOk) {
GLOBAL (CurrentActivity) |= CHECK_ABORT;
goto AbortBattle;
}
}
#endif /* NETPLAY */
bs.InputFunc = DoBattle;
bs.first_time = (BOOLEAN)(LOBYTE (GLOBAL (CurrentActivity)) ==
@@ -468,11 +485,26 @@ Battle (void)
LockMutex (GraphicsLock);
AbortBattle:
if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE &&
(GLOBAL (CurrentActivity) & CHECK_ABORT))
{
// Do not return to the main menu when a game is aborted,
// (just to the supermelee menu).
UnlockMutex (GraphicsLock);
waitResetConnections(NetState_inSetup);
// A connection may already be in inSetup (set from
// GetMeleeStarship). This is not a problem, although
// it will generate a warning in debug mode.
LockMutex (GraphicsLock);
GLOBAL (CurrentActivity) &= ~CHECK_ABORT;
}
#ifdef NETPLAY
uninitBattleInputBuffers();
#ifdef NETPLAY_CHECKSUM
uninitChecksumBuffers ();
#endif
#endif /* NETPLAY_CHECKSUM */
#endif /* NETPLAY */
StopMusic ();
+1
View File
@@ -25,6 +25,7 @@ extern BOOLEAN instantVictory;
#ifdef NETPLAY
typedef DWORD BattleFrameCounter;
extern BattleFrameCounter battleFrameCount;
extern COUNT currentDeadSide;
#endif
extern BOOLEAN Battle (void);
+2
View File
@@ -95,6 +95,7 @@ typedef struct state
} STATE;
typedef STATE *PSTATE;
// Any physical object in the simulation.
typedef struct element
{
HELEMENT pred, succ;
@@ -116,6 +117,7 @@ typedef struct element
STATE current, next;
PVOID pParent;
// The ship this element belongs to.
HELEMENT hTarget;
} ELEMENT;
typedef ELEMENT *PELEMENT;
+1 -1
View File
@@ -923,7 +923,7 @@ enum
START_INTERPLANETARY = MAKE_WORD (0, (1 << 3)),
CHECK_LOAD = MAKE_WORD (0, (1 << 4)),
CHECK_RESTART = MAKE_WORD (0, (1 << 5)),
CHECK_ABORT = MAKE_WORD (0, (1 << 6))
CHECK_ABORT = MAKE_WORD (0, (1 << 6)),
};
typedef UWORD ACTIVITY;
+193 -73
View File
@@ -575,6 +575,7 @@ DrawPickIcon (COUNT iship, BYTE DrawErase)
#ifdef NETPLAY
// This function is generic. It should probably be moved to elsewhere.
// The caller should hold the GraphicsLock.
static void
multiLineDrawText(TEXT *textIn, RECT *clipRect) {
RECT oldRect;
@@ -701,6 +702,7 @@ UpdateMeleeStatusMessage (ssize_t player)
#endif /* NETPLAY */
// XXX: this function is called when the current selection is blinking off.
// The caller should hold the GraphicsLock.
static void
Deselect (BYTE opt)
{
@@ -760,6 +762,7 @@ Deselect (BYTE opt)
}
// XXX: this function is called when the current selection is blinking off.
// The caller should hold the GraphicsLock.
static void
Select (BYTE opt)
{
@@ -2303,7 +2306,6 @@ DoConnectingDialog (PMELEE_STATE pMS)
if ((status == NetState_init) ||
(status == NetState_inSetup))
{
RECT r;
/* Connection complete! */
PlayerControl[which_side] = NETWORK_CONTROL | STANDARD_RATING;
SetPlayerInput ();
@@ -2349,7 +2351,8 @@ check_for_disconnections (PMELEE_STATE pMS)
{
PlayerControl[player] = HUMAN_CONTROL & STANDARD_RATING;
DrawControls (player, FALSE);
log_add (log_User, "Player %d has disconnected; shifting controls\n", player);
log_add (log_User, "Player %d has disconnected; shifting "
"controls\n", player);
changed = TRUE;
}
}
@@ -2358,6 +2361,8 @@ check_for_disconnections (PMELEE_STATE pMS)
{
SetPlayerInput ();
}
(void) pMS;
}
#endif
@@ -2852,6 +2857,88 @@ InitPreBuilt (PMELEE_STATE pMS)
}
}
int
LoadMeleeConfig (PMELEE_STATE pMS)
{
uio_Stream *load_fp;
int status;
load_fp = res_OpenResFile (configDir, "melee.cfg", "rb");
if (!load_fp)
goto err;
if (LengthResFile (load_fp) != (1 + sizeof (TEAM_IMAGE)) * 2)
goto err;
status = GetResFileChar (load_fp);
if (status == -1)
goto err;
PlayerControl[0] = (BYTE)status;
status = ReadTeamImage (&pMS->TeamImage[0], load_fp);
if (status == -1)
goto err;
status = GetResFileChar (load_fp);
if (status == -1)
goto err;
PlayerControl[1] = (BYTE)status;
status = ReadTeamImage (&pMS->TeamImage[1], load_fp);
if (status == -1)
goto err;
res_CloseResFile (load_fp);
/* Do not allow netplay mode at the start. */
if (PlayerControl[0] & NETWORK_CONTROL)
PlayerControl[0] = HUMAN_CONTROL | STANDARD_RATING;
if (PlayerControl[1] & NETWORK_CONTROL)
PlayerControl[1] = HUMAN_CONTROL | STANDARD_RATING;
return 0;
err:
if (load_fp)
res_CloseResFile (load_fp);
return -1;
}
int
WriteMeleeConfig (PMELEE_STATE pMS)
{
uio_Stream *save_fp;
save_fp = res_OpenResFile (configDir, "melee.cfg", "wb");
if (!save_fp)
goto err;
if (PutResFileChar (PlayerControl[0], save_fp) == -1)
goto err;
if (WriteTeamImage (&pMS->TeamImage[0], save_fp) == 0)
goto err;
if (PutResFileChar (PlayerControl[1], save_fp) == -1)
goto err;
if (WriteTeamImage (&pMS->TeamImage[1], save_fp) == 0)
goto err;
if (!res_CloseResFile (save_fp))
goto err;
return 0;
err:
if (save_fp)
{
res_CloseResFile (save_fp);
DeleteResFile (configDir, "melee.cfg");
}
return -1;
}
void
Melee (void)
{
@@ -2880,50 +2967,13 @@ Melee (void)
GameSounds = CaptureSound (LoadSound (GAME_SOUNDS));
LoadMeleeInfo (&MenuState);
{
uio_Stream *load_fp;
load_fp = res_OpenResFile (configDir, "melee.cfg", "rb");
if (load_fp)
{
int status;
if (LengthResFile (load_fp) != (1 + sizeof (TEAM_IMAGE)) * 2)
status = -1;
else if ((status = GetResFileChar (load_fp)) != -1)
{
PlayerControl[0] = (BYTE)status;
status = ReadTeamImage (&MenuState.TeamImage[0], load_fp);
if (status != -1)
{
status = GetResFileChar (load_fp);
if (status != -1)
{
PlayerControl[1] = (BYTE)status;
status = ReadTeamImage (
&MenuState.TeamImage[1], load_fp);
}
}
}
res_CloseResFile (load_fp);
if (status == -1)
load_fp = 0;
}
if (load_fp == 0)
if (LoadMeleeConfig (&MenuState) == -1)
{
PlayerControl[0] = HUMAN_CONTROL | STANDARD_RATING;
MenuState.TeamImage[0] = MenuState.PreBuiltList[0];
PlayerControl[1] = COMPUTER_CONTROL | STANDARD_RATING;
MenuState.TeamImage[1] = MenuState.PreBuiltList[1];
}
/* Do not allow netplay mode at the start. */
if (PlayerControl[0] & NETWORK_CONTROL)
PlayerControl[0] = HUMAN_CONTROL | STANDARD_RATING;
if (PlayerControl[1] & NETWORK_CONTROL)
PlayerControl[1] = HUMAN_CONTROL | STANDARD_RATING;
}
SetPlayerInput ();
teamStringChanged (&MenuState, 0);
teamStringChanged (&MenuState, 1);
@@ -2939,35 +2989,7 @@ Melee (void)
StopMusic ();
WaitForSoundEnd (TFBSOUND_WAIT_ALL);
{
uio_Stream *save_fp;
BOOLEAN err;
err = FALSE;
save_fp = res_OpenResFile (configDir, "melee.cfg", "wb");
if (save_fp)
{
if (PutResFileChar (PlayerControl[0], save_fp) == -1)
err = TRUE;
if (!err && WriteTeamImage (&MenuState.TeamImage[0],
save_fp) == 0)
err = TRUE;
if (!err && PutResFileChar (PlayerControl[1], save_fp) == -1)
err = TRUE;
if (!err && WriteTeamImage (&MenuState.TeamImage[1],
save_fp) == 0)
err = TRUE;
if (res_CloseResFile (save_fp) == 0)
err = TRUE;
}
else
err = TRUE;
if (err)
{
DeleteResFile (configDir, "melee.cfg");
}
}
WriteMeleeConfig (&MenuState);
FreeMeleeInfo (&MenuState);
DestroySound (ReleaseSound (GameSounds));
GameSounds = 0;
@@ -3083,6 +3105,7 @@ updateTeamName (PMELEE_STATE pMS, COUNT side, const char *name,
strncpy (pMS->TeamImage[side].TeamName, name, len);
pMS->TeamImage[side].TeamName[len] = '\0';
LockMutex (GraphicsLock);
#if 0 /* DTSHS_REPAIR does not combine with other options */
if (pMS->MeleeOption == EDIT_MELEE && pMS->side == side
&& pMS->row == NUM_MELEE_ROWS)
@@ -3090,6 +3113,7 @@ updateTeamName (PMELEE_STATE pMS, COUNT side, const char *name,
else
#endif
DrawTeamString (pMS, side, DTSHS_REPAIR);
UnlockMutex (GraphicsLock);
}
// Update a ship in a fleet as specified by a remote party.
@@ -3131,6 +3155,7 @@ updateFleetShip (PMELEE_STATE pMS, COUNT side, COUNT index, BYTE ship)
(pMS->side == side) && (index == selectedShipIndex);
// Ship to be updated is the currently selected one.
LockMutex (GraphicsLock);
if (ship == MELEE_NONE)
{
RECT r;
@@ -3148,12 +3173,14 @@ updateFleetShip (PMELEE_STATE pMS, COUNT side, COUNT index, BYTE ship)
// Reprint the team value:
//DrawTeamString (pMeleeState, side, DTSHS_NORMAL);
DrawTeamString (pMS, side, DTSHS_REPAIR);
UnlockMutex (GraphicsLock);
return true;
}
void
updateRandomSeed (PMELEE_STATE pMS, COUNT side, DWORD seed) {
updateRandomSeed (PMELEE_STATE pMS, COUNT side, DWORD seed)
{
TFB_SeedRandom (seed);
(void) pMS;
(void) side;
@@ -3161,51 +3188,144 @@ updateRandomSeed (PMELEE_STATE pMS, COUNT side, DWORD seed) {
// The remote player has done something which invalidates our confirmation.
void
confirmationCancelled(PMELEE_STATE pMS, COUNT side) {
confirmationCancelled(PMELEE_STATE pMS, COUNT side)
{
LockMutex (GraphicsLock);
if (side == 0)
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 16));
// "Bottom player changed something -- need to reconfirm."
else
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 17));
// "Top player changed something -- need to reconfirm."
UnlockMutex (GraphicsLock);
if (pMS->InputFunc == DoConfirmSettings)
pMS->InputFunc = DoMelee;
}
void
connectedFeedback (PMELEE_STATE pMS, COUNT side) {
LockMutex (GraphicsLock);
if (side == 0)
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 8));
// "Bottom player is connected."
else
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 9));
// "Top player is connected."
UnlockMutex (GraphicsLock);
PlayMenuSound (MENU_SOUND_INVOKED);
(void) pMS;
}
const char *
abortReasonString (NetplayResetReason reason)
{
switch (reason)
{
case AbortReason_unspecified:
return GAME_STRING (NETMELEE_STRING_BASE + 25);
// "Disconnect for an unspecified reason.'
case AbortReason_versionMismatch:
return GAME_STRING (NETMELEE_STRING_BASE + 26);
// "Connection aborted due to version mismatch."
case AbortReason_protocolError:
return GAME_STRING (NETMELEE_STRING_BASE + 27);
// "Connection aborted due to an internal protocol "
// "error."
}
return NULL;
// Should not happen.
}
void
errorFeedback (PMELEE_STATE pMS, COUNT side) {
abortFeedback (COUNT side, NetplayAbortReason reason)
{
const char *msg;
msg = abortReasonString (reason);
if (msg != NULL)
{
LockMutex (GraphicsLock);
DrawMeleeStatusMessage (msg);
UnlockMutex (GraphicsLock);
}
(void) side;
}
const char *
resetReasonString (NetplayResetReason reason)
{
switch (reason)
{
case ResetReason_unspecified:
return GAME_STRING (NETMELEE_STRING_BASE + 28);
// "Game aborted for an unspecified reason."
case ResetReason_syncLoss:
return GAME_STRING (NETMELEE_STRING_BASE + 29);
// "Game aborted due to loss of synchronisation."
case ResetReason_manualReset:
return GAME_STRING (NETMELEE_STRING_BASE + 30);
// "Game aborted by the remote player."
}
return NULL;
// Should not happen.
}
void
resetFeedback (COUNT side, NetplayResetReason reason, bool byRemote)
{
const char *msg;
GLOBAL (CurrentActivity) |= CHECK_ABORT;
if (reason == ResetReason_manualReset && !byRemote) {
// No message needed, the player initiated the reset.
return;
}
msg = resetReasonString (reason);
if (msg != NULL)
{
LockMutex (GraphicsLock);
DrawMeleeStatusMessage (msg);
UnlockMutex (GraphicsLock);
}
(void) side;
}
void
errorFeedback (PMELEE_STATE pMS, COUNT side)
{
LockMutex (GraphicsLock);
if (side == 0)
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 10));
// "Bottom player: connection failed."
else
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 11));
// "Top player: connection failed."
UnlockMutex (GraphicsLock);
(void) pMS;
}
void
closeFeedback (PMELEE_STATE pMS, COUNT side) {
closeFeedback (PMELEE_STATE pMS, COUNT side)
{
LockMutex (GraphicsLock);
if (side == 0)
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 12));
// "Bottom player: connection closed."
else
DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 13));
// "Top player: connection closed."
UnlockMutex (GraphicsLock);
(void) pMS;
}
#endif /* NETPLAY */
+4
View File
@@ -24,6 +24,8 @@
#include "libs/gfxlib.h"
#include "libs/sndlib.h"
#include "libs/reslib.h"
#include "netplay/packet.h"
// for NetplayAbortREason and NetplayResetReason.
typedef struct melee_state MELEE_STATE;
@@ -123,6 +125,8 @@ bool updateFleetShip (PMELEE_STATE pMS, COUNT side, COUNT index, BYTE ship);
void updateRandomSeed (PMELEE_STATE pMS, COUNT side, DWORD seed);
void confirmationCancelled(PMELEE_STATE pMS, COUNT side);
void connectedFeedback (PMELEE_STATE pMS, COUNT side);
void abortFeedback (COUNT side, NetplayAbortReason reason);
void resetFeedback (COUNT side, NetplayResetReason reason, bool byRemote);
void errorFeedback (PMELEE_STATE pMS, COUNT side);
void closeFeedback (PMELEE_STATE pMS, COUNT side);
+38 -5
View File
@@ -47,7 +47,8 @@ NetConnection *
NetConnection_open(int player, const NetplayPeerOptions *options,
NetConnection_ConnectCallback connectCallback,
NetConnection_CloseCallback closeCallback,
NetConnection_ErrorCallback errorCallback, void *extra) {
NetConnection_ErrorCallback errorCallback,
NetConnection_DeleteCallback deleteCallback, void *extra) {
NetConnection *conn;
conn = malloc(sizeof (NetConnection));
@@ -62,8 +63,11 @@ NetConnection_open(int player, const NetplayPeerOptions *options,
conn->connectCallback = connectCallback;
conn->closeCallback = closeCallback;
conn->errorCallback = errorCallback;
conn->deleteCallback = deleteCallback;
conn->readyCallback = NULL;
conn->readyCallbackArg = NULL;
conn->resetCallback = NULL;
conn->resetCallbackArg = NULL;
conn->readBuf = malloc(NETPLAY_READBUFSIZE);
conn->readEnd = conn->readBuf;
@@ -80,6 +84,8 @@ NetConnection_open(int player, const NetplayPeerOptions *options,
conn->stateFlags.handshake.canceling = false;
conn->stateFlags.ready.localReady = false;
conn->stateFlags.ready.remoteReady = false;
conn->stateFlags.reset.localReset = false;
conn->stateFlags.reset.remoteReset = false;
conn->stateFlags.agreement = Agreement_nothingAgreed;
conn->stateFlags.inputDelay = 0;
#ifdef NETPLAY_CHECKSUM
@@ -105,8 +111,22 @@ NetConnection_open(int player, const NetplayPeerOptions *options,
return conn;
}
static void
NetConnection_doDeleteCallback(NetConnection *conn) {
if (conn->deleteCallback != NULL) {
//NetConnection_incRef(conn);
conn->deleteCallback(conn);
//NetConnection_decRef(conn);
}
}
static void
NetConnection_delete(NetConnection *conn) {
NetConnection_doDeleteCallback(conn);
if (conn->stateData != NULL) {
NetConnectionStateData_release(conn->stateData);
conn->stateData = NULL;
}
free(conn->readBuf);
PacketQueue_uninit(&conn->queue);
free(conn);
@@ -133,10 +153,6 @@ NetConnection_doClose(NetConnection *conn) {
Netplay_doCloseCallback(conn);
NetConnection_setState(conn, NetState_unconnected);
if (conn->stateData != NULL) {
NetConnectionStateData_release(conn->stateData);
conn->stateData = NULL;
}
}
// Called when the NetDescriptor is shut down.
@@ -213,6 +229,23 @@ NetConnection_getReadyCallbackArg(const NetConnection *conn) {
return conn->readyCallbackArg;
}
void
NetConnection_setResetCallback(NetConnection *conn,
NetConnection_ResetCallback callback, void *arg) {
conn->resetCallback = callback;
conn->resetCallbackArg = arg;
}
NetConnection_ResetCallback
NetConnection_getResetCallback(const NetConnection *conn) {
return conn->resetCallback;
}
void *
NetConnection_getResetCallbackArg(const NetConnection *conn) {
return conn->resetCallbackArg;
}
void
NetConnection_setState(NetConnection *conn, NetState state) {
#ifdef NETPLAY_DEBUG
+26 -1
View File
@@ -33,8 +33,10 @@ typedef void (*NetConnection_ConnectCallback)(NetConnection *nd);
typedef void (*NetConnection_CloseCallback)(NetConnection *nd);
typedef void (*NetConnection_ErrorCallback)(NetConnection *nd,
const NetConnectionError *error);
typedef void (*NetConnection_DeleteCallback)(NetConnection *nd);
typedef void (*NetConnection_ReadyCallback)(NetConnection *conn, void *arg);
typedef void (*NetConnection_ResetCallback)(NetConnection *conn, void *arg);
#include "netstate.h"
#include "netoptions.h"
@@ -80,6 +82,11 @@ typedef struct {
bool remoteReady : 1;
} ReadyFlags;
typedef struct {
bool localReset : 1;
bool remoteReset : 1;
} ResetFlags;
// Which parameters have we both sides of a connection reached agreement on?
typedef struct {
bool randomSeed : 1;
@@ -108,6 +115,7 @@ typedef struct {
* during a connection. Undefined while not connected. */
HandShakeFlags handshake;
ReadyFlags ready;
ResetFlags reset;
Agreement agreement;
size_t inputDelay;
/* Used during negotiation of the actual inputDelay. This
@@ -135,6 +143,13 @@ struct NetConnection {
// Extra argument for readyCallback().
// XXX: when is this cleaned up if a connection is broken?
NetConnection_ResetCallback resetCallback;
// Called when a reset has been signalled and confirmed.
// Set by Netplay_localReset().
void *resetCallbackArg;
// Extra argument for resetCallback().
// XXX: when is this cleaned up if a connection is broken?
const NetplayPeerOptions *options;
PacketQueue queue;
#ifdef NETPLAY_STATISTICS
@@ -145,7 +160,10 @@ struct NetConnection {
#endif
NetConnection_ConnectCallback connectCallback;
NetConnection_CloseCallback closeCallback;
// Called when the NetConnection becomes disconnected.
NetConnection_ErrorCallback errorCallback;
NetConnection_DeleteCallback deleteCallback;
// Called when the NetConnection is destroyed.
uint8 *readBuf;
uint8 *readEnd;
NetConnectionStateData *stateData;
@@ -170,7 +188,8 @@ NetConnection *NetConnection_open(int player,
const NetplayPeerOptions *options,
NetConnection_ConnectCallback connectCallback,
NetConnection_CloseCallback closeCallback,
NetConnection_ErrorCallback errorCallback, void *extra);
NetConnection_ErrorCallback errorCallback,
NetConnection_DeleteCallback deleteCallback, void *extra);
void NetConnection_close(NetConnection *conn);
bool NetConnection_isConnected(const NetConnection *conn);
@@ -203,6 +222,12 @@ NetConnection_ReadyCallback NetConnection_getReadyCallback(
const NetConnection *conn);
void *NetConnection_getReadyCallbackArg(const NetConnection *conn);
void NetConnection_setResetCallback(NetConnection *conn,
NetConnection_ResetCallback callback, void *arg);
NetConnection_ResetCallback NetConnection_getResetCallback(
const NetConnection *conn);
void *NetConnection_getResetCallbackArg(const NetConnection *conn);
#endif /* _NETCONNECTION_H */
+161 -4
View File
@@ -28,6 +28,7 @@
#include "netplay/packetq.h"
#include "netplay/proto/npconfirm.h"
#include "netplay/proto/ready.h"
#include "netplay/proto/reset.h"
#include "build.h"
// for StarShipPlayer()
@@ -65,9 +66,13 @@ closeAllConnections(void) {
COUNT player;
for (player = 0; player < NUM_PLAYERS; player++)
if (netConnections[player] != NULL)
{
NetConnection *conn = netConnections[player];
if (conn != NULL && NetConnection_isConnected(conn))
closePlayerNetworkConnection(player);
}
}
size_t
getNumNetConnections(void) {
@@ -100,6 +105,9 @@ netInputBlocking(uint32 timeoutMs) {
timeoutMs = nextAlarmMs;
NetManager_process(&timeoutMs);
// This may cause more packets to be queued, hence the
// flushPacketQueues().
flushPacketQueues();
Alarm_process();
Callback_process();
@@ -183,6 +191,22 @@ connectionsLocalReady(NetConnection_ReadyCallback callback, void *arg) {
}
}
bool
allConnected(void) {
COUNT player;
for (player = 0; player < NUM_PLAYERS; player++)
{
NetConnection *conn = netConnections[player];
if (conn == NULL)
continue;
if (!NetConnection_isConnected(conn))
return false;
}
return true;
}
void
sendBattleInputConnections(BATTLE_INPUT_STATE input) {
COUNT player;
@@ -297,6 +321,11 @@ networkBattleInput(COUNT player, STARSHIPPTR StarShipPtr) {
return result;
}
static void
deleteConnectionCallback(NetConnection *conn) {
removeNetConnection(NetConnection_getPlayerNr(conn));
}
NetConnection *
openPlayerNetworkConnection(COUNT player, void *extra) {
NetConnection *conn;
@@ -305,7 +334,8 @@ openPlayerNetworkConnection(COUNT player, void *extra) {
conn = NetConnection_open(player,
&netplayOptions.peer[player], NetMelee_connectCallback,
NetMelee_closeCallback, NetMelee_errorCallback, extra);
NetMelee_closeCallback, NetMelee_errorCallback,
deleteConnectionCallback, extra);
addNetConnection(conn, player);
return conn;
@@ -321,7 +351,6 @@ closePlayerNetworkConnection(COUNT player) {
assert(netConnections[player] != NULL);
NetConnection_close(netConnections[player]);
removeNetConnection(player);
}
// If the callback function returns 'false', the function will immediately
@@ -392,6 +421,30 @@ setStateConnections(NetState state) {
(bool(*)(NetConnection *, void *)) setStateConnection, &state);
}
static bool
sendAbortConnection(NetConnection *conn, const NetplayAbortReason *reason) {
sendAbort(conn, *reason);
return true;
}
bool
sendAbortConnections(NetplayAbortReason reason) {
return forAllConnectedPlayers(
(bool(*)(NetConnection *, void *)) sendAbortConnection, &reason);
}
static bool
resetConnection(NetConnection *conn, const NetplayResetReason *reason) {
Netplay_localReset(conn, *reason);
return true;
}
bool
resetConnections(NetplayResetReason reason) {
return forAllConnectedPlayers(
(bool(*)(NetConnection *, void *)) resetConnection, &reason);
}
/////////////////////////////////////////////////////////////////////////////
typedef struct {
@@ -422,6 +475,7 @@ localReadyConnections(NetConnection_ReadyCallback readyCallback,
/////////////////////////////////////////////////////////////////////////////
#define NETWORK_POLL_DELAY (ONE_SECOND / 24)
typedef struct NegotiateReadyState NegotiateReadyState;
struct NegotiateReadyState {
@@ -437,7 +491,6 @@ struct NegotiateReadyState {
static BOOLEAN
negotiateReadyInputFunc(NegotiateReadyState *state) {
#define NETWORK_POLL_DELAY (ONE_SECOND / 24)
netInputBlocking(NETWORK_POLL_DELAY);
// The timing out is necessary so that immediate key presses get
// handled while we wait. If we could do without the timeout,
@@ -572,4 +625,108 @@ waitReady(NetConnection *conn) {
////////////////////////////////////////////////////////////////////////////
typedef struct WaitResetState WaitResetState;
struct WaitResetState {
// Common fields of INPUT_STATE_DESC, from which this structure
// "inherits".
BOOLEAN(*InputFunc)(PVOID pInputState);
COUNT MenuRepeatDelay;
NetConnection *conn;
NetState nextState;
bool done;
};
static BOOLEAN
waitResetInputFunc(WaitResetState *state) {
netInputBlocking(NETWORK_POLL_DELAY);
// The timing out is necessary so that immediate key presses get
// handled while we wait. If we could do without the timeout,
// we wouldn't even need waitResetInputFunc() and the
// DoInput() call.
// No need to call flushPacketQueues(); nothing needs to be sent
// right now.
if (!NetConnection_isConnected(state->conn))
return FALSE;
return !state->done;
}
// Called when both sides are reset.
static void
waitResetBothResetCallback(NetConnection *conn, void *arg) {
WaitResetState *state = (WaitResetState *) arg;
if (state->nextState != (NetState) -1) {
NetConnection_setState(conn, state->nextState);
// This has to be done immediately, as more packets in the
// receive queue may be handled by the netInput() call that
// triggered this callback.
// This is the reason for the nextState argument to
// waitReset(); setting the state after the call to
// waitReset() would be too late.
}
state->done = true;
}
bool
waitReset(NetConnection *conn, NetState nextState) {
WaitResetState state;
state.InputFunc = (BOOLEAN(*)(void *)) waitResetInputFunc;
state.MenuRepeatDelay = 0;
state.conn = conn;
state.nextState = nextState;
state.done = false;
Netplay_setResetCallback(conn, waitResetBothResetCallback,
(void *) &state);
if (state.done)
goto out;
if (!Netplay_isLocalReset(conn)) {
Netplay_localReset(conn, ResetReason_manualReset);
flushPacketQueue(conn);
}
if (!state.done)
DoInput(&state, FALSE);
out:
return NetConnection_isConnected(conn);
}
// Wait until we have received a reset packet to all connections. If we
// ourselves have not sent a reset packet, one is sent, with reason
// 'manualReset'.
// XXX: Right now all connections are handled one by one. Handling them all
// at once would be faster but would require more work, which is
// not worth it as the time is minimal and this function is not
// time critical.
// Use '(NetState) -1' for nextState to keep the current state.
bool
waitResetConnections(NetState nextState) {
COUNT player;
size_t numDisconnected = 0;
for (player = 0; player < NUM_PLAYERS; player++)
{
NetConnection *conn = netConnections[player];
if (conn == NULL)
continue;
if (!NetConnection_isConnected(conn)) {
numDisconnected++;
continue;
}
waitReset(conn, nextState);
}
return numDisconnected == 0;
}
////////////////////////////////////////////////////////////////////////////
+8
View File
@@ -22,6 +22,7 @@
#include "netplay.h"
#include "netinput.h"
#include "netconnection.h"
#include "packetsenders.h"
#include "../controls.h"
// for BATTLE_INPUT_STATE
@@ -44,6 +45,8 @@ void confirmConnections(void);
void cancelConfirmations(void);
void connectionsLocalReady(NetConnection_ReadyCallback callback, void *arg);
bool allConnected(void);
void sendBattleInputConnections(BATTLE_INPUT_STATE input);
void sendChecksumConnections(uint32 frameNr, uint32 checksum);
void initBattleStateDataConnections(void);
@@ -59,6 +62,8 @@ bool forAllConnectedPlayers(ForAllCallback callback, void *arg);
bool setupInputDelay(size_t localInputDelay);
bool sendInputDelayConnections(size_t delay);
bool setStateConnections(NetState state);
bool sendAbortConnections(NetplayAbortReason reason);
bool resetConnections(NetplayResetReason reason);
bool localReadyConnections(NetConnection_ReadyCallback readyCallback,
void *arg, bool notifyRemote);
@@ -67,6 +72,9 @@ bool negotiateReady(NetConnection *conn, bool notifyRemote,
bool negotiateReadyConnections(bool notifyRemote, NetState nextState);
bool waitReady(NetConnection *conn);
bool waitReset(NetConnection *conn, NetState nextState);
bool waitResetConnections(NetState nextState);
#endif /* _NETMELEE_H */
-2
View File
@@ -121,8 +121,6 @@ dataReceivedMulti(NetConnection *conn, const uint8 *data, size_t len) {
return processed;
}
// Returns -1 on error (setting errno), or 0 if everything went
// ok, regardless of whether any packets were actually processed.
void
dataReadyCallback(NetDescriptor *nd) {
NetConnection *conn = (NetConnection *) NetDescriptor_getExtra(nd);
+1
View File
@@ -24,6 +24,7 @@
typedef struct NetConnectionStateData NetConnectionStateData;
// State of a NetConnection.
typedef enum {
NetState_unconnected, /* No connection initiated */
NetState_connecting, /* Connection being setup */
+16
View File
@@ -54,6 +54,8 @@ PacketTypeData packetTypeData[PACKET_NUM] = {
DEFINE_PACKETDATA(BattleInput, false),
DEFINE_PACKETDATA(FrameCount, false),
DEFINE_PACKETDATA(Checksum, false),
DEFINE_PACKETDATA(Abort, false),
DEFINE_PACKETDATA(Reset, false),
};
static inline void *
@@ -253,5 +255,19 @@ Packet_Checksum_create(uint32 frameNr, uint32 checksum) {
return packet;
}
Packet_Abort *
Packet_Abort_create(uint16 reason) {
Packet_Abort *packet = (Packet_Abort *) Packet_create(PACKET_ABORT, 0);
packet->reason = hton16(reason);
return packet;
}
Packet_Reset *
Packet_Reset_create(uint16 reason) {
Packet_Reset *packet = (Packet_Reset *) Packet_create(PACKET_RESET, 0);
packet->reason = hton16(reason);
return packet;
}
+30
View File
@@ -39,10 +39,26 @@ typedef enum PacketType {
PACKET_BATTLEINPUT,
PACKET_FRAMECOUNT,
PACKET_CHECKSUM,
PACKET_ABORT,
PACKET_RESET,
PACKET_NUM, /* Number of packet types */
} PacketType;
// Sent before aborting the connection.
typedef enum NetplayAbortReason {
AbortReason_unspecified,
AbortReason_versionMismatch,
AbortReason_protocolError,
// Network is in an inconsistent state.
} NetplayAbortReason;
// Sent before resetting the connection. A game in progress is terminated.
typedef enum NetplayResetReason {
ResetReason_unspecified,
ResetReason_syncLoss,
ResetReason_manualReset,
} NetplayResetReason;
#ifndef PACKET_H_STANDALONE
#include "netconnection.h"
@@ -227,6 +243,18 @@ typedef struct {
uint32 checksum; /* Actually Checksum */
} Packet_Checksum;
typedef struct {
PacketHeader header;
uint16 reason; /* Actually NetplayAbortReason */
uint16 padding0;
} Packet_Abort;
typedef struct {
PacketHeader header;
uint16 reason; /* Actually NetplayResetReason */
uint16 padding0;
} Packet_Reset;
#ifndef PACKET_H_STANDALONE
void Packet_delete(Packet *packet);
@@ -248,6 +276,8 @@ Packet_SelectShip *Packet_SelectShip_create(uint16 ship);
Packet_BattleInput *Packet_BattleInput_create(uint8 state);
Packet_FrameCount *Packet_FrameCount_create(uint32 frameCount);
Packet_Checksum *Packet_Checksum_create(uint32 frameNr, uint32 checksum);
Packet_Abort *Packet_Abort_create(uint16 reason);
Packet_Reset *Packet_Reset_create(uint16 reason);
#endif
+121
View File
@@ -28,12 +28,15 @@
#include "packetsenders.h"
#include "proto/npconfirm.h"
#include "proto/ready.h"
#include "proto/reset.h"
#include "libs/log.h"
#include "controls.h"
// for BATTLE_INPUT_STATE
#include "init.h"
// for NUM_PLAYERS
#include "globdata.h"
// for GLOBAL
#include "melee.h"
// for various update functions.
#include "pickmele.h"
@@ -56,6 +59,13 @@ testNetState(bool condition, PacketType type) {
int
PacketHandler_Init(NetConnection *conn, const Packet_Init *packet) {
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_init &&
!conn->stateFlags.ready.remoteReady, PACKET_INIT))
return -1; // errno is set
@@ -152,6 +162,13 @@ checkYourTurn(NetConnection *conn, PacketType type) {
int
PacketHandler_Ready(NetConnection *conn, const Packet_Ready *packet) {
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(readyFlagsMeaningful(conn->state) &&
!conn->stateFlags.ready.remoteReady, PACKET_READY))
return -1; // errno is set
@@ -172,6 +189,13 @@ PacketHandler_Fleet(NetConnection *conn, const Packet_Fleet *packet) {
int player;
BattleStateData *battleStateData;
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_inSetup, PACKET_FLEET))
return -1; // errno is set
@@ -223,6 +247,13 @@ PacketHandler_TeamName(NetConnection *conn, const Packet_TeamName *packet) {
int side;
BattleStateData *battleStateData;
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_inSetup, PACKET_TEAMNAME))
return -1; // errno is set
@@ -262,6 +293,13 @@ handshakeComplete(NetConnection *conn) {
int
PacketHandler_Handshake0(NetConnection *conn,
const Packet_Handshake0 *packet) {
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(handshakeMeaningful(conn->state)
&& !conn->stateFlags.handshake.remoteOk, PACKET_HANDSHAKE0))
return -1; // errno is set
@@ -280,6 +318,13 @@ PacketHandler_Handshake0(NetConnection *conn,
int
PacketHandler_Handshake1(NetConnection *conn,
const Packet_Handshake1 *packet) {
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(handshakeMeaningful(conn->state) &&
(conn->stateFlags.handshake.localOk ||
conn->stateFlags.handshake.canceling), PACKET_HANDSHAKE1))
@@ -312,6 +357,13 @@ PacketHandler_Handshake1(NetConnection *conn,
int
PacketHandler_HandshakeCancel(NetConnection *conn,
const Packet_HandshakeCancel *packet) {
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(handshakeMeaningful(conn->state)
&& conn->stateFlags.handshake.remoteOk, PACKET_HANDSHAKECANCEL))
return -1; // errno is set
@@ -328,6 +380,13 @@ PacketHandler_HandshakeCancel(NetConnection *conn,
int
PacketHandler_HandshakeCancelAck(NetConnection *conn,
const Packet_HandshakeCancelAck *packet) {
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(handshakeMeaningful(conn->state)
&& conn->stateFlags.handshake.canceling,
PACKET_HANDSHAKECANCELACK))
@@ -352,6 +411,13 @@ PacketHandler_SeedRandom(NetConnection *conn,
const Packet_SeedRandom *packet) {
BattleStateData *battleStateData;
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_preBattle &&
!conn->stateFlags.discriminant, PACKET_SEEDRANDOM))
return -1; // errno is set
@@ -370,6 +436,13 @@ PacketHandler_InputDelay(NetConnection *conn,
BattleStateData *battleStateData;
uint32 delay;
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_preBattle,
PACKET_INPUTDELAY))
return -1; // errno is set
@@ -392,6 +465,13 @@ PacketHandler_SelectShip(NetConnection *conn,
bool updateResult;
BattleStateData *battleStateData;
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_selectShip, PACKET_SELECTSHIP))
return -1; // errno is set
@@ -413,6 +493,13 @@ PacketHandler_BattleInput(NetConnection *conn,
BATTLE_INPUT_STATE input;
BattleInputBuffer *bib;
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_inBattle ||
conn->state == NetState_endingBattle ||
conn->state == NetState_endingBattle2, PACKET_BATTLEINPUT))
@@ -434,6 +521,13 @@ PacketHandler_FrameCount(NetConnection *conn,
BattleStateData *battleStateData;
BattleFrameCounter frameCount;
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(conn->state == NetState_endingBattle,
PACKET_FRAMECOUNT))
return -1; // errno is set
@@ -461,6 +555,13 @@ PacketHandler_Checksum(NetConnection *conn, const Packet_Checksum *packet) {
size_t interval;
#endif
if (conn->stateFlags.reset.localReset)
return 0;
if (conn->stateFlags.reset.remoteReset) {
errno = EBADMSG;
return -1;
}
if (!testNetState(NetState_battleActive(conn->state), PACKET_CHECKSUM))
return -1; // errno is set
@@ -521,5 +622,25 @@ PacketHandler_Checksum(NetConnection *conn, const Packet_Checksum *packet) {
return 0;
}
int
PacketHandler_Abort(NetConnection *conn, const Packet_Abort *packet) {
abortFeedback(conn->player, packet->reason);
return -1;
// Close connection.
}
int
PacketHandler_Reset(NetConnection *conn, const Packet_Reset *packet) {
NetplayResetReason reason;
if (!testNetState(!conn->stateFlags.reset.remoteReset, PACKET_RESET))
return -1; // errno is set
reason = ntoh16(packet->reason);
Netplay_remoteReset(conn, reason);
return 0;
}
+2
View File
@@ -42,6 +42,8 @@ DECLARE_PACKETHANDLER(SelectShip);
DECLARE_PACKETHANDLER(BattleInput);
DECLARE_PACKETHANDLER(FrameCount);
DECLARE_PACKETHANDLER(Checksum);
DECLARE_PACKETHANDLER(Abort);
DECLARE_PACKETHANDLER(Reset);
#endif /* _PACKETHANDLERS_H */
+16
View File
@@ -195,5 +195,21 @@ sendChecksum(NetConnection *conn, BattleFrameCounter frameNr,
}
#endif
void
sendAbort(NetConnection *conn, NetplayAbortReason reason) {
Packet_Abort *packet;
packet = Packet_Abort_create((uint16) reason);
queuePacket(conn, (Packet *) packet, false);
}
void
sendReset(NetConnection *conn, NetplayResetReason reason) {
Packet_Reset *packet;
packet = Packet_Reset_create((uint16) reason);
queuePacket(conn, (Packet *) packet, false);
}
+2
View File
@@ -49,6 +49,8 @@ void sendSelectShip(NetConnection *conn, COUNT ship);
void sendBattleInput(NetConnection *conn, BATTLE_INPUT_STATE input);
void sendFrameCount(NetConnection *conn, uint32 frameCount);
void sendChecksum(NetConnection *conn, uint32 frameNr, uint32 checksum);
void sendAbort(NetConnection *conn, NetplayAbortReason reason);
void sendReset(NetConnection *conn, NetplayResetReason reason);
#endif /* _PACKETSENDERS_H */
+1 -1
View File
@@ -1,2 +1,2 @@
uqm_CFILES="npconfirm.c ready.c"
uqm_CFILES="npconfirm.c ready.c reset.c"
+4 -4
View File
@@ -36,11 +36,11 @@ Netplay_bothReady(NetConnection *conn) {
callback = conn->readyCallback;
readyArg = conn->readyCallbackArg;
conn->readyCallback = NULL;
NetConnection_setReadyCallback(conn, NULL, NULL);
// Clear the readyCallback field before performing the callback,
// so that it can be set again from inside the callback
// function.
conn->readyCallbackArg = NULL;
callback(conn, readyArg);
}
@@ -94,12 +94,12 @@ Netplay_remoteReady(NetConnection *conn) {
}
bool
Netplay_isLocalReady(NetConnection *conn) {
Netplay_isLocalReady(const NetConnection *conn) {
return conn->stateFlags.ready.localReady;
}
bool
Netplay_isRemoteReady(NetConnection *conn) {
Netplay_isRemoteReady(const NetConnection *conn) {
return conn->stateFlags.ready.remoteReady;
}
+2 -2
View File
@@ -24,8 +24,8 @@
bool Netplay_localReady(NetConnection *conn,
NetConnection_ReadyCallback callback, void *arg, bool notifyRemote);
bool Netplay_remoteReady(NetConnection *conn);
bool Netplay_isLocalReady(NetConnection *conn);
bool Netplay_isRemoteReady(NetConnection *conn);
bool Netplay_isLocalReady(const NetConnection *conn);
bool Netplay_isRemoteReady(const NetConnection *conn);
#endif /* _READY_H */
+22 -20
View File
@@ -153,7 +153,7 @@ DoGetMelee (GETMELEE_STATE *gms)
gms->remoteSelected = FALSE;
#endif
// We determine upfront which ship would be chosen if the player
// We determine in advance which ship would be chosen if the player
// wants a random ship, to keep it simple to keep network parties
// synchronised.
gms->randomIndex = (COUNT)TFB_Random () % gms->ships_left;
@@ -165,8 +165,14 @@ DoGetMelee (GETMELEE_STATE *gms)
SleepThread (ONE_SECOND / 120);
#ifdef NETPLAY
netInput ();
if (!allConnected())
goto aborted;
#endif
if (GLOBAL (CurrentActivity) & CHECK_ABORT)
goto aborted;
if (PlayerInput[which_player] == ComputerInput)
{
/* TODO: Make this a frame-by-frame thing. This code is currently
@@ -200,16 +206,7 @@ DoGetMelee (GETMELEE_STATE *gms)
select = PulsedInputState.key[template][KEY_WEAPON];
}
if (GLOBAL (CurrentActivity) & CHECK_ABORT)
{
gms->hBattleShip = 0;
GLOBAL (CurrentActivity) &= ~CHECK_ABORT;
#ifdef NETPLAY
// TODO: send abort packet
#endif
done = true;
}
else if (select)
if (select)
{
if (gms->col == NUM_MELEE_COLS_ORIG)
{
@@ -225,13 +222,9 @@ DoGetMelee (GETMELEE_STATE *gms)
}
else
{
// Exit
// Selected exit
if (ConfirmExit ())
{
gms->hBattleShip = 0;
GLOBAL (CurrentActivity) &= ~CHECK_ABORT;
done = TRUE;
}
goto aborted;
}
}
else
@@ -294,6 +287,14 @@ DoGetMelee (GETMELEE_STATE *gms)
#endif
return !done;
aborted:
#ifdef NETPLAY
flushPacketQueues ();
#endif
gms->hBattleShip = 0;
GLOBAL (CurrentActivity) &= ~CHECK_ABORT;
return FALSE;
}
#ifdef NETPLAY
@@ -495,7 +496,10 @@ GetMeleeStarShip (STARSHIPPTR LastStarShipPtr, COUNT which_player)
SetFlashRect (NULL_PTR, (FRAME)0);
if (gmstate.hBattleShip == 0)
{
// Aborting.
GLOBAL (CurrentActivity) &= ~IN_BATTLE;
}
else
{
StarShipPtr =
@@ -513,14 +517,12 @@ GetMeleeStarShip (STARSHIPPTR LastStarShipPtr, COUNT which_player)
#ifdef NETPLAY
{
NetConnection *conn = netConnections[which_player];
if (conn != NULL)
if (conn != NULL && NetConnection_isConnected(conn))
{
BattleStateData *battleStateData;
battleStateData = (BattleStateData *)
NetConnection_getStateData(conn);
battleStateData->getMeleeState = NULL;
if (gmstate.hBattleShip == 0)
NetConnection_setState(conn, NetState_inSetup);
}
}
#endif
+1 -2
View File
@@ -393,8 +393,7 @@ GetEncounterStarShip (STARSHIPPTR LastStarShipPtr, COUNT which_player)
if (LastStarShipPtr->special_counter == 0)
/* died in the line of duty */
GLOBAL_SIS (CrewEnlisted) = (COUNT)~0;
else if (GLOBAL_SIS (FuelOnBoard) >
RUN_AWAY_FUEL_COST)
else if (GLOBAL_SIS (FuelOnBoard) > RUN_AWAY_FUEL_COST)
GLOBAL_SIS (FuelOnBoard) -= RUN_AWAY_FUEL_COST;
else
GLOBAL_SIS (FuelOnBoard) = 0;
+5 -2
View File
@@ -387,7 +387,7 @@ spawn_ship (STARSHIPPTR StarShipPtr)
RDPtr->ship_info.var2 = (BYTE)StarShipPtr->ShipFacing;
StarShipPtr->ship_input_state = 0;
StarShipPtr->cur_status_flags =
StarShipPtr->cur_status_flags = 0;
StarShipPtr->old_status_flags = 0;
if (LOBYTE (GLOBAL (CurrentActivity)) == IN_ENCOUNTER
@@ -420,6 +420,7 @@ spawn_ship (STARSHIPPTR StarShipPtr)
StarShipPtr->hShip = hShip;
if (StarShipPtr->hShip != 0)
{
// Construct an ELEMENT for the STARSHIP
ELEMENTPTR ShipElementPtr;
LockElement (hShip, &ShipElementPtr);
@@ -437,6 +438,7 @@ spawn_ship (STARSHIPPTR StarShipPtr)
if ((ShipElementPtr->state_flags & BAD_GUY)
&& LOBYTE (GLOBAL (CurrentActivity)) == IN_LAST_BATTLE)
{
// This is the Sa-Matra
StarShipPtr->ShipFacing = 0;
ShipElementPtr->current.image.frame =
SetAbsFrameIndex (RDPtr->ship_data.ship[0],
@@ -452,7 +454,8 @@ spawn_ship (STARSHIPPTR StarShipPtr)
{
COUNT facing;
if ((facing = LOWORD (GLOBAL (ShipStamp.frame))) > 0)
facing = LOWORD (GLOBAL (ShipStamp.frame));
if (facing > 0)
--facing;
GLOBAL (ShipStamp.frame) = (FRAME)MAKE_DWORD (
+7 -7
View File
@@ -142,7 +142,8 @@ spawn_crew (PELEMENT ElementPtr)
{
HELEMENT hCrew;
if ((hCrew = AllocElement ()) != 0)
hCrew = AllocElement ();
if (hCrew != 0)
{
ELEMENTPTR CrewPtr;
@@ -151,9 +152,7 @@ spawn_crew (PELEMENT ElementPtr)
CrewPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE
| (ElementPtr->state_flags & (GOOD_GUY | BAD_GUY));
CrewPtr->life_span = 0;
{
CrewPtr->death_func = spawn_crew;
}
CrewPtr->pParent = ElementPtr->pParent;
CrewPtr->hTarget = 0;
UnlockElement (hCrew);
@@ -181,12 +180,13 @@ spawn_crew (PELEMENT ElementPtr)
SIZE dx, dy;
DWORD d_squared;
if ((dx = ObjPtr->next.location.x
- ElementPtr->next.location.x) < 0)
dx = ObjPtr->next.location.x - ElementPtr->next.location.x;
if (dx < 0)
dx = -dx;
if ((dy = ObjPtr->next.location.y
- ElementPtr->next.location.y) < 0)
dy = ObjPtr->next.location.y - ElementPtr->next.location.y;
if (dy < 0)
dy = -dy;
dx = WORLD_TO_DISPLAY (dx);
dy = WORLD_TO_DISPLAY (dy);
#define ABANDONER_RANGE 208 /* originally SPACE_HEIGHT */
+44 -7
View File
@@ -25,6 +25,7 @@
# include "netplay/netmisc.h"
# include "netplay/notify.h"
# include "netplay/proto/ready.h"
# include "netplay/packet.h"
# include "netplay/packetq.h"
#endif
#include "races.h"
@@ -180,7 +181,7 @@ readyForBattleEndPlayer (NetConnection *conn, void *arg)
#endif
static inline bool
readyForBattleEnd (void)
readyForBattleEnd (COUNT side)
{
#ifndef NETPLAY
#if DEMO_MODE
@@ -194,9 +195,26 @@ readyForBattleEnd (void)
if (PLRPlaying ((MUSIC_REF)~0))
return false;
// We can only handle one dead ship at a time. So 'deadSide' is set
// to the side we're handling now. (COUNT)~0 means we're not handling
// any side yet.
if (currentDeadSide == (COUNT)~0)
{
// Not handling any side yet.
currentDeadSide = side;
}
else if (side != currentDeadSide)
{
// We're handing another side at the moment.
return false;
}
if (!forAllConnectedPlayers (readyForBattleEndPlayer, NULL))
return false;
currentDeadSide = (COUNT)~0;
// Another side may be handled.
return true;
#endif /* defined (NETPLAY) */
}
@@ -239,9 +257,9 @@ new_ship (PELEMENT DeadShipPtr)
DeadShipPtr->turn_wait = (BYTE)(
DeadShipPtr->state_flags & (GOOD_GUY | BAD_GUY));
// DeadShipPtr->turn_wait is abused to store which
// side this element is for, probably because this
// information will be lost from state_flags (why is this
// necessary?).
// side this element is for, because this information
// will be lost from state_flags when the element is
// set up for deletion below.
for (hElement = GetHeadElement (); hElement; hElement = hSuccElement)
{
ELEMENTPTR ElementPtr;
@@ -250,14 +268,20 @@ new_ship (PELEMENT DeadShipPtr)
LockElement (hElement, &ElementPtr);
hSuccElement = GetSuccElement (ElementPtr);
GetElementStarShip (ElementPtr, &StarShipPtr);
// Get the STARSHIP that this ELEMENT belongs to.
if (StarShipPtr == DeadStarShipPtr)
{
// This element belongs to the dead ship; it may be the
// ship's own element.
SetElementStarShip (ElementPtr, 0);
if (!(ElementPtr->state_flags & CREW_OBJECT)
|| ElementPtr->preprocess_func != crew_preprocess)
{
SetPrimType (&DisplayArray[ElementPtr->PrimIndex], NO_PRIM);
// Set the element up for deletion.
SetPrimType (&DisplayArray[ElementPtr->PrimIndex],
NO_PRIM);
ElementPtr->life_span = 0;
ElementPtr->state_flags =
NONSOLID | DISAPPEARING | FINITE_LIFE;
@@ -271,6 +295,7 @@ new_ship (PELEMENT DeadShipPtr)
if (StarShipPtr
&& (StarShipPtr->cur_status_flags & PLAY_VICTORY_DITTY))
{
// StarShipPtr points to the surviving ship.
MusicStarted = TRUE;
PlayMusic ((MUSIC_REF)StarShipPtr->RaceDescPtr->
ship_data.victory_ditty, FALSE, 3);
@@ -287,7 +312,8 @@ new_ship (PELEMENT DeadShipPtr)
SetElementStarShip (DeadShipPtr, DeadStarShipPtr);
}
if (DeadShipPtr->life_span || !readyForBattleEnd ())
if (DeadShipPtr->life_span || !readyForBattleEnd (
WHICH_SIDE (DeadShipPtr->turn_wait)))
{
DeadShipPtr->state_flags &= ~DISAPPEARING;
++DeadShipPtr->life_span;
@@ -328,7 +354,7 @@ UnbatchGraphics ();
#endif /* NETPLAY */
if (GetNextStarShip (DeadStarShipPtr,
WHICH_SIDE (DeadShipPtr->turn_wait)) && RestartMusic)
WHICH_SIDE (DeadShipPtr->turn_wait)))
{
#ifdef NETPLAY
{
@@ -343,11 +369,22 @@ UnbatchGraphics ();
}
}
#endif
if (RestartMusic)
BattleSong (TRUE);
}
else if (LOBYTE (battle_counter) == 0
|| HIBYTE (battle_counter) == 0)
{
// One player is out of ships. The battle is over.
GLOBAL (CurrentActivity) &= ~IN_BATTLE;
}
#ifdef NETPLAY
else
{
// Battle has been aborted.
GLOBAL (CurrentActivity) |= CHECK_ABORT;
}
#endif
#ifdef NETPLAY
// Turn_wait was abused to store the side this element was on.